部署 SkyPilot API 服务器#

SkyPilot API 服务器被打包为一个 Helm chart,用于部署 Kubernetes Ingress 控制器和 API 服务器。

提示

本指南面向管理员,用于部署 API 服务器。如果您是希望连接到 API 服务器的用户,请参阅 连接到 API 服务器

先决条件#

  • 支持 LoadBalancer 或 NodePort 服务的 Kubernetes 集群

  • Helm

  • kubectl

提示

如果您没有 Kubernetes 集群,请参阅 Kubernetes 部署指南 进行设置。

您也可以使用现有的 SkyPilot 安装在云虚拟机上部署 API 服务器。请参阅 备选方案:在云虚拟机上部署

步骤 1:部署 API 服务器 Helm chart#

使用以下命令安装 SkyPilot Helm chart

# Ensure the helm repository is added and up to date
helm repo add skypilot https://helm.skypilot.co
helm repo update

# The following variables will be used throughout the guide
# NAMESPACE is the namespace to deploy the API server in
NAMESPACE=skypilot
# RELEASE_NAME is the name of the helm release, must be unique within the namespace
RELEASE_NAME=skypilot
# Replace with your username and password to configure the basic auth credentials for the API server
WEB_USERNAME=skypilot
WEB_PASSWORD=yourpassword
AUTH_STRING=$(htpasswd -nb $WEB_USERNAME $WEB_PASSWORD)
# Deploy the API server
helm upgrade --install $RELEASE_NAME skypilot/skypilot-nightly --devel \
  --namespace $NAMESPACE \
  --create-namespace \
  --set ingress.authCredentials=$AUTH_STRING
标志解释

以下是上面命令中使用的标志的详细说明

  • upgrade --install:如果 API 服务器已存在,则升级;如果不存在,则安装。

  • --devel:使用 SkyPilot helm chart 的最新开发版本。要使用特定版本,请向 helm upgrade 命令传递 --version 标志(例如,--version 0.1.0)。

  • --namespace $NAMESPACE:指定部署 API 服务器的命名空间。

  • --create-namespace:如果命名空间不存在,则创建。

  • –set ingress.authCredentials=$AUTH_STRING:设置 API 服务器的基本认证凭据。

有关可用配置选项的更多详细信息,请参阅 SkyPilot API 服务器 Helm Chart 值

提示

默认情况下,部署的 API 服务器将被配置为使用托管 Kubernetes 集群来启动任务。请参阅 可选:配置云账户 以配置更多云和 Kubernetes 集群的凭据。

API 服务器部署后,您可以使用以下命令检查 API 服务器 Pod 的状态

kubectl get pods --namespace $NAMESPACE -l app=${RELEASE_NAME}-api --watch

您应该会看到 Pod 正在初始化并最终变为运行和就绪状态。如果不是,请参阅 Helm 部署故障排除 来诊断问题。

步骤 2:获取 API 服务器 URL#

API 服务器部署后,我们可以获取 API 服务器 URL。我们使用 nginx ingress 来暴露 API 服务器。

我们默认使用 NodePort 服务是暴露 API 服务器的推荐方式,因为某些云负载均衡器(例如 GKE)不支持 websocket 连接,而 SkyPilot 的 Kubernetes SSH 隧道需要 websocket 连接。

获取 ingress 控制器 URL

$ HOST=$(kubectl get svc ${RELEASE_NAME}-ingress-nginx-controller --namespace $NAMESPACE -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ ENDPOINT=http://${WEB_USERNAME}:${WEB_PASSWORD}@${HOST}
$ echo $ENDPOINT
http://skypilot:[email protected]

提示

如果您使用的 Kubernetes 集群不支持 LoadBalancer,您可能会在上面的输出中看到一个空的 IP 地址。在这种情况下,请改用 NodePort 选项。

提示

有关 LoadBalancer 服务的细粒度控制,请参阅 ingress-nginx 的 helm 值。请注意,所有值都应放在 ingress-nginx. 前缀下,因为 ingress-nginx chart 是作为子 chart 安装的。

  1. 在您的节点上选择两个未使用的端口,并允许网络入站流量通过这些端口。本示例将使用 30050 和 30051。

  2. 升级 API 服务器以使用 NodePort,并将节点端口设置为选定的端口

$ helm upgrade --namespace $NAMESPACE $RELEASE_NAME skypilot/skypilot-nightly --devel \
  --set ingress-nginx.controller.service.type=NodePort \
  --set ingress-nginx.controller.service.nodePorts.http=30050 \
  --set ingress-nginx.controller.service.nodePorts.https=30051
  1. 使用以下命令获取 ingress 控制器 URL

$ NODE_PORT=$(kubectl get svc ${RELEASE_NAME}-ingress-controller-np --namespace $NAMESPACE -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}')
$ NODE_IP=$(kubectl get nodes -o jsonpath='{ $.items[0].status.addresses[?(@.type=="ExternalIP")].address }')
$ ENDPOINT=http://${WEB_USERNAME}:${WEB_PASSWORD}@${NODE_IP}:${NODE_PORT}
$ echo $ENDPOINT
http://skypilot:[email protected]:30050

提示

您也可以省略 ingress-nginx.controller.service.nodePorts.httpingress-nginx.controller.service.nodePorts.https,以使用 NodePort 范围内的随机端口(默认 30000-32767)。如果您这样做,请确保这些端口在您的节点上是开放的。

提示

为了避免云提供商频繁更改节点上的 IP 地址,您可以为您的节点附加一个静态 IP 地址(GKE 说明),并在上面的命令中将其用作 NODE_IP

步骤 3:测试 API 服务器#

通过 curl 请求健康检查端点来测试 API 服务器

$ curl ${ENDPOINT}/api/health
{"status":"healthy","api_version":"1","commit":"ba7542c6dcd08484d83145d3e63ec9966d5909f3-dirty","version":"1.0.0-dev0"}

如果一切顺利,您现在就可以开始使用 API 服务器了。请参阅 连接到 API 服务器 以将您的本地 SkyPilot 客户端连接到 API 服务器。

可选:配置云账户#

以下标签页描述了如何在 API 服务器上配置不同云的凭据。所有云凭据都存储在 Kubernetes secrets 中。

注意

如果您还没有部署 SkyPilot API 服务器,请参阅 步骤 1:部署 API 服务器 Helm chart,了解您在下面的 helm 部署过程中可能需要设置的其他值。

在 API 服务器部署后配置凭据时,将自动触发 API 服务器重启以应用新凭据。请参阅 升级 SkyPilot API 服务器 了解有关潜在停机时间和缓解措施的更多详细信息。

默认情况下,SkyPilot API 服务器被授予权限使用其托管 Kubernetes 集群,并将在与 API 服务器相同的命名空间中启动任务

  • 要禁用使用托管 Kubernetes 集群,请在 Helm chart 值中设置 kubernetesCredentials.useApiServerCluster=false

  • 要为任务使用不同的命名空间,请在 Helm chart 值中设置 kubernetesCredentials.inclusterNamespace=<namespace>

提示

授予 API 服务器的默认权限可以直接使用。为了进一步加固,您可以参阅 在 helm 部署中设置最小权限 了解权限以及如何自定义它们。

要向其他集群进行身份验证,首先使用具有 所需权限 的 kubeconfig 文件创建 Kubernetes secret

kubectl create secret generic kube-credentials \
  --namespace $NAMESPACE \
  --from-file=config=~/.kube/config

创建 secret 后,在 Helm chart 值中设置 kubernetesCredentials.useKubeconfig=truekubernetesCredentials.kubeconfigSecretName 以使用 kubeconfig 进行身份验证

helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
  --namespace $NAMESPACE \
  # keep the Helm chart values set in the previous step
  --reuse-values \
  --set kubernetesCredentials.useKubeconfig=true \
  --set kubernetesCredentials.kubeconfigSecretName=kube-credentials

提示

如果您使用的 kubeconfig 文件包含 基于 exec 的身份验证(例如 GKE 默认的基于 gke-gcloud-auth-plugin 的身份验证),您需要从 exec 配置的 command 字段中剥离路径信息。您可以使用 exec_kubeconfig_converter.py 脚本来完成此操作。

python -m sky.utils.kubernetes.exec_kubeconfig_converter --input ~/.kube/config --output ~/.kube/config.converted

然后使用转换后的 kubeconfig 文件 ~/.kube/config.converted 创建 Kubernetes secret。

要使用多个 Kubernetes 集群,您需要在 SkyPilot 配置中将上下文名称添加到 allowed_contexts。下面显示了一个允许使用托管 Kubernetes 集群和另外两个 Kubernetes 集群的示例配置文件

kubernetes:
  allowed_contexts:
  # The hosting Kubernetes cluster, you cannot set this if the hosting cluster is disabled by kubernetesCredentials.useApiServerCluster=false
  - in-cluster
  # The additional Kubernetes context names in the kubeconfig you configured
  - context1
  - context2

请参阅 设置 SkyPilot 配置 了解如何在 Helm chart 值中设置 SkyPilot 配置。

请确保您拥有访问密钥 ID 和秘密访问密钥。

使用您的 AWS 凭据创建一个 Kubernetes secret

kubectl create secret generic aws-credentials \
  --namespace $NAMESPACE \
  --from-literal=aws_access_key_id=YOUR_ACCESS_KEY_ID \
  --from-literal=aws_secret_access_key=YOUR_SECRET_ACCESS_KEY

YOUR_ACCESS_KEY_IDYOUR_SECRET_ACCESS_KEY 替换为您的实际 AWS 凭据。

在 Helm values 文件中设置 awsCredentials.enabled=trueawsCredentials.awsSecretName=aws-credentials 以启用 AWS 凭据。

helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
    --namespace $NAMESPACE \
    # keep the Helm chart values set in the previous step
    --reuse-values \
    --set awsCredentials.enabled=true
使用现有的 AWS 凭据

您还可以设置以下值来使用已包含您的 AWS 凭据的 secret

我们使用服务账户与 GCP 进行身份验证。请参阅 GCP 服务账户 指南了解如何设置服务账户。

一旦您拥有服务账户的 JSON 密钥,创建一个 Kubernetes secret 来存储它

kubectl create secret generic gcp-credentials \
  --namespace $NAMESPACE \
  --from-file=gcp-cred.json=YOUR_SERVICE_ACCOUNT_JSON_KEY.json

安装或升级 Helm chart 时,通过设置 gcpCredentials.enabled=truegcpCredentials.projectId 为您的项目 ID 来启用 GCP 凭据

helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
  --namespace $NAMESPACE \
  # keep the Helm chart values set in the previous step
  --reuse-values \
  --set gcpCredentials.enabled=true \
  --set gcpCredentials.projectId=YOUR_PROJECT_ID
使用现有的 GCP 凭据

您还可以设置以下值来使用已包含您的 GCP 凭据的 secret

# TODO: replace with your secret name
helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
    --namespace $NAMESPACE \
    --reuse-values \
    --set gcpCredentials.enabled=true \
    --set gcpCredentials.gcpSecretName=your_secret_name

SkyPilot API 服务器使用 API 密钥 与 RunPod 进行身份验证。要配置 RunPod 访问,请访问 RunPod 控制台上的 设置 页面并生成 API 密钥

密钥生成后,创建一个 Kubernetes secret 来存储它

kubectl create secret generic runpod-credentials \
  --namespace $NAMESPACE \
  --from-literal api_key=YOUR_API_KEY

安装或升级 Helm chart 时,通过设置 runpodCredentials.enabled=true 来启用 RunPod 凭据

使用现有的 RunPod 凭据

您还可以设置以下值来使用已包含您的 RunPod API 密钥的 secret

# TODO: replace with your secret name
helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
    --namespace $NAMESPACE \
    --reuse-values \
    --set runpodCredentials.enabled=true \
    --set runpodCredentials.runpodSecretName=your_secret_name

SkyPilot API 服务器使用 API 密钥 与 Lambda 进行身份验证。要配置 Lambda 访问,请访问您的 Lambda Cloud 控制台上的 API 密钥 页面并生成 API 密钥

密钥生成后,创建一个 Kubernetes secret 来存储它

kubectl create secret generic lambda-credentials \
  --namespace $NAMESPACE \
  --from-literal api_key=YOUR_API_KEY

安装或升级 Helm chart 时,通过设置 lambdaCredentials.enabled=true 来启用 Lambda 凭据

helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
  --namespace $NAMESPACE \
  # keep the Helm chart values set in the previous step
  --reuse-values \
  --set lambdaCredentials.enabled=true
使用现有的 Lambda 凭据

您还可以设置以下值来使用已包含您的 Lambda 凭据的 secret

# TODO: replace with your secret name
helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
    --namespace $NAMESPACE \
    --reuse-values \
    --set lambdaCredentials.enabled=true \
    --set lambdaCredentials.lambdaSecretName=your_secret_name

我们使用服务账户与 Nebius 进行身份验证。请参阅 Nebius 服务账户 指南了解如何设置服务账户。

一旦您拥有服务账户的 JSON 凭据,创建一个 Kubernetes secret 来存储它

kubectl create secret generic nebius-credentials \
  --namespace $NAMESPACE \
  --from-file=credentials.json=$HOME/.nebius/credentials.json

安装或升级 Helm chart 时,通过设置 nebiusCredentials.enabled=truenebiusCredentials.tenantId 为您的租户 ID 来启用 Nebius 凭据

helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
  --namespace $NAMESPACE \
  # keep the Helm chart values set in the previous step
  --reuse-values \
  --set nebiusCredentials.enabled=true \
  --set nebiusCredentials.tenantId=YOUR_TENANT_ID
使用现有的 Nebius 凭据

您还可以设置以下值来使用已包含您的 Nebius 凭据的 secret

# TODO: replace with your secret name
helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
    --namespace $NAMESPACE \
    --reuse-values \
    --set nebiusCredentials.enabled=true \
    --set nebiusCredentials.nebiusSecretName=your_secret_name

您可以在 API 服务器 Pod 部署并运行后,通过 kubectl exec 进入该 Pod,并运行相关的 安装命令 手动配置其他云的凭据。

请注意,手动配置的凭据在 API 服务器重启后不会持久化。

通过 secrets 配置其他云的支持即将推出!

升级 API 服务器#

请参阅 升级 SkyPilot API 服务器 了解如何升级 API 服务器。

卸载#

要卸载 API 服务器,请运行

helm uninstall $RELEASE_NAME --namespace $NAMESPACE

这将删除 API 服务器和所有相关资源。

其他说明#

容错和状态持久化#

SkyPilot API 服务器设计为具有容错能力。如果 API 服务器 Pod 被终止,Kubernetes 将自动创建一个新的 Pod 来替换它。

为了在 Pod 终止期间保留状态,我们使用持久卷声明。持久卷声明由 Helm chart 创建的 PersistentVolume 提供支持。

您可以通过创建 values.yaml 文件并使用以下值来自定义存储设置

storage:
  # Enable/disable persistent storage
  enabled: true
  # Storage class name - leave empty to use cluster default
  storageClassName: ""
  # Access modes - ReadWriteOnce or ReadWriteMany depending on storage class support
  accessMode: ReadWriteOnce
  # Storage size
  size: 10Gi
  # Optional selector for matching specific PVs
  selector: {}
    # matchLabels:
    #   environment: prod
  # Optional volume name for binding to specific PV
  volumeName: ""
  # Optional annotations
  annotations: {}

例如,要使用特定的存储类并增加存储大小

# values.yaml
storage:
  enabled: true
  storageClassName: "standard"
  size: 20Gi

使用以下命令应用配置

helm upgrade --install skypilot skypilot/skypilot-nightly --devel -f values.yaml

EKS 的额外设置#

为了支持 API 服务器状态的持久存储,我们需要一个支持持久卷的存储类。如果您已经有一个支持持久卷的存储类,您可以跳过以下步骤。

我们将使用 Amazon EBS CSI 驱动程序 创建一个支持由 Amazon EBS 支持的持久卷的存储类。您也可以使用其他支持持久卷的存储类,例如 EFS

以下步骤基于 官方文档。请遵循官方文档根据您的集群调整步骤。

  1. 请确保您的集群已启用 OIDC。按照此处的步骤操作。

    1. 您需要创建并绑定一个具有创建 EBS 卷权限的 IAM 角色。请参阅此处的说明。

  2. 安装 Amazon EBS CSI 驱动程序。推荐的方法是创建 EKS 插件。

安装 EBS CSI 驱动程序后,默认的 gp2 存储类将由 EBS 卷提供支持。

设置 SkyPilot 配置#

Helm chart 支持在 API 服务器上设置全局 SkyPilot 配置 YAML 文件。配置文件作为 ~/.sky/config.yaml 挂载到 API 服务器容器中。

要设置配置文件,请将 --set-file apiService.config=path/to/your/config.yaml 传递给 helm 命令

# Create the config.yaml file
cat <<EOF > config.yaml
admin_policy: admin_policy_examples.AddLabelsPolicy

jobs:
  controller:
    resources:
        cpus: 2+

allowed_clouds:
  - aws
  - kubernetes

kubernetes:
  allowed_contexts:
    - my-context
    - my-other-context
EOF

# Install the API server with the config file
helm upgrade --install skypilot skypilot/skypilot-nightly --devel \
  --namespace $NAMESPACE \
  # Reuse the values set in the previous steps, if any
  --reuse-values \
  --set-file apiService.config=config.yaml

您也可以直接在 values.yaml 文件中设置配置值,例如

apiService:
  config: |
    allowed_clouds:
    - aws
    - kubernetes

要应用新配置,请使用更新后的 values.yaml 文件重新运行 helm upgrade

设置管理员策略#

Helm chart 支持在 API 服务器启动前安装管理员策略。

为此,将 apiService.preDeployHook 设置为您要运行的命令。例如,要安装管理员策略,请创建包含以下内容的 values.yaml 文件

# values.yaml
apiService:
  preDeployHook: |
   echo "Installing admin policy"
   pip install git+https://github.com/michaelvll/admin-policy-examples

  config: |
    admin_policy: admin_policy_examples.AddLabelsPolicy

然后在运行 helm upgrade 命令时使用 -f 标志应用 values.yaml 文件

helm upgrade --install skypilot skypilot/skypilot-nightly --devel -f values.yaml

在 helm 部署中设置最小权限#

在 helm 部署中,API 服务器被授予一组默认权限来访问托管 Kubernetes 集群。您可以在以下条件下自定义权限

  • 通过使用 kubernetes.remote_identity 减少 RBAC 权限:默认情况下,API 服务器创建服务账户和 RBAC 角色以授予 SkyPilot 任务 Pod 权限。这反过来要求 API 服务器具有操作 RBAC 角色和服务账户的权限。您可以通过以下步骤禁用此功能

    1. 请参阅 设置 SkyPilot 配置kubernetes.remote_identity 设置为 API 服务器的服务账户,该账户已具有必要的权限

    # TODO: replace ${RELEASE_NAME} with the actual release name in deployment step
    kubernetes:
      remote_identity: ${RELEASE_NAME}-api-sa
    

    注意

    如果您还通过 kubernetesCredentials.useKubeconfig 授予 API 服务器外部 Kubernetes 集群权限,则必须在这些 Kubernetes 集群中手动准备具有足够权限的相同服务账户。

    1. 在 helm 值中设置 rbac.manageRbacPolicies=false 以禁用 RBAC 策略

    helm upgrade --install skypilot skypilot/skypilot-nightly --devel --reuse-values \
      --set rbac.manageRbacPolicies=false
    
  • 如果您的用例不需要对象存储挂载,您可以通过设置 rbac.manageSystemComponents=false 禁用管理 SkyPilot 系统组件的权限

    helm upgrade --install skypilot skypilot/skypilot-nightly --devel --reuse-values \
      --set rbac.manageSystemComponents=false
    

如果您想使用一个满足 SkyPilot 所需最小权限 的现有服务账户和权限,而不是由 Helm 管理的服务账户,您可以禁用 RBAC 策略的创建并指定要使用的服务账户名称

helm upgrade --install skypilot skypilot/skypilot-nightly --devel --reuse-values \
  --set rbac.create=false \
  --set rbac.serviceAccountName=my-existing-service-account

从旧版 NodePort 服务迁移#

如果您正在从早期的 0.8.0 nightly 版本升级,并且之前部署了 NodePort 服务(名为 ${RELEASE_NAME}-ingress-controller-np),将引发错误要求进行迁移。此外,将创建一个新服务来暴露 API 服务器(默认使用 LoadBalancer 服务类型)。您可以根据您的需求选择以下任何选项继续升级过程

  • 保留旧版 NodePort 服务,并逐步迁移到新的 LoadBalancer 服务

    在您的 helm upgrade 命令中添加 --set ingress.nodePortEnabled=true 以保留旧版 NodePort 服务。现有客户端可以继续使用先前的 NodePort 服务。在所有客户端迁移到新服务后,您可以通过在 helm upgrade 命令中添加 --set ingress.nodePortEnabled=false 来禁用旧版 NodePort 服务。

  • 禁用旧版 NodePort 服务

    在您的 helm upgrade 命令中添加 --set ingress.nodePortEnabled=false 以禁用旧版 NodePort 服务。客户端需要使用新服务连接到 API 服务器。

注意

禁用 NodePort 服务之前,请确保没有客户端正在使用它。

注意

请参阅 步骤 2:获取 API 服务器 URL 了解如何自定义和/或连接到新服务。

备选方案:在云虚拟机上部署#

注意

虚拟机部署不提供故障转移和优雅升级支持。我们建议在生产环境中使用 Helm 部署 部署 SkyPilot API 服务器

您也可以使用现有的 SkyPilot 安装直接在云虚拟机上部署 API 服务器。

步骤 1:使用 SkyPilot 在云虚拟机上部署 API 服务器#

编写 SkyPilot API 服务器 YAML 文件并使用 sky launch 部署 API 服务器

# Write the YAML to a file
cat <<EOF > skypilot-api-server.yaml
resources:
  cpus: 8+
  memory: 16+
  ports: 46580
  image_id: docker:berkeleyskypilot/skypilot-nightly:latest

run: |
  sky api start --deploy
EOF

# Deploy the API server
sky launch -c api-server skypilot-api-server.yaml

步骤 2:获取 API 服务器 URL#

API 服务器部署后,您可以使用以下命令获取 API 服务器 URL

$ sky status --endpoint 46580 api-server
http://a.b.c.d:46580

通过 curl 请求健康检查端点来测试 API 服务器

$ curl ${ENDPOINT}/health
SkyPilot API Server: Healthy

如果一切顺利,您现在就可以开始使用 API 服务器了。请参阅 连接到 API 服务器 以将您的本地 SkyPilot 客户端连接到 API 服务器。

注意

默认情况下,使用上述 YAML 文件部署的 API 服务器没有任何身份验证。我们建议添加一个身份验证层(例如 nginx 反向代理)或在 Kubernetes 集群上使用 SkyPilot helm chart 以获得更安全的部署。

提示

如果您在同一环境中安装 SkyPilot API 客户端,我们建议使用不同的 Python 环境(venv、conda 等),以避免与用于部署 API 服务器的 SkyPilot 安装发生冲突。