Kubernetes上的Zeppelin

Zeppelin 可以在由 Kubernetes 管理的集群上运行。当 Zeppelin 在 Pod 中运行时,它会为每个解释器创建 pod。此外,Spark 解释器会自动配置为在 Kubernetes 上以客户端模式使用 Spark。

主要优势是

  • 解释器扩展
  • Spark 解释器自动在 Kubernetes 上配置 Spark
  • 能够自定义Kubernetes yaml文件
  • Spark UI 访问

先决条件

  • Zeppelin >= 0.9.0 的 Docker 镜像
  • Spark >= 2.4.0 的 Docker 镜像(如果使用 Spark 解释器)
  • 一个正在运行的Kubernetes集群,并使用kubectl配置了访问权限
  • Kubernetes DNS 已在您的集群中配置
  • 您的Kubernetes集群中有足够的CPU和内存。我们建议使用4个CPU和6GB内存,以便能够启动带有少量执行器的Spark解释器。

    • 如果您正在使用minikube,请检查您的集群容量(kubectl describe node),并在必要时增加容量

      $ minikube delete    # otherwise configuration won't apply
      $ minikube config set cpus <number>
      $ minikube config set memory <number in MB>
      $ minikube start
      $ minikube config view
      

快速开始

首先,我们从GitHub克隆Zeppelin仓库:

git clone https://github.com/apache/zeppelin.git
cd zeppelin
# you can check out to your desired version/branch
# git checkout tags/v0.10.1
# just make sure you check the version inside "./pom.xml"

现在我们将创建zeppelin-distribution镜像。这可能需要一些时间,并且此镜像将用作即将需要的镜像的基础:

docker build -t zeppelin-distribution:latest -f ./Dockerfile .

接下来,我们将构建我们的 zeppelin-server 镜像:

cd scripts/docker/zeppelin-server
# Looking at the "./pom.xml" we can see the version is 0.11.2
# Let's set the correct version in our Dockerfile:
# vi Dockerfile
# ARG version="0.11.2"
# Once you saved the Dockerfile with the correct version we can build our image:
docker build -t zeppelin-server:0.11.2 -f ./Dockerfile .

我们构建的最后一个镜像是 zeppelin-interpreter

cd scripts/docker/zeppelin-interpreter
docker build -t zeppelin-interpreter:0.11.2 -f ./Dockerfile .

所以我们现在应该有以下图片:

# sudo if you are on Linux and Docker requires root
$ docker images

REPOSITORY                    TAG               IMAGE ID       CREATED          SIZE
zeppelin-interpreter          0.11.2            4f77fe989eed   3 minutes ago    622MB
zeppelin-server               0.11.2            4f77fe989eed   3 minutes ago    622MB
zeppelin-distribution         latest            bd2fb4b321d2   40 minutes ago   1.27GB

提醒:请调整zeppelin-server.yaml的YAML文件中的图像。

在Kubernetes集群上启动Zeppelin,

kubectl apply -f zeppelin-server.yaml

端口转发 Zeppelin 服务器端口,

kubectl port-forward zeppelin-server 8080:80

并浏览 localhost:8080。 尝试运行一些段落,看看每个解释器是否作为 Pod 运行(使用 kubectl get pods),而不是本地进程。

要关闭,

kubectl delete -f zeppelin-server.yaml

Spark 解释器

构建Spark Docker镜像以使用Spark解释器。 下载Spark二进制发行版并运行以下命令。 需要Spark 2.4.0或更高版本。

# if you're using minikube, set docker-env
$ eval $(minikube docker-env)

# build docker image
$ <spark-distribution>/bin/docker-image-tool.sh -m -t 2.4.0 build

运行 docker images 并检查是否创建了 spark:2.4.0。 在 zeppelin-server.yaml 中配置 zeppelin-server-conf ConfigMap 的 sparkContainerImage

创建笔记并配置执行器数量(默认1)

%spark.conf
spark.executor.instances  5

然后启动你的spark解释器

%spark
sc.parallelize(1 to 100).count
...

当SparkInterpreter的spark.master属性以k8s://开头时(默认情况下,当Zeppelin使用zeppelin-server.yaml启动时为k8s://https://kubernetes.default.svc),Spark执行器将自动在您的Kubernetes集群中创建。 通过点击段落上的SPARK JOB可以访问Spark UI。

查看这里了解更多关于在Kubernetes上运行Spark的信息。

手动构建Zeppelin镜像

要构建您自己的Zeppelin镜像,首先使用-Pbuild-distr标志构建Zeppelin项目。

$ ./mvnw package -DskipTests -Pbuild-distr <your flags>

二进制包将在zeppelin-distribution/target目录下创建。将创建的包文件移动到scripts/docker/zeppelin/bin/目录下。

$ mv zeppelin-distribution/target/zeppelin-*.tar.gz scripts/docker/zeppelin/bin/

scripts/docker/zeppelin/bin/Dockerfile 从互联网下载包。修改文件以从文件系统添加包。

...

# Find following section and comment out
#RUN echo "$LOG_TAG Download Zeppelin binary" && \
#    wget -O /tmp/zeppelin-${Z_VERSION}-bin-all.tgz http://archive.apache.org/dist/zeppelin/zeppelin-${Z_VERSION}/zeppelin-${Z_VERSION}-bin-all.tgz && \
#    tar -zxvf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
#    rm -rf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
#    mv /zeppelin-${Z_VERSION}-bin-all ${ZEPPELIN_HOME}

# Add following lines right after the commented line above
ADD zeppelin-${Z_VERSION}.tar.gz /
RUN ln -s /zeppelin-${Z_VERSION} /zeppelin
...

然后构建docker镜像。

# configure docker env, if you're using minikube
$ eval $(minikube docker-env)

# change directory
$ cd scripts/docker/zeppelin/bin/

# build image. Replace <tag>.
$ docker build -t <tag> .

最后,将刚刚创建的自定义镜像设置为image,并在zeppelin-server.yaml文件中的zeppelin-server容器规范中设置ZEPPELIN_K8S_CONTAINER_IMAGE环境变量。

目前,Zeppelin服务器和解释器pod中都在使用单个docker镜像。因此,

Pod 实例数量 镜像 备注
Zeppelin 服务器 1 Zeppelin docker 镜像 用户使用 kubectl 命令创建/删除
Zeppelin 解释器 n Zeppelin docker 镜像 Zeppelin 服务器创建/删除
Spark执行器 m Spark Docker镜像 Spark解释器创建/删除

目前,Zeppelin docker 镜像的大小相当大。Zeppelin 项目计划在未来为每个单独的解释器提供轻量级镜像。

它是如何工作的

Kubernetes上的Zeppelin

k8s/zeppelin-server.yaml 提供了运行 Zeppelin Server 的少量 sidecar 和配置。 一旦 Zeppelin Server 在 Kubernetes 中启动,它会自动配置自己以使用 K8sStandardInterpreterLauncher

启动器使用位于k8s/interpreter/目录下的模板在Pod中创建每个解释器。 目录中的模板按字母顺序应用。模板由jinjava渲染, 并且所有解释器属性都可以在模板内部访问。

Spark 在 Kubernetes 上

当解释器组是spark时,Zeppelin会自动设置必要的Spark配置以在Kubernetes上使用Spark。 它使用客户端模式,因此Spark解释器Pod作为Spark驱动程序工作,Spark执行器在单独的Pod中启动。 可以通过手动设置Spark解释器的spark.master属性来覆盖此自动配置。

访问Spark UI(或在解释器Pod中运行的服务)

Zeppelin 服务器 Pod 有一个反向代理作为边车,它将流量分配到 Zeppelin 服务器和运行在其他 Pod 中的 Spark UI。 它假设 *. 都指向 nginx 代理地址。 被定向到 ZeppelinServer,*. 被定向到解释器 Pods。

-. 是访问在解释器 Pod 中运行的任何应用程序的约定。

例如,当您的服务域名为 local.zeppelin-project.org 时,Spark 解释器 Pod 正在以名称 spark-axefeg 运行,并且 Spark UI 正在端口 4040 上运行,

4040-spark-axefeg.local.zeppelin-project.org

是访问Spark UI的地址。

默认服务域是 local.zeppelin-project.org:8080local.zeppelin-project.org*.local.zeppelin-project.org 配置为解析 127.0.0.1。 它允许使用 kubectl port-forward zeppelin-server 8080:80 访问 Zeppelin 和 Spark UI。

如果您喜欢使用您的自定义域名

  1. 在Kubernetes集群中为k8s/zeppelin-server.yaml中定义的zeppelin-server服务的http端口配置Ingress
  2. 配置DNS记录,使您的服务域名和通配符子域名指向您的Ingress的IP地址。
  3. 修改k8s/zeppelin-server.yaml文件中的zeppelin-server-conf ConfigMap的serviceDomain
  4. 应用更改(例如 kubectl apply -f k8s/zeppelin-server.yaml

持久化 /notebook 和 /conf 目录

默认情况下,Notebook 和配置不会被持久化。请配置卷并更新 k8s/zeppelin-server.yaml 以在必要时使用卷来持久化 /notebook 和 /conf 目录。

自定义

Zeppelin 服务器 Pod

编辑 k8s/zeppelin-server.yaml 并应用。

解释器 Pod

由于解释器 Pod 是由 ZeppelinServer 使用 k8s/interpreter 目录下的模板创建/删除的,要进行自定义,

  1. 准备k8s/interpreter目录并进行自定义(编辑或创建新的yaml文件),在Kubernetes卷中。
  2. 修改 k8s/zeppelin-server.yaml 并将准备好的卷目录 k8s/interpreter 挂载到 /zeppelin/k8s/interpreter/
  3. 应用修改后的 k8s/zeppelin-server.yaml
  4. 运行一个段落将使用修改后的yaml文件创建一个解释器。

解释器pod也可以通过解释器设置进行自定义。以下是一些属性:

属性名称 默认值 描述
zeppelin.k8s.interpreter.namespace default 指定当前解释器的命名空间。用户可以为不同的解释器设置不同的命名空间。为了最小化权限,默认情况下解释器pod只能在default命名空间中创建。如果用户需要在其他命名空间中创建解释器pod,则需要在k8s/zeppelin-server.yaml中添加相应的rolebinding
zeppelin.k8s.interpreter.serviceAccount default 使用的Kubernetes服务账户。
zeppelin.k8s.interpreter.container.image apache/zeppelin: 要使用的解释器镜像。
zeppelin.k8s.interpreter.cores (可选) 使用的CPU核心数量。
zeppelin.k8s.interpreter.memory (可选) 使用的内存,例如 1g
zeppelin.k8s.interpreter.gpu.type (可选) 设置当解释器pod需要调度gpu资源时请求的gpu类型,例如 nvidia.com/gpu
zeppelin.k8s.interpreter.gpu.nums (可选) 使用的GPU数量。
zeppelin.k8s.interpreter.imagePullSecrets (可选) 设置拉取镜像时使用的Kubernetes密钥列表,以逗号分隔,例如 mysecret1,mysecret2
zeppelin.k8s.interpreter.container.imagePullPolicy (可选) 设置解释器镜像的拉取策略,例如 Always
zeppelin.k8s.spark.container.imagePullPolicy (可选) 设置spark镜像的拉取策略,例如 Always
zeppelin.spark.uiWebUrl //-. 用户访问Spark UI的URL。默认值是一个包含三个变量的jinjava模板。
zeppelin.k8s.spark.useIngress (可选) 如果为true,则在创建spark解释器时将创建Ingress。因此,用户可以通过Ingress访问Spark UI。
zeppelin.k8s.spark.ingress.host -. 如果 zeppelin.k8s.spark.useIngresstrue,则配置 Ingress 的 host 值。默认值是一个包含三个变量的 jinjava 模板。用户可以通过自定义的 zeppelin.k8s.spark.ingress.host 访问 Spark UI。

未来工作

  • 更小的解释器 Docker 镜像。
  • 阻止解释器 Pod 之间的通信。
  • Spark Interpreter Pod 对同一命名空间中的任何 pod/service 具有 Role CRUD 权限。这应该仅限于 Spark executors Pod。
  • 当Zeppelin在Kubernetes上运行时,默认情况下为每个笔记解释器模式

开发

在开发过程中,不必每次都构建Zeppelin的发行包和Docker镜像,Zeppelin可以在本地运行(例如在IDE的调试模式下),并且能够通过配置以下环境变量来使用K8sStandardInterpreterLauncher运行解释器。

环境变量 描述
ZEPPELIN_RUN_MODE k8s 使Zeppelin在Kubernetes上运行解释器
ZEPPELIN_K8S_PORTFORWARD true 启用从本地Zeppelin实例到在Kubernetes上运行的Interpreters的端口转发
ZEPPELIN_K8S_CONTAINER_IMAGE : 使用的Zeppelin解释器docker镜像
ZEPPELIN_K8S_SPARK_CONTAINER_IMAGE : 使用的Spark docker镜像
ZEPPELIN_K8S_NAMESPACE 要使用的Kubernetes命名空间
KUBERNETES_AUTH_TOKEN 用于创建资源的Kubernetes认证令牌