Kubernetes 是部署应用程序和微服务的实际标准。然而,AI 工作负载不同。开发 AI 模型是一个交互式且资源密集型过程,对资源的部署和管理需要一种根本不同的方法。

在本博客中,我们将

  1. 讨论 Kubernetes 对于 AI 工作负载的优缺点
  2. 介绍 SkyPilot,以在 Kubernetes 及其他环境上轻松且经济高效地运行 AI
  3. 提供分步指南,介绍如何使用 SkyPilot 在您的 Kubernetes 集群上运行整个 AI 生命周期——从开发到训练再到部署。

Kubernetes 并非为 AI 而生

Kubernetes 是托管通用微服务的绝佳选择,并为管理员提供了广泛的集群管理功能。

然而,AI 工作负载具有 Kubernetes 未设计考虑的独特要求。

AI 开发需要交互性

构建和部署 AI 需要与部署微服务根本不同的流程。开发模型和清理数据是迭代过程,需要频繁修改代码并进行快速迭代。

这与微服务的“即发即忘”部署形成对比,微服务的一次部署可以长时间运行而无需任何干预。

AI 需要大量资源

AI 不仅需要强大的 GPU 进行训练,控制成本还需要处理可能分布在不同地理区域和提供商的多样化资源类型。难怪 OpenAI 在多个区域中运行基础设施。

另一方面,Kubernetes 设计用于单个紧密联网的集群。etcd(Kubernetes 的底层数据存储)在跨区域运行时性能会下降

因此,您的资源被锁定在单个区域,限制了可用性并增加了成本

AI 有严格的调度要求

AI 训练有严格的调度要求。大规模分布式训练需要协同调度(gang scheduling),即所有资源必须同时分配才能取得进展。

Kubernetes 默认不支持协同调度,这使得高效运行分布式训练作业变得困难。

Kubernetes 学习曲线陡峭

Kubernetes Learning Curve

Kubernetes 学习曲线。来源:r/kubernetes

AI 工程师需要与基础设施紧密合作来开发和部署模型。然而,Kubernetes 并不以对 AI 工程师和数据科学家友好而闻名。但他们被迫学习 Kubernetes 及其带来的所有复杂性——容器化、管理 Pod、服务等等。

因此,Kubernetes 成为了许多讨论抱怨甚至梗图的主题。

AI 工程师不应该为基础设施烦恼。相反,他们应该专注于自己的核心优势——数据处理、模型开发和评估。

但是……Kubernetes 也有许多优势

事情并非一团糟。Kubernetes 提供了一系列出色的功能,对 AI 工作负载非常有帮助——自动伸缩、故障恢复、资源管理和生产就绪性。

然而,要在 Kubernetes 上利用这些功能来运行 AI,需要深入了解 Kubernetes 生态系统,并且需要一个专门的团队来开发和维护高度专业化的工具。

SkyPilot:在 Kubernetes 及其他环境上运行 AI

SkyPilot 是一个在任何基础设施上运行 AI 的框架。对于 Kubernetes 用户来说,它建立在 Kubernetes 的核心优势之上,不仅提供了更简单的接口,还提供了一个超出单个 Kubernetes 集群范围的、更具成本效益和更高可用性的基础设施层。

以下是在您的 Kubernetes 集群上使用 SkyPilot 的一些主要优势

更简单的开发者体验和内置交互性

SkyPilot 抽象化了 Kubernetes 的复杂性,提供了运行 AI 工作负载的简单接口。

SkyPilot 通过 SSH 访问和与 VSCodeJupyter notebooks 的集成,提供了无缝的交互式开发体验。开发者可以专注于构建模型,无需担心底层基础设施。

示例:迭代模型开发

交互式工作流受益于 SkyPilot 更快的迭代速度。例如,AI 工程师的常见工作流是通过观察训练运行来调整代码和超参数,从而迭代开发和训练模型。

  • 使用 Kubernetes,单次迭代是一个多步过程,包括构建 Docker 镜像、将其推送到注册表、更新 Kubernetes YAML 文件,然后进行部署。
  • 使用 SkyPilot,一个简单的 sky launch 命令即可处理一切。在后台,SkyPilot 会提供 Pod、安装所有必需的依赖项、执行作业、返回日志并提供 SSH 访问以进行调试。

Iterative Development - Kubernetes vs SkyPilot

使用 SkyPilot 与 Kubernetes 进行迭代开发。使用 Kubernetes,每次更改都需要对 Docker 镜像进行繁琐的更新,并且需要多个步骤来更新训练运行。使用 SkyPilot,您只需一个 sky launch 命令。

示例:模型部署

训练模型后的常见任务是部署。

考虑使用 vLLM 部署 Gemma 模型

SkyPilot YAML vs Kubernetes YAML

使用 SkyPilot 与 Kubernetes 部署使用 vLLM 的 Gemma 模型。SkyPilot 的 YAML 规范短了 3 倍,对 AI 工程师来说更易读。

智能编排,最大化团队效率

在多租户 Kubernetes 集群中运行时,SkyPilot 会智能地跨用户调度 GPU。每个用户都有自己的隔离环境,确保其工作负载不相互干扰,同时最大化资源利用率。

无需手动调度 GPU——SkyPilot 会为您处理一切。

SkyPilot GPU Scheduling

使用 SkyPilot 在多租户环境中进行智能编排。手动调度依赖于用户通过 Slack 和电子表格进行的缓慢且低效的协调。使用 SkyPilot,每个用户向 SkyPilot 请求资源,SkyPilot 会有效地分配 GPU,最大化利用率。

GPU 不够用了?SkyPilot 以最低成本找到更多

GPU 供应短缺。SkyPilot 旨在通过在您的 Kubernetes 集群、云和区域中查找 GPU,最大化您的 AI 工作负载的可用性。它可以自动从 GPU 故障、竞价实例抢占和其他故障中恢复。

如果您的本地集群资源不足,SkyPilot 可以突发到云端,并在任何可用之处找到资源,确保您的工作负载不被阻塞。

SkyPilot failover

SkyPilot 的故障转移机制可以在任何可用之处为您找到 GPU。如果您的 Kubernetes 集群上的所有 GPU 都被占用,SkyPilot 可以将您的作业突发到云端,以最低成本找到 GPU 容量。

当您使用云时,每个 sky launch 命令都会调用 SkyPilot 的优化器,该优化器会在您所有基础设施中找到最具成本效益的资源。SkyPilot 还支持云上的竞价实例,并且可以混合使用竞价实例和按需实例,以在确保可用性的同时将成本降低高达 6 倍。

== Optimizer ==
Estimated cost: $0.0 / hour

Considered resources (1 node):
----------------------------------------------------------------------------------------------------------
 CLOUD        INSTANCE               vCPUs   Mem(GB)   ACCELERATORS   REGION/ZONE     COST ($)   CHOSEN
----------------------------------------------------------------------------------------------------------
 Kubernetes   2CPU--8GB--1T4         2       8         T4:1           kubernetes      0.00          ✔
 Azure        Standard_NC4as_T4_v3   4       28        T4:1           eastus          0.53
 AWS          g4dn.xlarge            4       16        T4:1           us-east-1       0.53
 GCP          n1-highmem-4           4       26        T4:1           us-central1-a   0.59
----------------------------------------------------------------------------------------------------------

Launching a new cluster 'dev'. Proceed? [Y/n]:
SkyPilot 的优化器会显示您所有基础设施中所有可用的资源,并选择最具成本效益的选项来运行您的工作负载。

统一的接口,适用于所有基础设施

SkyPilot 提供了一个统一的接口,用于在本地、云和混合环境中运行 AI 工作负载。同一个 YAML 规范可以在 12+ 个云提供商甚至您的本地 Kubernetes 集群上工作。一旦您的作业运行起来,sky status 命令会为您提供跨云所有资源的统一视图。

$ sky status
Clusters
NAME                           LAUNCHED  RESOURCES                                          STATUS  AUTOSTOP    COMMAND
sky-serve-controller-2ea485ea  1 hr ago  1x Kubernetes(4CPU--4GB, ports=['30001-30020']...  UP      10m (down)  sky serve up -n llama2 ll...
sky-jobs-controller-2ea485ea   1 hr ago  1x AWS(4CPU--4GB)                                  UP      10m (down)  sky jobs launch -c bert ...

Managed jobs
In progress tasks: 1 RUNNING
ID  TASK  NAME  RESOURCES   SUBMITTED   TOT. DURATION  JOB DURATION  #RECOVERIES  STATUS
1   -     bert  2x[A100:1]  3 mins ago  3m 26s         2m 18s        0            RUNNING

Services
NAME    VERSION  UPTIME   STATUS  REPLICAS  ENDPOINT
llama2  1        34m 44s  READY   3/3       35.225.61.44:30001

Service Replicas
SERVICE_NAME  ID  VERSION  ENDPOINT                   LAUNCHED  RESOURCES                 STATUS  REGION
llama2        1   1        http://34.173.84.219:8888  1 hr ago  1x Kubernetes({'T4': 1})  READY   kubernetes
llama2        2   1        http://35.199.51.206:8888  1 hr ago  1x GCP([Spot]{'T4': 1})   READY   us-east4
llama2        3   1        http://34.31.108.35:8888   1 hr ago  1x Kubernetes({'T4': 1})  READY   kubernetes

* To see detailed service status: sky serve status -a
* 1 cluster has auto{stop,down} scheduled. Refresh statuses with: sky status --refresh
SkyPilot 提供了一个单一的管理界面,用于管理您所有基础设施上的所有工作负载——开发、训练和部署。

兼容您现有的 Kubernetes 工具

SkyPilot 在 Kubernetes 上像其他任何应用程序一样运行。在后台,它创建 Pod 为作业提供计算资源,并在需要时使用 Kubernetes Service 或 Ingress 暴露它们。它还可以与 Kueue 等其他 Kubernetes 控制器集成。

这意味着您的所有现有 Kubernetes 工具(用于监控、日志记录和告警)都可以与 SkyPilot 一起使用。

Kubernetes Dashboard

您现有的工具,例如 Kubernetes Dashboard,可以用来监控 SkyPilot 创建的 Pod 和其他 Kubernetes 资源。

指南:使用 SkyPilot 在 Kubernetes 上运行 AI

让我们深入探讨如何使用 SkyPilot 在 Kubernetes 上运行整个 AI 生命周期——从开发到训练再到部署。

入门

要开始使用,请安装最新版本的 SkyPilot 以及 Kubernetes 依赖项

pip install skypilot-nightly[kubernetes]

接下来,我们需要将 Kubernetes 集群连接到 SkyPilot。

  • 如果您已经有 Kubernetes 集群,您只需要一个有效的 kubeconfig 文件。确保您的凭据已在 ~/.kube/config 中设置,并且您可以访问您的 Kubernetes 集群。您可以通过运行 kubectl get nodes 进行测试。
  • 如果您没有 Kubernetes 集群,请运行 sky local up。这将设置一个本地 Kubernetes 集群用于开发和测试目的。

运行 sky check 以验证您的集群和 SkyPilot 是否设置正确

# Checks if your Kubernetes credentials are set up correctly 
sky check kubernetes

您应该在已启用云列表下看到 Kubernetes。如果没有,SkyPilot 将显示未启用的原因并建议纠正步骤。有关如何设置 Kubernetes 的更多详细信息,请参阅我们的文档

对于更高级的设置,SkyPilot 也可以配置为使用自定义命名空间和服务帐户

我们现在准备好启动您的第一个 SkyPilot 集群了!

通过 SSH 和 VSCode 连接到 GPU Pod

AI 开发的初始阶段需要在 GPU 上进行大量的交互式开发。SkyPilot 允许您创建“集群”,这些集群是 Kubernetes 上 Pod 的集合。让我们启动一个启用了 GPU 的 SkyPilot 开发集群,并通过 SSH 和 VSCode 连接到它。

首先,让我们使用 sky show-gpus --cloud kubernetes 查看集群上有哪些 GPU 可用

$ sky show-gpus --cloud kubernetes

Kubernetes GPUs
GPU   QTY_PER_NODE  TOTAL_GPUS  TOTAL_FREE_GPUS
T4    1             4           4
V100  1, 2          4           4
使用 SkyPilot 列出您的 Kubernetes 集群上的 GPU 可用性。SkyPilot 显示 GPU 类型、总容量和当前可用数量。

要启动一个带有 GPU 的集群进行开发,请使用 sky launch

# Launch a cluster named 'dev' with 1 NVIDIA T4 GPU. If you do not have a GPU, remove the --gpus flag.
sky launch -c dev --gpus T4:1

SkyPilot 将运行其优化器来查找最低成本,并向您显示运行您的开发集群的最便宜选项

== Optimizer ==
Estimated cost: $0.0 / hour

Considered resources (1 node):
----------------------------------------------------------------------------------------------------------
 CLOUD        INSTANCE               vCPUs   Mem(GB)   ACCELERATORS   REGION/ZONE     COST ($)   CHOSEN
----------------------------------------------------------------------------------------------------------
 Kubernetes   2CPU--8GB--1T4         2       8         T4:1           kubernetes      0.00          ✔
 Azure        Standard_NC4as_T4_v3   4       28        T4:1           eastus          0.53
 AWS          g4dn.xlarge            4       16        T4:1           us-east-1       0.53
 GCP          n1-highmem-4           4       26        T4:1           us-central1-a   0.59
----------------------------------------------------------------------------------------------------------

Launching a new cluster 'dev'. Proceed? [Y/n]:

您的 SkyPilot 集群将作为 Pod 在您的 Kubernetes 集群中启动。SkyPilot 将负责启动 Pod、安装依赖项、设置 SSH 等等。

配置完成后,您可以通过 SSH 或 VSCode 连接到它。

通过 SSH 连接

SkyPilot 会自动配置您的 ssh config 文件,为开发集群添加一个别名。访问您的集群就像运行 ssh <cluster> 一样简单

ssh dev

通过 VSCode 连接

交互式开发的另一个常见用例是将本地 VSCode 连接到远程集群,并直接编辑集群上的代码。只需使用集群名称将 VSCode 连接到集群即可支持此操作。

  1. 单击顶部栏,输入:> remote-ssh,然后选择 Remote-SSH: Connect Current Window to Host...
  2. 从主机列表中选择集群名称(例如,dev)。

VSCode Remote SSH

将 VSCode 连接到远程开发集群。

运行 Jupyter Notebook

您也可以在集群上启动 Jupyter,以获得支持 GPU 的 notebook。连接到机器并转发 Jupyter notebook 使用的端口

ssh -L 8888:localhost:8888 dev

在集群内部,您可以运行以下命令启动 Jupyter 会话

pip install jupyter
jupyter notebook

在本地浏览器中,您现在应该能够访问 localhost:8888 并在您的 notebook 中使用 GPU

Jupyter Notebook

在开发集群上运行由 GPU 驱动的 Jupyter Notebook。

使用 SkyPilot 进行分布式训练

开发完模型后,您可以使用 SkyPilot 的托管作业功能大规模训练您的模型。

让我们定义训练作业。例如,我们将使用 torch 分布式数据并行 (DDP) 在 SQuAD 数据集上,跨两个节点使用 2 个 A100 GPU 训练 BERT 问答模型

envs:
  WANDB_API_KEY: # TODO: Fill with your own wandb token, or use --env to pass.

resources:
  accelerators: A100:1

# Run on two nodes with 1 GPU each
num_nodes: 2

setup: |
  git clone https://github.com/huggingface/transformers.git -b v4.30.1
  cd transformers
  
  pip install -e .
  cd examples/pytorch/question-answering/
  pip install -r requirements.txt torch==1.12.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113
  pip install wandb  

run: |
  cd transformers/examples/pytorch/question-answering/
  
  NUM_NODES=`echo "$SKYPILOT_NODE_IPS" | wc -l`
  HOST_ADDR=`echo "$SKYPILOT_NODE_IPS" | head -n1`

  torchrun \
    --nnodes=$NUM_NODES \
    --nproc_per_node=$SKYPILOT_NUM_GPUS_PER_NODE \
    --master_port=12375 \
    --master_addr=$HOST_ADDR \
    --node_rank=${SKYPILOT_NODE_RANK} \
  run_qa.py \
    --model_name_or_path bert-base-uncased \
    --dataset_name squad \
    --do_train \
    --do_eval \
    --per_device_train_batch_size 12 \
    --learning_rate 3e-5 \
    --num_train_epochs 50 \
    --max_seq_length 384 \
    --doc_stride 128 \
    --report_to wandb \
    --run_name $SKYPILOT_TASK_ID \
    --output_dir ~/checkpoints \
    --save_total_limit 10 \
    --save_steps 1000  

您也可以通过修改 --output_dir 标志,将检查点配置记录到持久卷云存储桶

要启动此作业,请将上述 YAML 保存到文件(例如,bert.yaml),然后运行

sky jobs launch -n bert bert.yaml

SkyPilot 将提供一个控制器 Pod 来编排训练作业。该控制器将创建两个 Pod,分布在两个节点上,每个 Pod 请求一个 Nvidia A100 GPU。它还将确保协同调度,以便所有资源同时分配。

配置完成后,SkyPilot 运行时将安装所需的依赖项并执行训练脚本。此外,它会自动从任何故障中恢复,包括 GPU 错误和 NCCL 超时。

您可以使用 sky jobs queuesky jobs logs 命令监控作业状态和查看日志

$ sky jobs queue
Fetching managed job statuses...
Managed jobs
In progress tasks: 1 RUNNING
ID  TASK  NAME  RESOURCES   SUBMITTED   TOT. DURATION  JOB DURATION  #RECOVERIES  STATUS
1   -     bert  2x[A100:1]  3 mins ago  3m 26s         2m 18s        0            RUNNING

如果您使用 Weights and Biases (W&B) 进行日志记录,您也可以在 W&B 面板上查看训练进度

Wandb Dashboard

在 W&B 面板上监控 SkyPilot 作业的训练进度。

如果需要,您可以使用 sky jobs cancel 命令取消作业。SkyPilot 将终止 Pod 并清理作业使用的任何资源。

使用 SkyServe 在 Kubernetes 上部署生成式 AI

最后,训练完模型后,您可以使用 SkyPilot 的SkyServe 库对其进行部署。

  • 支持任何部署框架:vLLM、TGI、FastAPI 等。
  • SkyServe 为您的服务提供单一端点,由您所有基础设施中的副本支持,以确保高可用性和最低成本。
  • SkyServe 管理自动伸缩和负载均衡,并允许自定义负载均衡策略。

例如,要通过兼容 OpenAI 的端点部署 Google 开源 Gemma 模型,我们可以使用此 SkyPilot YAML 在 Kubernetes 上运行 vLLM

envs:
  MODEL_NAME: google/gemma-2b-it
  HF_TOKEN: # TODO: Fill with your own huggingface token, or use --env to pass.

resources:
  image_id: docker:vllm/vllm-openai:latest
  accelerators: T4:1
  ports: 8000

service:
  readiness_probe:
    path: /v1/chat/completions
    post_data:
      model: $MODEL_NAME
      messages:
        - role: user
          content: Hello! What is your name?
      max_tokens: 1
  replicas: 3

run: |
  conda deactivate
  python3 -c "import huggingface_hub; huggingface_hub.login('${HF_TOKEN}')"
  python3 -m vllm.entrypoints.openai.api_server --model $MODEL_NAME --host 0.0.0.0 --dtype half  

service 部分指定了就绪探针(用于检查模型是否准备好提供服务)以及运行的副本数量。您可以指定自动伸缩策略、配置滚动更新等。有关更多详细信息,请参阅文档

将上面的代码片段保存为 vllm.yaml,确保填写了 HF_TOKEN,并确保您可以访问该模型

使用 sky serve up 命令启动服务

sky serve up -n vllm vllm.yaml

SkyPilot 将启动一个控制器,该控制器将充当负载均衡器并管理服务副本。此负载均衡器将提供一个统一的端点,同时在后台它将在您的 Kubernetes 集群中提供 3 个 Pod,每个 Pod 请求一个 T4 GPU,并使用 vLLM 容器镜像实现快速启动。一旦副本的就绪探针通过,统一端点将在这些副本之间进行负载均衡请求。

要查看您的服务状态,请运行 sky serve status

$ sky serve status
Services
NAME  VERSION  UPTIME  STATUS  REPLICAS  ENDPOINT
vllm  1        3m 53s  READY   3/3       34.44.26.104:30001

Service Replicas
SERVICE_NAME  ID  VERSION  ENDPOINT                   LAUNCHED    RESOURCES                 STATUS  REGION
vllm          1   1        http://34.30.184.120:8000  5 mins ago  1x Kubernetes({'T4': 1})  READY   kubernetes
vllm          2   1        http://34.27.200.138:8000  5 mins ago  1x Kubernetes({'T4': 1})  READY   kubernetes
vllm          3   1        http://34.70.146.169:8000  3 mins ago  1x Kubernetes({'T4': 1})  READY   kubernetes
SkyServe 为您的服务提供一个统一的端点,由您基础设施中提供的副本支持。

SkyServe 公开了一个统一的端点地址,您的应用程序现在可以连接到该地址并从 Gemma 模型获取补全。在此端点背后,SkyPilot 将管理服务副本,根据负载自动伸缩它们并确保高可用性。

例如,让我们使用 curl 通过该端点获取 Gemma 模型的补全结果

$ ENDPOINT=$(sky serve status --endpoint vllm)
$ curl http://$ENDPOINT/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{
      "model": "google/gemma-2b-it",
      "messages": [
        {
          "role": "user",
          "content": "Hello! What is your name?"
        }
      ],
      "max_tokens": 25
  }'
使用 curl 获取由 SkyServe 部署的 Gemma 模型的补全结果。
点击查看输出。
{
  "id": "cmpl-79dc510b6e484352b74b056f6dc36028",
  "object": "chat.completion",
  "created": 1719526198,
  "model": "google/gemma-2b-it",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! My name is Gemma, and I'm here to assist you with any questions or tasks you may have. ",
        "tool_calls": []
      },
      "logprobs": null,
      "finish_reason": "length",
      "stop_reason": null
    }
  ],
  "usage": {
    "prompt_tokens": 16,
    "total_tokens": 41,
    "completion_tokens": 25
  }
}

扩展和更新服务

您也可以手动扩展和更新服务。例如,要将 vLLM 服务扩展到 5 个副本,请将 YAML 中的 replicas 字段更新为 5,然后运行

$ sky serve update -n vllm vllm.yaml

SkyPilot 将自动将服务扩展到 5 个副本。如果 Kubernetes 集群资源不足,SkyPilot 将突发到云端,以确保服务保持可用,即使在高负载下也是如此。

$ sky serve status
Services
NAME  VERSION  UPTIME   STATUS  REPLICAS  ENDPOINT
vllm  1        18m 48s  READY   5/5       34.44.26.104:30001

Service Replicas
SERVICE_NAME  ID  VERSION  ENDPOINT                   LAUNCHED     RESOURCES                 STATUS  REGION
vllm          1   1        http://34.30.184.120:8000  20 mins ago  1x Kubernetes({'T4': 1})  READY   kubernetes
vllm          2   1        http://34.27.200.138:8000  20 mins ago  1x Kubernetes({'T4': 1})  READY   kubernetes
vllm          3   1        http://34.70.146.169:8000  18 mins ago  1x Kubernetes({'T4': 1})  READY   kubernetes
vllm          4   1        http://3.182.116.201:8000  3 mins ago   1x GCP({'T4': 1})         READY   us-central1
vllm          5   1        http://3.182.101.130:8000  2 mins ago   1x GCP({'T4': 1})         READY   us-central1
将 vLLM 服务扩展到 5 个副本。由于 Kubernetes 集群资源不足,SkyPilot 在 GCP 上启动了副本,并通过公共端点无缝地暴露它们。

结论

Kubernetes 是为微服务设计的,在其上运行 AI 工作负载可能具有挑战性。SkyPilot 基于 Kubernetes 的优势,通过统一的接口运行完整的 AI 生命周期,同时提供突发到云端以获取额外容量的能力,超越了 Kubernetes 集群的范围。通过这样做,SkyPilot 保证了您的 AI 工作负载的高可用性和低成本。

了解更多


要接收最新更新,请为项目 GitHub 仓库 点星并关注,关注 @skypilot_org,或加入 SkyPilot 社区 Slack