配置服务

在 Kubernetes 中,Service 是一种用于暴露集群中作为一个或多个 Pod 运行的网络应用的方法。

为什么需要 Service

  1. Pod 拥有自己的 IP,但:

    • Pod IP 不稳定(Pod 重新创建时会发生变化)。

    • 直接访问 Pod 会变得不可靠。

  2. Service 通过提供以下功能解决了这一问题:

    • 稳定的 IP 和 DNS 名称。

    • 自动将流量负载均衡到匹配的 Pod。

ClusterIP 类型 Service 示例:

# simple-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  1. 可用的类型值及其行为分别为 ClusterIP、NodePort、LoadBalancer、ExternalName
  2. Service 目标 Pod 的集合通常由您定义的 selector 确定。
  3. Service 端口。
  4. 将 Service 的 targetPort 绑定到 Pod 的 containerPort。此外,您可以在 Pod 容器下引用 port.name。

无头服务

有时您不需要负载均衡和单个 Service IP。在这种情况下,您可以创建所谓的无头服务:

spec:
  clusterIP: None

无头服务适用于以下场景:

  • 您希望发现单个 Pod IP,而不仅仅是单个 Service IP。

  • 您需要直接连接到每个 Pod(例如,用于 Cassandra 等数据库或 StatefulSet)。

  • 您使用的是 StatefulSet,其中每个 Pod 都必须具有稳定的 DNS 名称。

使用 Web 控制台创建服务

  1. 转到 容器平台。

  2. 在左侧导航栏中,单击 网络 > 服务。

  3. 单击 创建服务。

  4. 按照以下说明配置相关参数。

    参数描述
    虚拟 IP 地址如果启用,将为此 Service 分配一个 ClusterIP,可用于集群内的服务发现。
    如果禁用,将创建无头服务,通常由 StatefulSet 使用。
    类型
    • ClusterIP:在集群内部 IP 上暴露 Service。选择此值后,Service 只能从集群内部访问。
    • NodePort:在每个节点的 IP 上通过静态端口(NodePort)暴露 Service。
    • ExternalName:将 Service 映射到 externalName 字段的内容(例如,主机名 api.foo.bar.example)。
    • LoadBalancer:使用外部负载均衡器在集群外部暴露 Service。Kubernetes 不直接提供负载均衡组件;您必须自行提供,或者将 Kubernetes 集群与云服务提供商集成。
    目标组件
    • 工作负载:Service 会将请求转发到特定工作负载,该工作负载匹配类似 project.cpaas.io/name: projectname 和 service.cpaas.io/name: deployment-name 的标签。

    • 虚拟化:Service 会将请求转发到特定虚拟机或虚拟机组。

    • 标签选择器:Service 会将请求转发到具有指定标签的特定类型工作负载,例如 environment: release。
    端口用于配置此 Service 的端口映射。在以下示例中,集群内的其他 Pod 可以通过虚拟 IP(如果已启用)和 TCP 端口 80 调用此 Service;访问请求将转发到目标组件 Pod 对外暴露的 TCP 端口 6379 或 redis。
    • 协议:Service 使用的协议,支持的协议包括:TCP、UDP、HTTP、HTTP2、HTTPS、gRPC。
    • 服务端口:Service 在集群内暴露的服务端口号,即 Port,例如 80。
    • 容器端口:服务端口映射到的目标端口号(或名称),即 targetPort,例如 6379 或 redis。
    • 服务端口名称:将自动生成。格式为 <protocol>-<service port>-<container port>,例如:tcp-80-6379 或 tcp-80-redis。
    会话亲和性基于源 IP 地址(ClientIP)的会话亲和性。启用后,在负载均衡期间,来自同一 IP 地址的所有访问请求都将保持在同一服务器上,从而确保来自同一客户端的请求被转发到同一服务器进行处理。
  5. 单击 创建。

使用 CLI 创建服务

kubectl apply -f simple-service.yaml

基于现有的 Deployment 资源 my-app 创建服务。

kubectl expose deployment my-app \
  --port=80 \
  --target-port=8080 \
  --name=test-service \
  --type=NodePort \
  -n p1-1

示例:访问集群内的应用

# access-internal-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-clusterip
spec:
  type: ClusterIP
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
  1. 应用此 YAML:

    kubectl apply -f access-internal-demo.yaml
  2. 启动另一个 Pod:

    kubectl run test-pod --rm -it --image=busybox -- /bin/sh
  3. 在 test-pod Pod 中访问 nginx-clusterip 服务:

    wget -qO- http://nginx-clusterip
    # or using DNS records created automatically by Kubernetes: <service-name>.<namespace>.svc.cluster.local
    wget -qO- http://nginx-clusterip.default.svc.cluster.local

你应会看到包含类似“Welcome to nginx!”文本的 HTML 响应。

示例:访问集群外的应用

# access-external-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-nodeport
spec:
  type: NodePort
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30080
  1. 应用此 YAML:

    kubectl apply -f access-external-demo.yaml
  2. 检查 Pod:

    kubectl get pods -l app=nginx -o wide
  3. 使用 curl 访问 Service:

    curl http://{NodeIP}:{nodePort}

你应会看到包含类似“Welcome to nginx!”文本的 HTML 响应。

当然,也可以通过创建 LoadBalancer 类型的 Service 从集群外部访问应用。

注意:请提前配置 LoadBalancer Service。

# access-external-demo-with-loadbalancer.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-lb-service
spec:
  type: LoadBalancer
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80
  1. 应用此 YAML:

    kubectl apply -f access-external-demo-with-loadbalancer.yaml
  2. 获取外部 IP 地址:

    kubectl get svc nginx-lb-service
    NAME            TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)        AGE
    nginx-service   LoadBalancer   10.0.2.57        34.122.45.100   80:30005/TCP   30s

    EXTERNAL-IP 是你在浏览器中访问的地址。

    curl http://34.122.45.100

你应会看到包含类似“Welcome to nginx!”文本的 HTML 响应。

如果 EXTERNAL-IP 为 pending,则表示 LoadBalancer Service 当前未部署在集群上。

示例:ExternalName 类型的服务

apiVersion: v1
kind: Service
metadata:
  name: my-external-service
  namespace: default
spec:
  type: ExternalName
  externalName: example.com
  1. 应用此 YAML:

    kubectl apply -f external-service.yaml
  2. 尝试在集群中的某个 Pod 内解析:

    kubectl run test-pod --rm -it --image=busybox -- sh

    然后:

    nslookup my-external-service.default.svc.cluster.local

你会看到它解析为 example.com。

LoadBalancer 类型 Service 注解

AWS EKS 集群

有关 EKS LoadBalancer Service 注解的详细说明,请参阅注解使用文档。

KeyValueDescription
service.beta.kubernetes.io/aws-load-balancer-typeexternal:使用官方 AWS LoadBalancer Controller。指定 LoadBalancer 类型使用的控制器。

注意:请提前联系平台管理员部署 AWS LoadBalancer Controller。
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type
  • instance:流量将通过 NodePort 发送到 Pod。
  • ip:流量直接路由到 Pod(集群必须使用 Amazon VPC CNI)。
指定流量到达 Pod 的方式。
service.beta.kubernetes.io/aws-load-balancer-scheme
  • internal:私有网络。
  • internet-facing:公共网络。
指定使用私有网络还是公共网络。
service.beta.kubernetes.io/aws-load-balancer-ip-address-type
  • IPv4
  • dualstack
指定支持的 IP 地址栈。

Huawei Cloud CCE 集群

有关 CCE LoadBalancer Service 注解的详细说明,请参阅注解使用文档。

KeyValueDescription
kubernetes.io/elb.id填写云负载均衡器的 ID,必须使用现有的云负载均衡器。
kubernetes.io/elb.autocreate示例:{"type":"public","bandwidth_name":"cce-bandwidth-1551163379627","bandwidth_chargemode":"bandwidth","bandwidth_size":5,"bandwidth_sharetype":"PER","eip_type":"5_bgp","available_zone":["cn-north-4b"],"l4_flavor_name":"L4_flavor.elb.s1.small"}

注意:请先阅读填写说明,并根据需要调整示例参数。
要创建的新云负载均衡器。
kubernetes.io/elb.subnet-id集群所在子网的 ID。当 Kubernetes 版本为 1.11.7-r0 或更低版本时,创建新的云负载均衡器必须填写此字段。
kubernetes.io/elb.class
  • union:共享型负载均衡。
  • performance:独享型负载均衡,仅支持 Kubernetes 1.17 及更高版本。
指定要创建的新云负载均衡器的类型,请参阅独享型与共享型弹性负载均衡的区别。
kubernetes.io/elb.enterpriseID指定新创建的云负载均衡器所属的企业项目。

Azure AKS 集群

有关 AKS LoadBalancer Service 注解的详细说明,请参阅注解使用文档。

KeyValueDescription
service.beta.kubernetes.io/azure-load-balancer-internal
  • true:私有网络。
  • false:公共网络。
指定使用私有网络还是公共网络。

Google GKE 集群

有关 GKE LoadBalancer Service 注解的详细说明,请参阅注解使用文档。

KeyValueDescription
networking.gke.io/load-balancer-typeInternal指定使用私有网络。
cloud.google.com/l4-rbsenabled默认为公共网络。配置此参数后,流量将直接路由到 Pod。

示例:使用 MetalLB BGP 和本地流量策略的 LoadBalancer

此示例演示如何使用 MetalLB BGP 模式和 externalTrafficPolicy: Local 配置 LoadBalancer Service,从而实现无需额外网络跳转的双活负载均衡。

优势

  • 双活负载均衡:流量可同时分发到多个节点
  • 无额外网络跳转:无需通过中间节点转发即可直接路由到 Pod
  • 更高性能:externalTrafficPolicy: Local 可保留源 IP 并降低延迟
  • 高可用性:BGP 路由通告确保流量能够到达正常运行的节点

前提条件

配置 LoadBalancer Service 前,请确保已完成以下准备:

  1. 已部署 MetalLB:安装方法请参阅创建外部 IP 地址池
  2. 已配置 BGP Peer:BGP 配置方法请参阅创建 BGP Peer
  3. 外部 IP 地址池:配置带有 BGPAdvertisement 的 IPAddressPool

步骤

使用 externalTrafficPolicy: Local 部署带有 LoadBalancer Service 的应用:

# nginx-loadbalancer-local-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.25
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-loadbalancer-local
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80

关键配置点

externalTrafficPolicy: Local

externalTrafficPolicy: Local 设置具有以下优势:

  • 保留源 IP:保留客户端源 IP,从而支持正确的日志记录和安全策略
  • 直接路由到 Pod:流量直接发送到 Pod,无需节点级转发

使用 BGP 的 LoadBalancer

使用 MetalLB BGP 模式时:

  • 路由将从 BGPAdvertisement nodeSelectors 指定的节点进行通告
  • BGP Peer 接收这些通告,并据此路由流量
  • BGPPeer 与 BGPAdvertisement 之间的节点选择器保持一致,可确保路由一致性

部署步骤

  1. 部署应用:

    kubectl apply -f nginx-loadbalancer-local-demo.yaml
  2. 验证 LoadBalancer Service:

    kubectl get svc nginx-loadbalancer-local

    预期输出:

    NAME                     TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
    nginx-loadbalancer-local LoadBalancer   10.0.2.57       4.4.4.3       80:30005/TCP   30s
  3. 测试服务:

    curl http://4.4.4.3

验证

  • 监控服务端点:kubectl get endpoints nginx-loadbalancer-local
  • 检查服务状态:kubectl describe svc nginx-loadbalancer-local

商标声明

NGINX® 是 F5, Inc. 在美国及其他国家/地区的注册商标。

MetalLB™ 是 The Linux Foundation 的商标。

Alauda 是一家独立供应商。本产品与 The Linux Foundation 或 F5, Inc. 无关联,也未获得其认可或赞助。所有商标均归其各自所有者所有,仅用于标识目的。