You need to enable JavaScript to run this app.
导航
使用自定义 Docker 镜像运行作业
最近更新时间:2024.08.15 15:22:34首次发布时间:2024.04.01 11:32:37

EMR On VKE 支持将自定义 Docker 镜像作为集群中任务的默认工作负载运行时。使用自定义镜像具有以下优势:

  • 可以自行定义 EMR 官方版本中未提供的软件包或库,以便提高工作性能或支持您所执行的任务;
  • 可以通过已有的流水线,统一研发、测试及上线流程,简化依赖管理;
  • 可以对发布到生产环境的镜像进行控制,以满足工作负载对于组织合规性等要求。

自定义镜像的基本运行原理

我们以 Spark 集群为例进行说明。EMR On VKE 的 SparkOperator 运行原理如下:
图片
提交任务后,Spark Operator 将使用预先定制或提交任务的任务模板中定义的镜像启动 Driver Pod,之后启动 Executor Pod。所以,我们可以对配置进行更改,来达到 DriverPod 及 Executor Pod 中使用自定义镜像的目的。

自定义镜像使用流程

步骤一:获取 Spark 或 Ray 的基础镜像

EMR On VKE 提供了 Spark 及 Ray 运行作业的基础镜像,其中包含了开源版本所运行的基本依赖。
您可以通过以下命令获取 Spark 及 Ray 的基础镜像:

# Spark 基础镜像
docker pull emr-vke-public-cn-beijing.cr.volces.com/emr/spark:3.5.1-1.0.0.59-1.3.0
# Ray 基础镜像
docker pull emr-vke-public-cn-beijing.cr.volces.com/emr/ray:2.9.3-py3.9-ubuntu20.04-1.2.0

步骤二:自定义基础镜像

  1. 创建一个新的 DockerFile,内容如下:
# 请将 xxxx 替换为您需要的镜像版本
FROM emr-vke-public-cn-beijing.cr.volces.com/emr/spark:xxxx
# 其他安装命令,如 RUN pip3 install --upgrade boto3 pandas numpy // For python 3
  1. 在 Dockerfile 所在目录运行命令生成对应的镜像:
docker build -t $(PUB_TAG_VKE):$(VERSION) .

步骤三:(可选)验证自定义镜像

  • 镜像基础校验
    • username、WorkingDir、entrypoint 校验;
    • env 校验;

    您可使用 docker inspect 命令查看对应情况。

  • 作业校验
    • 组件的必备文件校验,如 spark 对应目录、启动脚本等;
    • 执行简单命令以保证作业可运行。

    根据镜像的不同,您可以使用不同的 docker run 命令执行具体的一些简单任务。

步骤四:发布自定义镜像

您可以通过 Docker push 命令将镜像发布至您账号下的火山引擎镜像中心中,以便在后续作业中使用该镜像:

docker push xxx/spark:3.5.1-customized

为了后续在 VKE 集群中能够正确获取该镜像,请根据您镜像仓库的权限情况为 VKE 集群配置对应的镜像拉取秘钥
如,您可以使用下述命令生成秘钥:

kubectl create secret docker-registry my-docker-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL -n YOUR_NAMESPACE

步骤五:提交作业

提交 Spark 作业

目前支持使用 Spark Submit(登录到 SparkOperator 节点)提交作业及使用 kubectl 提交 SparkApplication 作业。我们以 SparkApplication 方式为例进行提交。
使用 kubectl apply -f 提交下述作业:

apiVersion: "sparkoperator.k8s.io/v1beta2"
kind: SparkApplication
metadata:
  name: spark-wordcount
spec:
  type: Scala
  sparkVersion: 3.2.1
  mainClass: org.apache.spark.examples.SparkPi
  mainApplicationFile: "tos://yourTosPath"
  arguments:
    - "1000"
  driver:
    cores: 1
    coreLimit: 1000m
    memory: 8g
    image: xxx/spark:3.5.1-customized  # 指定 Driver 自定义镜像
  executor:
    cores: 1
    coreLimit: 1000m
    memory: 4g
    memoryOverhead: 2g
    instances: 1
    image: xxx/spark:3.5.1-customized # 指定 Driver 自定义镜像
  imagePullSecrets:
    - {{ your-secret }} # 指定 vke 下载 docker 镜像的秘钥

注意

您也可以通过修改默认配置的方式来指定 Executor Pod 和 Driver Pod 的镜像地址和下载秘钥。
在Spark on Kubernetes中,镜像的优先级顺序是:

  1. SparkApplication规范中的设置(使用 kubectl apply 提交);
  2. spark-defaults.conf 中 spark.kubernetes.container.image 的配置;
  3. spark.kubernetes.driver.podTemplateFile 或 spark.kubernetes.executor.podTemplateFile中的设置。

提交 KubeRay 作业

目前 Ray 支持 RayCluster 和 RayJob 方式。RayJob 方式支持指定自定义镜像,提交RayJob作业参考镜像仓库中的使用示例。

修改 RayCluster CRD 以使用自定义镜像

当您希望使用 RayCluster 预先启动的 Pod 提交任务时,我们需要修改 Ray 集群中所创建的自定义资源 RayCluster 来实现。CRD 定义头部分如下:

apiVersion: ray.io/v1
kind: RayCluster

您可以通过 kubectl 查看对应信息:

kubectl get raycluster ray-cluster-kuberay -n {您的 EMR 集群 ID} > raycluster.yaml

打开 raycluster.yaml 文件,您可以看到其 Spec 部分定义了对应 rayCluster 的镜像部分如下,替换红色字体部分为您的新镜像。

  1. ray-head
apiVersion: ray.io/v1
kind: RayCluster
metadata:
  ...
spec:
  headGroupSpec:
    ...
    template:
      ...
      spec:
        affinity: {}
        containers:
        - env: []
          image: xxx/ray:2.9.1-customized
          imagePullPolicy: IfNotPresent
          name: ray-head
          ...
          securityContext: {}
          volumeMounts:
          - mountPath: /tmp/ray
            name: log-volume
        imagePullSecrets:
        - name: {{ your-secret }}
  ...
  1. ray-worker
apiVersion: ray.io/v1
kind: RayCluster
metadata:
  ...
spec:
  headGroupSpec:
    ...
  workerGroupSpecs:
  - groupName: workergroup
    ...
    replicas: 1
    template:
      metadata:
        ...
      spec:
        affinity: {}
        containers:
        - env: []
          image: xxx/ray:2.9.1-customized
          imagePullPolicy: IfNotPresent
          name: ray-worker
          resources:
            ...
        imagePullSecrets:
        - name: {{ your-secret }}

修改完成后使用 kubectl 使其生效:

kubectl get raycluster {您的 ray cluster 名称} -n {您的 EMR 集群 ID} > raycluster.yaml

之后您需要手动删除对应的 Pod 以便 ray-operator 可以使用新镜像重建集群:

kubectl delete pod ray-cluster-kuberay-head-{可以通过 kubectl get pod 获取} -n {您的 EMR 集群 ID}
kubectl delete pod ray-cluster-kuberay-worker-workergroup-{可以通过 kubectl get pod 获取} -n {您的 EMR 集群 ID}