apiVersion: v1 kind: ConfigMap metadata: name: zeppelin-server-conf-map namespace: spark data: # 'serviceDomain' is a Domain name to use for accessing Zeppelin UI. # Should point IP address of 'zeppelin-server' service. # # Wildcard subdomain need to be point the same IP address to access service inside of Pod (such as SparkUI). # i.e. if service domain is 'local.zeppelin-project.org', DNS configuration should make 'local.zeppelin-project.org' and '*.local.zeppelin-project.org' point the same address. # # Default value is 'local.zeppelin-project.org' while it points 127.0.0.1 and `kubectl port-forward zeppelin-server` will give localhost to connects. # If you have your ingress controller configured to connect to `zeppelin-server` service and have a domain name for it (with wildcard subdomain point the same address), you can replace serviceDomain field with your own domain. SERVICE_DOMAIN: zeppelin.yourdomain.com ZEPPELIN_K8S_SPARK_CONTAINER_IMAGE: nvtienanh/spark-py:latest ZEPPELIN_K8S_CONTAINER_IMAGE: apache/zeppelin:0.10.0 ZEPPELIN_RUN_MODE: k8s ZEPPELIN_K8S_NAMESPACE: spark ZEPPELIN_HOME: /opt/zeppelin ZEPPELIN_SERVER_RPC_PORTRANGE: 12320:12320 # default value of 'master' property for spark interpreter. SPARK_MASTER: k8s://https://kubernetes.default.svc # default value of 'SPARK_HOME' property for spark interpreter. SPARK_HOME: /spark --- apiVersion: v1 kind: ConfigMap metadata: name: zeppelin-server-conf namespace: spark data: nginx.conf: | daemon off; worker_processes auto; events { worker_connections 1024; } http { map $http_upgrade $connection_upgrade { default upgrade; '' close; } # first server block will be default. Proxy zeppelin server. server { listen 80; location / { proxy_pass http://localhost:8080; proxy_set_header Host $host; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_redirect http://localhost $scheme://SERVICE_DOMAIN; } } # match request domain [port]-[service].[serviceDomain] # proxy extra service such as spark-ui server { listen 80; server_name "~(?[0-9]+)-(?[^.]*)\.(.*)"; location / { resolver 127.0.0.1:53 ipv6=off; proxy_pass http://$svc_name.NAMESPACE.svc:$svc_port; proxy_set_header Host $host; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_redirect http://localhost $scheme://SERVICE_DOMAIN; # redirect rule for spark ui. 302 redirect response misses port number of service domain proxy_redirect ~(http:[/]+[0-9]+[-][^-]+[-][^.]+)[^/]+(\/jobs.*) $1.SERVICE_DOMAIN$2; } } } --- apiVersion: apps/v1 kind: Deployment metadata: name: zeppelin-server namespace: spark labels: app.kubernetes.io/name: zeppelin-server spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: zeppelin-server strategy: type: RollingUpdate template: metadata: labels: app.kubernetes.io/name: zeppelin-server spec: serviceAccountName: zeppelin-server volumes: - name: nginx-conf configMap: name: zeppelin-server-conf items: - key: nginx.conf path: nginx.conf - name: zeppelin-server-notebook-volume persistentVolumeClaim: claimName: zeppelin-notebook-pvc - name: zeppelin-server-custom-k8s persistentVolumeClaim: claimName: zeppelin-custom-k8s-pvc - name: zeppelin-server-conf persistentVolumeClaim: claimName: zeppelin-server-conf-pvc initContainers: - name: init-zeppelin-server image: apache/zeppelin:0.10.0 args: - /bin/bash - -c - cp -Rnp /opt/zeppelin/conf/* /zeppelin-server-conf - cp -Rnp /opt/zeppelin/k8s/* /zeppelin-server-custom-k8s - cp -Rnp /opt/zeppelin/notebook/* /zeppelin-server-notebook-volume volumeMounts: - name: zeppelin-server-conf mountPath: /zeppelin-server-conf - name: zeppelin-server-custom-k8s mountPath: /zeppelin-server-custom-k8s - name: zeppelin-server-notebook-volume mountPath: /zeppelin-server-notebook-volume containers: - name: zeppelin-server image: apache/zeppelin:0.10.0 command: ["sh", "-c", "$(ZEPPELIN_HOME)/bin/zeppelin.sh"] lifecycle: preStop: exec: # SIGTERM triggers a quick exit; gracefully terminate instead command: [ "sh", "-c", "ps -ef | grep org.apache.zeppelin.server.ZeppelinServer | grep -v grep | awk '{print $2}' | xargs kill", ] ports: - name: http containerPort: 8080 - name: https containerPort: 8443 - name: rpc containerPort: 12320 env: - name: POD_UID valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.uid - name: POD_NAME valueFrom: fieldRef: apiVersion: v1 fieldPath: metadata.name envFrom: - configMapRef: name: zeppelin-server-conf-map volumeMounts: - name: zeppelin-server-notebook-volume # configure this to persist notebook mountPath: /opt/zeppelin/notebook - name: zeppelin-server-conf # configure this to persist Zeppelin configuration mountPath: /opt/zeppelin/conf - name: zeppelin-server-custom-k8s # configure this to mount customized Kubernetes spec for interpreter mountPath: /opt/zeppelin/k8s resources: limits: cpu: "1" memory: 4096Mi requests: cpu: 500m memory: 2048Mi - name: zeppelin-server-gateway image: nginx:1.14.0 command: ["/bin/sh", "-c"] env: - name: SERVICE_DOMAIN valueFrom: configMapKeyRef: name: zeppelin-server-conf-map key: SERVICE_DOMAIN args: - cp -f /tmp/conf/nginx.conf /etc/nginx/nginx.conf; sed -i -e "s/SERVICE_DOMAIN/$SERVICE_DOMAIN/g" /etc/nginx/nginx.conf; sed -i -e "s/NAMESPACE/$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)/g" /etc/nginx/nginx.conf; cat /etc/nginx/nginx.conf; /usr/sbin/nginx volumeMounts: - name: nginx-conf mountPath: /tmp/conf lifecycle: preStop: exec: # SIGTERM triggers a quick exit; gracefully terminate instead command: ["/usr/sbin/nginx", "-s", "quit"] resources: limits: cpu: 50m memory: 512Mi requests: cpu: 50m memory: 512Mi - name: dnsmasq # nginx requires dns resolver for dynamic dns resolution image: "janeczku/go-dnsmasq:release-1.0.5" args: - --listen - "127.0.0.1:53" - --default-resolver - --append-search-domains - --hostsfile=/etc/hosts - --verbose resources: limits: cpu: 50m memory: 512Mi requests: cpu: 50m memory: 512Mi --- kind: Service apiVersion: v1 metadata: name: zeppelin-server namespace: spark spec: ports: - name: http port: 80 - name: rpc # port name is referenced in the code. So it shouldn't be changed. port: 12320 selector: app.kubernetes.io/name: zeppelin-server --- apiVersion: v1 kind: ServiceAccount metadata: name: zeppelin-server namespace: spark --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: zeppelin-server-role namespace: spark rules: - apiGroups: [""] resources: ["pods", "services", "configmaps"] verbs: ["create", "get", "update", "patch", "list", "delete", "watch"] - apiGroups: ["extensions", "networking.k8s.io"] resources: ["ingresses"] verbs: ["create", "get", "update", "patch", "list", "delete", "watch"] - apiGroups: ["rbac.authorization.k8s.io"] resources: ["roles", "rolebindings"] verbs: ["bind", "create", "get", "update", "patch", "list", "delete", "watch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: zeppelin-server-role-binding namespace: spark subjects: - kind: ServiceAccount name: zeppelin-server roleRef: kind: ClusterRole name: zeppelin-server-role apiGroup: rbac.authorization.k8s.io