
用 SkyPilot 一键在云上部署 Kubernetes 集群从 k3s 安装、GPU 使能到 AI 任务调度实战【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot本文基于仓库 examples/k8s_cloud_deploy 目录下的完整示例讲解如何借助 SkyPilot 在云厂商的裸 VM 上「一键」部署一个自带 GPU 支持的 Kubernetes 集群并让本地的kubectl与sky命令直接对接该集群。读完本文你将掌握cloud_k8s.yaml中每个配置项的真实作用、launch_k8s.sh的端到端执行链路以及如何在部署好的集群上运行交互式开发环境、托管作业Jobs并完成队列调度与销毁。一、方案概览为什么要用 SkyPilot 在云上部署 Kubernetes在云端手动搭建一套可用的 GPU Kubernetes 集群通常需要依次完成购买多台带 GPU 的 VM → 安装容器运行时与 kubelet → 部署控制平面 → 打通网络与证书 → 安装 NVIDIA GPU Operator → 配置 RuntimeClass → 拉取并改写 kubeconfig。这一流程冗长且极易出错。SkyPilot 提供了一条捷径你只需要写一个描述「集群长什么样」的 YAMLcloud_k8s.yaml再执行一个脚本launch_k8s.shSkyPilot 就会替你完成 VM 采购、集群部署、GPU 使能、kubeconfig 抓取与本地kubectl对接的全部工作。官方文档 kubernetes-deployment.rst 将这种模式称为 Deploying on cloud VMs并明确说明仓库中提供了负责采购 VM、安装 Kubernetes、配置 GPU 支持以及配置本地 kubeconfig 的脚本。本文示例默认以 Lambda Cloud 作为云厂商infra: lambda但通过修改 YAML 中的infra字段即可切换到其他云。二、前置条件1. 安装 SkyPilot nightly 版本示例要求使用最新的 SkyPilot nightly 发行版并同时启用lambdaLambda Cloud 支持与kubernetesKubernetes 支持两个 extrapip install skypilot-nightly[lambda,kubernetes]kubernetesextra 会引入kubernetesPython 客户端依赖这是 SkyPilot 以 Kubernetes 为后端cloud与集群 API Server 交互所必需的。2. 开放 API Server 所需端口SkyPilot 会在被采购的 VM 上安装 k3sk3s 的 API Server 监听6443端口而后续kubectl/sky通过 HTTPS 访问时也会用到443。因此需要满足以下二选一使用支持在 SkyPilot 层面直接打开端口的云在 YAML 中配置ports或者手动在云控制台的防火墙/安全组中放行 VM 的6443与443入站流量。以 Lambda Cloud 为例需要在其 Dashboard 的防火墙配置中允许443和6443端口的入站连接。说明示例 YAML 中的ports: 6443默认被注释掉是因为 Lambda Cloud 会在 SkyPilot 层面对 6443 做端口映射而如果改用 GCP、AWS 或 Azure则需取消注释ports: 6443行让 SkyPilot 在 VM 上打开对应端口详见下文配置文件分析。三、核心配置文件 cloud_k8s.yaml 详解完整文件位于 cloud_k8s.yaml它同时承担两项职责一是描述 SkyPilot 集群的资源配置VM 规格、节点数二是通过run命令段定义 k3s 集群的完整安装脚本。逐项拆解如下。1. 资源与集群规模resources: infra: lambda accelerators: A10:1 # Uncomment the following line to expose ports on a different cloud # ports: 6443 num_nodes: 2配置项含义说明infra: lambda指定底层基础设施为 Lambda Cloud可替换为其他云见下文infra字段解析accelerators: A10:1每台节点配备 1 块 NVIDIA A10示例共 2 节点即 2 块 A10ports: 6443在 VM 上打开 6443 端口默认注释切换到 GCP/AWS/Azure 等云时需要取消注释num_nodes: 2集群节点总数1 个作为控制平面head其余作为 worker 节点加入关于infra字段从源码 sky/resources.py 可以看到它是资源规格的顶层字段格式为cloud、cloud/region或cloud/region/zone同时该文件中明确注释cloud/region/zone为已弃用字段推荐统一使用infra且二者不能同时指定否则抛出ValueError。解析逻辑位于 sky/utils/infra_utils.py对k8s/kubernetes前缀有特殊处理k8s/之后的整段字符串会被当作 Kubernetescontext 名称即源码注释里说的sky.Resources(infrak8s/my-cluster-ctx, acceleratorsV100)用法且k8s会被归一化为kubernetes对*通配符会归一化为None表示「任意值均可」其他云则按/最多切分成 cloud/region/zone 三段格式非法时抛出ValueError。2. 集群加入令牌envs: SKY_K3S_TOKEN: mytoken # Can be any string, used to join worker nodes to the clusterSKY_K3S_TOKEN是一个任意字符串用于 k3s worker 节点向控制平面注册时进行身份验证。它会被注入到所有节点的环境中供后续run脚本读取。3. run 命令k3s 集群的完整安装逻辑run段是一个 Shell 脚本SkyPilot 会将它分发到每个节点执行。脚本通过 SkyPilot 自动注入的SKYPILOT_NODE_RANK与SKYPILOT_NODE_IPS两个环境变量来区分节点角色这两个变量由 sky/backends/task_codegen.py 按节点 rank 与实际 IP 列表生成并注入run: | # ...wait_for_gpu_operator_installation 辅助函数见下文 if [ ${SKYPILOT_NODE_RANK} -ne 0 ]; then # Worker nodes MASTER_ADDRecho $SKYPILOT_NODE_IPS | head -n1 echo Worker joining k3s cluster ${MASTER_ADDR} curl -sfL https://get.k3s.io | K3S_URLhttps://${MASTER_ADDR}:6443 K3S_TOKEN${SKY_K3S_TOKEN} sh - exit 0 fiWorker 节点分支SKYPILOT_NODE_RANK不为 0 的节点即为 worker它们从SKYPILOT_NODE_IPS中取出第一个 IPhead 节点作为 master 地址通过K3S_URL与K3S_TOKEN环境变量执行 k3s 官方安装脚本把自己注册进集群后立即退出。Head 节点分支SKYPILOT_NODE_RANK为 0即控制平面# Head node curl -sfL https://get.k3s.io | K3S_TOKEN${SKY_K3S_TOKEN} sh - # Copy over kubeconfig file echo Copying kubeconfig file mkdir -p $HOME/.kube sudo cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config # Wait for k3s to be ready echo Waiting for k3s to be ready sleep 5 kubectl wait --forconditionready node --all --timeout5m --kubeconfig ~/.kube/config以K3S_TOKEN方式初始化 k3s 控制平面将/etc/rancher/k3s/k3s.yaml复制到~/.kube/config并修正属主方便本节点使用kubectl用kubectl wait等待所有节点进入 Ready 状态5 分钟超时。GPU 支持安装 NVIDIA GPU Operator。接下来 head 节点负责为集群安装 GPU 驱动与容器运行时支持# GPU support echo Installing helm curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm repo update echo Creating namespace gpu-operator kubectl create namespace gpu-operator --kubeconfig ~/.kube/config || true # Patch ldconfig echo Patching ldconfig sudo ln -s /sbin/ldconfig /sbin/ldconfig.real echo Installing GPU operator helm install gpu-operator -n gpu-operator --create-namespace \ nvidia/gpu-operator $HELM_OPTIONS \ --set toolkit.env[0].nameCONTAINERD_CONFIG \ --set toolkit.env[0].value/var/lib/rancher/k3s/agent/etc/containerd/config.toml \ --set toolkit.env[1].nameCONTAINERD_SOCKET \ --set toolkit.env[1].value/run/k3s/containerd/containerd.sock \ --set toolkit.env[2].nameCONTAINERD_RUNTIME_CLASS \ --set toolkit.env[2].valuenvidia wait_for_gpu_operator_installation这段脚本的关键点通过helm repo add nvidia添加 NVIDIA 官方 Helm 仓库通过环境变量注入k3s 特有路径CONTAINERD_CONFIG指向/var/lib/rancher/k3s/agent/etc/containerd/config.tomlk3s 的 containerd 配置CONTAINERD_SOCKET指向/run/k3s/containerd/containerd.sockCONTAINERD_RUNTIME_CLASS设为nvidia。这套 k3s 专用的参数与官方部署文档 kubernetes-deployment.rst 中 K3s 一节的安装说明完全一致sudo ln -s /sbin/ldconfig /sbin/ldconfig.real是官方文档里提到的 nvidia-docker 已知问题的变通修复K3s 场景下该符号链接路径同样适用安装完成后进入等待循环每 5 秒检查一次kubectl describe nodes输出中是否出现nvidia.com/gpu:资源标记最多等待 600 秒10 分钟超时则exit 1。官方文档提示 GPU Operator 安装需要几分钟期间出现部分 CrashLoopBackOff 属正常现象可通过kubectl get pods -n gpu-operator观察安装进度。创建 RuntimeClass。最后为 k3s 创建名为nvidia的 RuntimeClass# Create RuntimeClass sleep 5 echo Creating RuntimeClass kubectl apply --kubeconfig ~/.kube/config -f - EOF apiVersion: node.k8s.io/v1 kind: RuntimeClass metadata: name: nvidia handler: nvidia EOF该 RuntimeClass 会被 SkyPilot 自动用于调度 GPU Pod见 kubernetes-deployment.rst。四、launch_k8s.sh一键脚本的完整执行链路launch_k8s.sh 将上述 YAML 的部署、kubeconfig 抓取与本地对接封装为一个命令./launch_k8s.sh其执行流程可拆解为四步理解它对排查部署问题很有帮助。1. 发起 SkyPilot launchCLUSTER_NAME${CLUSTER_NAME:-k8s} sky launch -y -c ${CLUSTER_NAME} cloud_k8s.yaml集群名默认取k8s可通过环境变量CLUSTER_NAME覆盖例如CLUSTER_NAMEmyk8s ./launch_k8s.sh-y跳过确认-c k8s指定集群名随后 SkyPilot 完成 VM 采购、环境初始化与run脚本的分发执行。2. 获取 API Server 端点PRIMARY_ENDPOINT SKY_STATUS_OUTPUT$(SKYPILOT_DEBUG0 sky status --endpoint 6443 ${CLUSTER_NAME} 21) || true if [[ $SKY_STATUS_OUTPUT ! *ValueError* ]]; then PRIMARY_ENDPOINT$SKY_STATUS_OUTPUT else echo Primary endpoint retrieval failed or unsupported. Falling back to alternate method... fi脚本优先通过sky status --endpoint 6443 cluster获取主端点若结果中包含ValueError说明当前云不支持该方式则回退到备用方案——从 SkyPilot 生成的 SSH 配置~/.sky/generated/ssh/${CLUSTER_NAME}中解析HostName字段并拼上:6443ENDPOINT$(awk /^ *HostName / { print $2; exit} $SSH_CONFIG_FILE) ENDPOINT${ENDPOINT}:64433. 拉取并改写本地 kubeconfigmkdir -p ~/.kube rsync -av ${CLUSTER_NAME}:~/.kube/config ~/.kube/config通过rsync把 head 节点上run脚本第 4 节生成的~/.kube/config拉到本地本地已有 kubeconfig 时先备份为~/.kube/config.bak随后用awk处理删除集群段的certificate-authority-data并把server替换为https://ENDPOINT同时加入insecure-skip-tls-verify: true因为本地没有集群 CA 证书且对外访问的是公网端点。这样本地的kubectl便能直连云端 k3s 集群。4. 校验 Kubernetes 后端sleep 5 # Wait for the cluster to be ready sky check kubernetessky check kubernetes会让 SkyPilot 重新探测并确认 Kubernetes 后端的连通性将集群注册为可用的 SkyPilot 云后端。脚本成功后会输出提示可以用sky gpus list --cloud kubernetes查看集群可用 GPU用sky launch --cloud kubernetes --gpus GPU -- nvidia-smi提交测试任务。五、验证集群kubectl 与 sky 双视角部署完成后README 给出了两套并行的验证手段。kubectl确认集群本身正常注意节点名即云上 VM 的 IP版本为 k3s 的 v1.30.4k3s1$ kubectl get nodes NAME STATUS ROLES AGE VERSION 129-80-133-44 Ready none 14m v1.30.4k3s1 150-230-191-161 Ready control-plane,master 14m v1.30.4k3s1sky gpus list --cloud kubernetes则从 SkyPilot 视角确认 GPU 已被 GPU Operator 正确暴露、并可由 SkyPilot 调度$ sky gpus list --cloud kubernetes Kubernetes GPUs GPU REQUESTABLE_QTY_PER_NODE UTILIZATION A10 1 2 of 2 free Kubernetes per node GPU availability NODE GPU UTILIZATION 129-80-133-44 A10 1 of 1 free 150-230-191-161 A10 1 of 1 free输出显示 2 块 A10 均处于空闲状态且 SkyPilot 能按节点粒度报告 GPU 占用说明从驱动、容器运行时到调度器的整条链路已经打通。六、在集群上运行 AI 工作负载1. 交互式开发集群想获得一个可直接 SSH / 远程开发的 GPU 环境在云上 Kubernetes 之上再叠一层 SkyPilot 开发集群即可sky launch -c mycluster --cloud kubernetes --gpus A10:1SkyPilot 会同时为你配置好 SSHSSH 直连ssh myclusterVSCode 远程开发code --remote ssh-remotemycluster /home这正是 SkyPilot 交互式开发interactive development模式在自建 Kubernetes 上的落地用法开发者无需关心 Pod 与端口映射细节。2. 托管作业与自动排队提交一次性作业sky jobs launch --gpus A10:1 --cloud kubernetes -- nvidia-smi; sleep 600当集群资源不足时可以持续提交多个作业让 SkyPilot 的托管作业队列自动处理排队。README 给出了一个真实的排队观察结果$ sky jobs queue Fetching managed job statuses... Managed jobs In progress tasks: 2 RUNNING, 1 STARTING ID TASK NAME RESOURCES SUBMITTED TOT. DURATION JOB DURATION #RECOVERIES STATUS 3 - finetune 1x[A10:1] 24 secs ago 24s - 0 STARTING 2 - qlora 1x[A10:1] 2 min ago 2m 18s 12s 0 RUNNING 1 - sky-cmd 1x[A10:1] 4 mins ago 4m 27s 3m 12s 0 RUNNING可以看到finetune作业处于 STARTING等待资源、qlora与sky-cmd正在 RUNNING这正是 SkyPilot 在集群资源不足时的排队调度的直观体现。3. 用 kubectl 观察底层 PodSkyPilot 作业在 Kubernetes 上以 Pod 形式运行可以在kubectl侧验证$ kubectl get pods NAME READY STATUS RESTARTS AGE qlora-2-2ea4-head 1/1 Running 0 5m31s sky-cmd-1-2ea4-head 1/1 Running 0 8m36s sky-jobs-controller-2ea485ea-2ea4-head 1/1 Running 0 10m输出中除了用户作业对应的 Pod还能看到 SkyPilot 部署的sky-jobs-controller控制器 Pod——它是 SkyPilot 托管作业系统在集群内的执行载体也是理解「SkyPilot 作业如何映射到 Kubernetes」的关键观察点。七、销毁集群不再使用时一条命令即可回收全部云资源sky down k8sSkyPilot 会销毁对应集群名下所有 VM 及其上部署的 k3s 集群。八、排障与注意事项GPU Operator 安装较慢官方文档指出安装需要数分钟期间出现部分 Pod CrashLoopBackOff 属正常现象可通过kubectl get pods -n gpu-operator观察若长期卡死可检查 head 节点上是否已正确创建/sbin/ldconfig.real符号链接对应cloud_k8s.yaml中的sudo ln -s步骤端口不通导致 kubeconfig 失效kubectl/sky无法连接时优先检查云防火墙是否放行了6443与443若在 GCP/AWS/Azure 上部署需确认已取消注释ports: 6443infra 字段格式infra支持cloud、cloud/region、cloud/region/zone三种粒度Kubernetes context 用k8s/context表达源码见 sky/utils/infra_utils.py它与旧的cloud/region/zone字段不能混用sky down k8s默认删除名为k8s的集群如果部署时通过CLUSTER_NAME指定了其他名称销毁时需使用对应集群名。通过这套「YAML 描述 一键脚本」的方案SkyPilot 将「云端 GPU VM 采购、k3s 部署、GPU Operator 使能、kubeconfig 对接」压缩为两条命令让开发团队可以像使用公有云 K8s 一样把自建 GPU 集群直接当作 SkyPilot 的调度后端来跑训练、微调与推理负载。【免费下载链接】skypilotThe AI Compute Platform for frontier teams. SkyPilot turns fragmented AI compute into one AI supercomputer, so frontier AI teams build custom intelligence faster.项目地址: https://gitcode.com/GitHub_Trending/sk/skypilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考