在 Kubernetes 上暴露服务#

注意

这是一个关于如何配置现有 Kubernetes 集群(以及涉及的注意事项),以便通过 SkyPilot 成功地将端口和服务暴露到外部的指南。

如果您是 SkyPilot 用户,并且您的集群已经设置为暴露端口,请参阅开放端口,其中解释了如何在任务中通过 SkyPilot 暴露服务。

SkyServe 和 SkyPilot 集群可以开放端口来暴露服务。对于运行在 Kubernetes 上的 SkyPilot 集群,我们支持以下两种模式来暴露端口

默认情况下,SkyPilot 会在您的 Kubernetes 集群上创建一个 LoadBalancer Service 来暴露端口。

如果您的集群不支持 LoadBalancer 服务,SkyPilot 也可以使用 现有的 Nginx IngressController 来创建一个 Ingress 来暴露您的服务。

LoadBalancer 服务#

此模式通过 Kubernetes LoadBalancer Service 暴露端口。这是 SkyPilot 使用的默认模式。

要使用此模式,您的 Kubernetes 集群必须支持 LoadBalancer Services

  • 在 Google GKE、Amazon EKS 或其他云托管的 Kubernetes 服务上,此模式开箱即用,无需额外配置。

  • 在裸金属和自管理的 Kubernetes 集群上,可以使用 MetalLB 来支持 LoadBalancer Services。

使用此模式时,SkyPilot 将为您在集群上暴露的所有端口创建一个 LoadBalancer Service。每个端口都可以使用 LoadBalancer 的外部 IP 地址和端口号访问。使用 sky status --endpoints <cluster> 查看所有端口的外部端点。

在基于云的 Kubernetes 集群中,这将自动创建一个外部负载均衡器。GKE 创建一个直通式负载均衡器(Pass-through Load Balancer),AWS 创建一个网络负载均衡器(Network Load Balancer)。这些负载均衡器将在集群删除时自动终止。

注意

使用 sky local up 创建的 kind 集群不支持 LoadBalancer 服务。

注意

EKS 中的默认 LoadBalancer 实现会从开放端口列表中随机选择一个端口用于负载均衡器的健康检查。如果选定的端口没有运行服务,可能会导致问题。

例如,如果一个 SkyPilot 任务暴露了 5 个端口,但只有其中 2 个端口有服务运行,EKS 可能会选择一个没有服务运行的端口,从而导致 LoadBalancer 健康检查失败。结果是,该服务将无法获得外部 IP 地址。

为解决此问题,请确保所有端口都有服务正在运行。

内部负载均衡器#

要限制您的服务只能在集群内部访问,您可以将所有 SkyPilot 服务设置为使用内部负载均衡器

根据您的云提供商,在 SkyPilot 配置文件(~/.sky/config.yaml)中设置适当的注解

# ~/.sky/config.yaml
kubernetes:
  custom_metadata:
    annotations:
      # For GCP/GKE
      networking.gke.io/load-balancer-type: "Internal"
      # For AWS/EKS
      service.beta.kubernetes.io/aws-load-balancer-internal: "true"
      # For Azure/AKS
      service.beta.kubernetes.io/azure-load-balancer-internal: "true"

Nginx Ingress#

此模式通过创建一个由现有 Nginx Ingress Controller 支持的 Kubernetes Ingress 来暴露端口。

要使用此模式

  1. 在您的 Kubernetes 集群上安装 Nginx Ingress Controller。请参考文档中针对您环境的安装说明。

  2. 验证 ingress-nginx-controller 服务具有有效的外部 IP

$ kubectl get service ingress-nginx-controller -n ingress-nginx

# Example output:
# NAME                             TYPE                CLUSTER-IP    EXTERNAL-IP     PORT(S)
# ingress-nginx-controller         LoadBalancer        10.24.4.254   35.202.58.117   80:31253/TCP,443:32699/TCP

注意

如果 EXTERNAL-IP 字段是 <none>,您可以通过在 ingress-nginx-controller 服务上添加 skypilot.co/external-ip 注解手动指定 Ingress IP 或主机名。在这种情况下,无需 EXTERNAL-IP 字段有效。

例如,如果您的 ingress-nginx-controller 服务是 NodePort

# Add skypilot.co/external-ip annotation to the nginx ingress service.
# Replace <IP> in the following command with the IP you select.
# Can be any node's IP if using NodePort service type.
$ kubectl annotate service ingress-nginx-controller skypilot.co/external-ip=<IP> -n ingress-nginx

如果 EXTERNAL-IP 字段是 <none> 并且 skypilot.co/external-ip 注解不存在,SkyPilot 将使用 localhost 作为 Ingress 的外部 IP,并且该端点可能无法从集群外部访问。

  1. 更新位于 ~/.sky/config.yamlSkyPilot 配置以使用 ingress 模式。

kubernetes:
  ports: ingress

提示

对于 RKE2 和 K3s,预安装的 Nginx ingress 默认配置不正确。请按照裸金属安装说明正确设置 Nginx ingress controller。

使用此模式时,SkyPilot 会为每个开放的端口创建一个 ingress 资源和一个 ClusterIP 服务。端口可以通过 Ingress URL 加上 /skypilot/{pod_name}/{port} 形式的路径前缀进行外部访问。

使用 sky status --endpoints <cluster> 查看所有端口的完整端点 URL。

$ sky status --endpoints mycluster
8888: http://34.173.152.251/skypilot/test-2ea4/8888

注意

当在子路径(例如 ingress)下暴露端口时,期望根路径访问的服务(例如 Jupyter notebook)可能会遇到问题。要解决此问题,请配置服务以在不同的基本 URL 下运行。对于 Jupyter,启动时使用 –NotebookApp.base_url 标志。或者,考虑使用LoadBalancer模式。