使用 Docker 容器#

SkyPilot 可以将容器作为任务运行,或作为集群的运行时环境运行。

  • 如果容器镜像可调用 / 具有入口点:将其 作为任务运行

  • 如果容器镜像将用作运行时环境(例如 ubuntunvcr.io/nvidia/pytorch:23.10-py3 等),并且您需要在容器内运行额外命令:将其 作为运行时环境运行

注意

在 RunPod 上不支持运行 docker 容器。要在 RunPod 上使用,请将您的 docker 镜像用作运行时环境,或使用 setuprun 来配置您的环境。更多信息请参见 GitHub 问题

将容器作为任务运行#

注意

在 Kubernetes 上,不推荐在 pod 中运行 Docker 运行时。相反,请将您的容器用作运行时环境

SkyPilot 可以直接将容器化应用作为常规任务运行。SkyPilot 提供的默认虚拟机镜像已预配置 Docker 运行时。

要启动容器化应用,您可以在任务的 run 部分直接调用 docker run

例如,要运行 HuggingFace TGI 服务容器

resources:
  accelerators: A100:1

run: |
  docker run --gpus all --shm-size 1g -v ~/data:/data \
    ghcr.io/huggingface/text-generation-inference \
    --model-id lmsys/vicuna-13b-v1.5

  # NOTE: Uncommon to have any commands after the above.
  # `docker run` is blocking, so any commands after it
  # will NOT be run inside the container.

私有仓库#

在使用此模式时,要访问托管在私有仓库中的 Docker 镜像,只需在您的任务 YAML 文件中添加 setup 部分以向仓库进行身份验证

resources:
  accelerators: A100:1

setup: |
  # Authenticate with private registry
  docker login -u <username> -p <password> <registry>

run: |
  docker run <registry>/<image>:<tag>

远程构建容器#

如果您正在运行容器化应用,也可以在任务的 setup 阶段在集群上远程构建容器镜像。

echo_app 示例 提供了一个如何做到这一点的例子

file_mounts:
  /inputs: ./echo_app  # Input to application
  /echo_app: ./echo_app  # Contains the Dockerfile and build context
  /outputs:  # Output to be written directly to S3 bucket
    name: # Set unique bucket name here
    store: s3
    mode: MOUNT

setup: |
  # Build docker image. If pushed to a registry, can also do docker pull here
  docker build -t echo:v0 /echo_app

run: |
  docker run --rm \
    --volume="/inputs:/inputs:ro" \
    --volume="/outputs:/outputs:rw" \
    echo:v0 \
    /inputs/README.md /outputs/output.txt

在这个例子中,Dockerfile 和构建上下文包含在 ./echo_app 中。任务的 setup 阶段构建镜像,run 阶段运行容器。应用的输入使用 file_mounts 复制到 SkyPilot,并通过 docker 卷挂载 (--volume 标志) 挂载到容器内。应用在容器内 /outputs 路径产生的输出也卷挂载到虚拟机的 /outputs,然后通过存储桶挂载直接写入 S3 存储桶。

我们的 GitHub 仓库有更多示例,包括通过 SkyPilot 在 Docker 容器中运行 Detectron2

将容器用作运行时环境#

当容器用作运行时环境时,所有事情都在容器内发生

  • SkyPilot 运行时会自动安装并在容器内启动;

  • setuprun 命令在容器中执行;

  • 任务创建的任何文件都将存储在容器内。

要将 Docker 镜像用作您的运行时环境,请将任务 YAML 文件中 resources 部分的 image_id 字段设置为 docker:<image_id>。目前仅支持基于 Debian 的镜像(例如 Ubuntu)。

例如,使用 Docker Hub 的 ubuntu:20.04 镜像

resources:
  image_id: docker:ubuntu:20.04

setup: |
  # Commands to run inside the container

run: |
  # Commands to run inside the container

注意

对于 RunPod 上的 非 root docker 镜像,您必须手动设置 SKYPILOT_RUNPOD_DOCKER_USERNAME 环境变量,使其与 docker 镜像的登录用户匹配(由 Dockerfile 中的最后一条 USER 指令设置)。

您可以在任务 YAML 文件的 envs 部分设置此环境变量

envs:
  SKYPILOT_RUNPOD_DOCKER_USERNAME: <ssh-user>

这是为了解决 RunPod 的一个限制,即我们无法获取创建的 pod 的登录用户,甚至 runpodctl 也使用硬编码的 root 进行 SSH 访问。但对于其他云,创建的 docker 容器的登录用户会自动获取并使用。

另一个例子是,如何使用 NVIDIA 的 PyTorch NGC 容器

resources:
  image_id: docker:nvcr.io/nvidia/pytorch:23.10-py3
  accelerators: T4

setup: |
  # Commands to run inside the container

run: |
  # Commands to run inside the container

  # Since SkyPilot tasks are run inside a fresh conda "(base)" environment,
  # deactivate first to access what the Docker image has already installed.
  source deactivate
  nvidia-smi
  python -c 'import torch; print(torch.__version__)'

分配给任务的任何 GPU 都将自动映射到您的 Docker 容器,并且集群内的所有后续任务也将运行在容器内。在多节点场景下,容器将在所有节点上启动,并将相应节点的容器分配用于任务执行。

提示

何时使用此功能?

如果您在 Docker 镜像中设置了预配置的开发环境,使用运行时环境模式会很方便。这对于启动在新虚拟机上难以配置的开发环境特别有用,例如依赖特定版本的 CUDA 或 cuDNN。

注意

由于我们会在启动时在用户指定的容器镜像内执行 pip install skypilot,用户应确保不会发生依赖冲突。

目前,必须满足以下要求

  1. 容器镜像应基于 Debian;

  2. 容器镜像必须授予用户无需密码认证的 sudo 权限。拥有 root 用户也是可以接受的。

注意

支持使用带有自定义入口点的容器作为运行时环境,容器的入口点将被 /bin/bash 覆盖。可以在任务 YAML 文件的 setuprun 部分执行特定命令。但是,由于 RunPod API 的限制,此方法与 RunPod 不兼容,因此请确保选择一个带有默认入口点(即 /bin/bash)的容器。

私有仓库#

注意

如果您使用 SkyPilot 在 Kubernetes 集群上启动,这些说明不适用。相反,更多信息请参阅 在 Kubernetes 中使用私有仓库的镜像

在使用此模式时,要访问托管在私有仓库中的 Docker 镜像,您可以使用任务环境变量提供仓库认证详情

resources:
  image_id: docker:<user>/<your-docker-hub-repo>:<tag>

envs:
  # Values used in: docker login -u <user> -p <password> <registry server>
  # The password should be a personal access token (PAT), see: https://app.docker.com/settings/personal-access-tokens
  SKYPILOT_DOCKER_USERNAME: <user>
  SKYPILOT_DOCKER_PASSWORD: <password>
  SKYPILOT_DOCKER_SERVER: docker.io
resources:
  image_id: docker:<your-ecr-repo>:<tag>

envs:
  # Values used in: docker login -u <user> -p <password> <registry server>
  # Password for ECR can be generated with ``aws ecr get-login-password --region <region>``
  SKYPILOT_DOCKER_USERNAME: AWS
  SKYPILOT_DOCKER_PASSWORD: <password>
  SKYPILOT_DOCKER_SERVER: <your-user-id>.dkr.ecr.<region>.amazonaws.com

或者,您可以使用带有 --env 标志的 sky launch 来传递密码

sky launch sky.yaml \
  --env SKYPILOT_DOCKER_PASSWORD="$(aws ecr get-login-password --region us-east-1)"

我们支持使用服务账户密钥的私有 GCP Artifact Registry (GCR)。请参阅 GCP Artifact Registry 认证。请注意,SKYPILOT_DOCKER_USERNAME 需要设置为 _json_key

resources:
  image_id: docker:<your-gcp-project-id>/<your-registry-repository>/<your-image-name>:<tag>

envs:
  SKYPILOT_DOCKER_USERNAME: _json_key
  SKYPILOT_DOCKER_PASSWORD: <gcp-service-account-key>
  SKYPILOT_DOCKER_SERVER: <location>-docker.pkg.dev

或者,您可以使用带有 --env 标志的 sky launch 来传递服务账户密钥

sky launch sky.yaml \
  --env SKYPILOT_DOCKER_PASSWORD="$(cat ~/gcp-key.json)"

注意

如果您的集群在 GCP 上,并且 SKYPILOT_DOCKER_USERNAMESKYPILOT_DOCKER_PASSWORD 设置为空字符串,SkyPilot 将自动使用实例的 IAM 权限向 GCR 进行认证

envs:
  SKYPILOT_DOCKER_USERNAME: ""
  SKYPILOT_DOCKER_PASSWORD: ""
  SKYPILOT_DOCKER_SERVER: <location>-docker.pkg.dev
resources:
  image_id: docker:nvidia/pytorch:23.10-py3

envs:
  SKYPILOT_DOCKER_USERNAME: $oauthtoken
  SKYPILOT_DOCKER_PASSWORD: <NGC_API_KEY>
  SKYPILOT_DOCKER_SERVER: nvcr.io

或者,您可以使用带有 --env 标志的 sky launch 来传递 API 密钥

sky launch sky.yaml \
  --env SKYPILOT_DOCKER_PASSWORD=<NGC_API_KEY>