在Kubernetes上暴露服务#

注意

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

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

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

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

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

负载均衡器服务#

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

要使用此模式,您必须拥有支持LoadBalancer服务的Kubernetes集群:

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

  • 在裸金属和自管理的Kubernetes集群上,MetalLB 可用于支持LoadBalancer服务。

使用此模式时,SkyPilot 将为您在集群上暴露的所有端口创建一个单一的负载均衡器服务。 每个端口都可以使用负载均衡器的外部IP地址和端口号进行访问。使用 sky status --endpoints 查看所有端口的外部端点。

在基于云的Kubernetes集群中,这将自动创建一个外部负载均衡器。 GKE创建一个直通负载均衡器 而AWS创建一个网络负载均衡器。 当集群被删除时,这些负载均衡器将自动终止。

注意

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

注意

EKS中的默认LoadBalancer实现从打开的端口列表中随机选择一个端口用于LoadBalancer的健康检查。如果所选端口后面没有运行服务,可能会导致问题。

例如,如果一个SkyPilot任务暴露了5个端口,但只有其中2个端口后面有服务在运行,EKS可能会选择一个没有服务运行的端口,而负载均衡器将无法通过健康检查。因此,该服务将不会被分配一个外部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控制器。请参考文档以获取适用于您环境的安装说明。

  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字段是,你可以通过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字段是并且skypilot.co/external-ip注解不存在, SkyPilot将使用localhost作为Ingress的外部IP, 并且该端点可能无法从集群外部访问。

  1. 更新位于 ~/.sky/configSkyPilot 配置 以使用入口模式。

kubernetes:
  ports: ingress

提示

对于RKE2和K3s,预安装的Nginx ingress默认情况下未正确配置。请按照裸金属安装说明正确设置Nginx ingress控制器。

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

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

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

注意

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