自定义 Docker 镜像#

本节将帮助您

  • 使用您自己的依赖项扩展官方 Ray Docker 镜像

  • 将 Serve 应用程序打包到自定义 Docker 镜像中,而不是使用 runtime_env

  • 将自定义 Docker 镜像与 KubeRay 一起使用

为了遵循本教程,请确保安装 Docker Desktop 并创建一个 Dockerhub 帐户,您可以在其中托管自定义 Docker 镜像。

工作示例#

创建一个名为 fake.py 的 Python 文件,并将以下 Serve 应用程序保存到其中

from faker import Faker

from ray import serve


@serve.deployment
def create_fake_email():
    return Faker().email()


app = create_fake_email.bind()

此应用程序创建并返回一个假电子邮件地址。它依赖于 Faker 包来创建假电子邮件地址。请在本地安装 Faker 包以运行它

% pip install Faker==18.13.0

...

% serve run fake:app

...

# In another terminal window:
% curl localhost:8000
[email protected]

本教程解释了如何将此代码打包并在自定义 Docker 镜像中提供服务。

扩展 Ray Docker 镜像#

rayproject 组织维护着包含运行 Ray 所需依赖项的 Docker 镜像。事实上,rayproject/ray 仓库托管着本文档使用的 Docker 镜像。例如,此 RayService 配置使用了由 rayproject/ray 托管的 rayproject/ray:2.9.0 镜像。

您可以通过在 Dockerfile 中将其用作基础层来扩展这些镜像并向其中添加您自己的依赖项。例如,工作示例应用程序使用 Ray 2.9.0 和 Faker 18.13.0。您可以创建一个 Dockerfile,通过添加 Faker 包来扩展 rayproject/ray:2.9.0

# File name: Dockerfile
FROM rayproject/ray:2.9.0

RUN pip install Faker==18.13.0

通常,rayproject/ray 镜像仅包含导入 Ray 和 Ray 库所需的依赖项。您可以扩展任一仓库中的镜像来构建您的自定义镜像。

然后,您可以构建此镜像并将其推送到您的 Dockerhub 帐户,以便将来可以拉取它

% docker build . -t your_dockerhub_username/custom_image_name:latest

...

% docker image push your_dockerhub_username/custom_image_name:latest

...

请确保将 your_dockerhub_username 替换为您的 DockerHub 用户名,并将 custom_image_name 替换为您希望为镜像命名的名称。latest 是此镜像的版本。如果在拉取镜像时不指定版本,Docker 会自动拉取包的 latest 版本。如果您愿意,也可以将 latest 替换为特定版本。

将您的 Serve 应用程序添加到 Docker 镜像#

在开发过程中,将您的 Serve 应用程序打包成 zip 文件并使用 runtime_envs 将其拉入 Ray 集群很有用。在生产环境中,将 Serve 应用程序放入 Docker 镜像中而不是 runtime_env 中会更稳定,因为新节点在运行之前无需动态拉取和安装 Serve 应用程序代码。

在 Dockerfile 中使用 WORKDIRCOPY 命令将示例 Serve 应用程序代码安装到您的镜像中

# File name: Dockerfile
FROM rayproject/ray:2.9.0

RUN pip install Faker==18.13.0

# Set the working dir for the container to /serve_app
WORKDIR /serve_app

# Copies the local `fake.py` file into the WORKDIR
COPY fake.py /serve_app/fake.py

KubeRay 在 WORKDIR 目录中使用 ray start 命令启动 Ray。所有 Ray Serve actors 都能导入该目录中的任何依赖项。通过将 Serve 文件 COPYWORKDIR 中,Serve 部署无需 runtime_env 即可访问 Serve 代码。

对于您的应用程序,您还可以将 Serve 应用程序所需的任何其他依赖项添加到 WORKDIR 目录中。

构建此镜像并将其推送到 Dockerhub。使用与之前相同的版本覆盖存储在该版本下的镜像。

在 KubeRay 中使用自定义 Docker 镜像#

通过将这些自定义 Docker 镜像添加到 RayService 配置中,可以在 KubeRay 中运行它们。进行以下更改:

  1. rayClusterConfig 中的 rayVersion 设置为您自定义 Docker 镜像中使用的 Ray 版本。

  2. ray-head 容器的 image 设置为自定义镜像在 Dockerhub 上的名称。

  3. ray-worker 容器的 image 设置为自定义镜像在 Dockerhub 上的名称。

  4. 更新 serveConfigV2 字段,移除容器中已有的 runtime_env 依赖项。

此镜像的预构建版本可在 shrekrisanyscale/serve-fake-email-example 获取。通过运行此 RayService 配置进行尝试

apiVersion: ray.io/v1alpha1
kind: RayService
metadata:
  name: rayservice-fake-emails
spec:
  serviceUnhealthySecondThreshold: 300
  deploymentUnhealthySecondThreshold: 300
  serveConfigV2: |
    applications:
      - name: fake
        import_path: fake:app
        route_prefix: /
  rayClusterConfig:
    rayVersion: '2.5.0' # Should match Ray version in the containers
    headGroupSpec:
      rayStartParams:
        dashboard-host: '0.0.0.0'
      template:
        spec:
          containers:
            - name: ray-head
              image: shrekrisanyscale/serve-fake-email-example:example
              resources:
                limits:
                  cpu: 2
                  memory: 2Gi
                requests:
                  cpu: 2
                  memory: 2Gi
              ports:
                - containerPort: 6379
                  name: gcs-server
                - containerPort: 8265 # Ray dashboard
                  name: dashboard
                - containerPort: 10001
                  name: client
                - containerPort: 8000
                  name: serve
    workerGroupSpecs:
      - replicas: 1
        minReplicas: 1
        maxReplicas: 1
        groupName: small-group
        rayStartParams: {}
        template:
          spec:
            containers:
              - name: ray-worker
                image: shrekrisanyscale/serve-fake-email-example:example
                lifecycle:
                  preStop:
                    exec:
                      command: ["/bin/sh","-c","ray stop"]
                resources:
                  limits:
                    cpu: "1"
                    memory: "2Gi"
                  requests:
                    cpu: "500m"
                    memory: "2Gi"