创建服务

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

目录

为什么需要服务

  1. Pod 有自己的 IP,但:

    • Pod 的 IP 不稳定(如果 Pod 被重建,IP 会改变)。

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

  2. 服务通过提供以下功能来解决这个问题:

    • 稳定的 IP 和 DNS 名称。

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

示例 ClusterIP 类型服务:

# 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. 可用的类型值及其行为为 ClusterIPNodePortLoadBalancerExternalName
  2. 服务所针对的 Pod 集合通常由您定义的选择器决定。
  3. Service 端口。
  4. 将服务的 targetPort 绑定到 Pod 的 containerPort。此外,您可以在 Pod 容器下引用 port.name

无头服务

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

spec:
  clusterIP: None

无头服务在以下情况下非常有用:

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

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

  • 您正在使用 StatefulSets,其中每个 Pod 必须具有稳定的 DNS 名称。

通过 Web 控制台创建服务

  1. 转到 Container Platform

  2. 在左侧导航栏中,单击 Network > Services

  3. 单击 Create Service

  4. 根据以下说明配置相关参数。

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

    • Virtualization: 服务将请求转发到 特定 虚拟机或虚拟机组。

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

通过 CLI 创建服务

kubectl apply -f simple-service.yaml

基于现有的部署资源 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
  1. 启动另一个 Pod:
kubectl run test-pod --rm -it --image=busybox -- /bin/sh
  1. test-pod Pod 中访问 nginx-clusterip 服务:
wget -qO- http://nginx-clusterip
# 或使用 Kubernetes 自动创建的 DNS 记录:<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
  1. 检查 Pods:
kubectl get pods -l app=nginx -o wide
  1. curl 服务:
curl http://{NodeIP}:{nodePort}

您应该会看到包含 "Welcome to nginx!" 的 HTML 响应。

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

注意:请提前配置 LoadBalancer 服务。

# 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
  1. 获取外部 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 服务当前未在集群上部署。

示例: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
  1. 尝试在集群中的 Pod 内解析:
kubectl run test-pod --rm -it --image=busybox -- sh

然后:

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

您会看到它解析为 example.com

LoadBalancer 类型服务注释

AWS EKS 集群

有关 EKS LoadBalancer 服务注释的详细说明,请参阅 注释使用文档

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

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

华为云 CCE 集群

有关 CCE LoadBalancer 服务注释的详细说明,请参阅 注释使用文档

描述
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.beta.kubernetes.io/azure-load-balancer-internal
  • true: 私有网络。
  • false: 公共网络。
指定是否使用私有网络或公共网络。

Google GKE 集群

有关 GKE LoadBalancer 服务注释的详细说明,请参阅 注释使用文档

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