本页面介绍 Kubernetes Service 及其在 Google Kubernetes Engine 中的使用。要了解如何创建 Service,请参阅使用 Service 公开应用。
什么是 Service?
Service 的理念是将一组 Pod 端点划分为单一资源。您可以配置各种方式来访问该分组。默认情况下,您会获得稳定的集群 IP 地址,集群内部的客户端可以使用该 IP 地址与 Service 中的 Pod 通信。客户端向稳定 IP 地址发送请求,然后请求会被路由到 Service 的其中一个 Pod。
Service 通过选择器来识别其成员 Pod。为使 Pod 成为 Service 的成员,该 Pod 必须具有选择器中指定的所有标签。 标签是附加到对象的任意键值对。
下列 Service 清单所具有的选择器指定了两种标签。selector
字段指示同时具有 app: metrics
标签和 department:engineering
标签的任何 Pod 都是该 Service 的成员。
apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: metrics department: engineering ports: ...
为何使用 Service?
在 Kubernetes 集群中,每个 Pod 都具有内部 IP 地址。但是,Deployment 中的 Pod 可以随时加入和退出,而且它们的 IP 地址也不是固定的。因此,直接使用 Pod IP 地址毫无意义。通过 Service,您会获得稳定的 IP 地址,该 IP 地址在 Service 的生命周期内有效,即使成员 Pod 的 IP 地址发生变化也仍然有效。
Service 还提供负载平衡。客户端会调用单个稳定的 IP 地址,而且客户端请求在 Service 的成员 Pod 之间保持平衡。
Service 类型
提供五种类型的 Service:
ClusterIP(默认):内部客户端向稳定的内部 IP 地址发送请求。
NodePort:客户端向使用 Service 指定的一个或多个
nodePort
值的节点的 IP 地址发送请求。LoadBalancer:客户端向网络负载平衡器的 IP 地址发送请求。
ExternalName:内部客户端使用 Service 的 DNS 名称作为外部 DNS 名称的别名。
Headless:如果您需要 Pod 分组,但不需要稳定的 IP 地址,则可以使用 Headless 服务。
NodePort
类型是 ClusterIP
类型的扩展。因此,NodePort
类型的 Service 具有集群 IP 地址。
LoadBalancer
类型是 NodePort
类型的扩展。因此,LoadBalancer
类型的 Service 具有集群 IP 地址以及一个或多个 nodePort
值。
ClusterIP 类型的 Service
创建 ClusterIP
类型的 Service 时,Kubernetes 会创建一个稳定的 IP 地址,该 IP 地址可从集群中的节点访问。
以下是 ClusterIP 类型的 Service 的清单:
apiVersion: v1 kind: Service metadata: name: my-cip-service spec: selector: app: metrics department: sales type: ClusterIP ports: - protocol: TCP port: 80 targetPort: 8080
您可以使用 kubectl apply -f [MANIFEST_FILE]
创建 Service。创建服务后,您可以使用 kubectl get service
查看稳定的 IP 地址:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) my-cip-service ClusterIP 10.11.247.213 none 80/TCP
集群中的客户端通过使用集群 IP 地址和 Service 清单的 port
字段中指定的 TCP 端口来调用 Service。请求将转发到 targetPort
字段中指定的 TCP 端口上的其中一个成员 Pod。因此,对于上述示例,客户端在 TCP 端口 80 上调用 10.11.247.213 的 Service。请求将转发到 TCP 端口 8080 上的其中一个成员 Pod。请注意,成员 Pod 必须拥有一个侦听 TCP 端口 8080 的容器。如果没有容器侦听端口 8080,则客户端将看到类似于“连接失败”或“无法访问该网站”的消息。
NodePort 类型的 Service
创建 NodePort
类型的 Service 时,Kubernetes 会为您提供 nodePort
值。然后,您可以使用任何节点的 IP 地址及 nodePort
值来访问 Service。
以下是 NodePort
类型的 Service 的清单:
apiVersion: v1 kind: Service metadata: name: my-np-service spec: selector: app: products department: sales type: NodePort ports: - protocol: TCP port: 80 targetPort: 8080
创建 Service 后,您可以使用 kubectl get service -o yaml
查看其规范并查看 nodePort
值。
spec: clusterIP: 10.11.254.114 externalTrafficPolicy: Cluster ports: - nodePort: 32675 port: 80 protocol: TCP targetPort: 8080
外部客户端使用节点的外部 IP 地址及 nodePort
指定的 TCP 端口来调用 Service。请求将转发到 targetPort
字段指定的 TCP 端口上的其中一个成员 Pod。
例如,假设其中一个集群节点的外部 IP 地址是 203.0.113.2。那么,对于上述示例,外部客户端在 TCP 端口 32675 上调用 203.0.113.2 的 Service。请求将转发到 TCP 端口 8080 上的其中一个成员 Pod。成员 Pod 必须拥有一个侦听 TCP 端口 8080 的容器。
NodePort
Service 类型是 ClusterIP
Service 类型的扩展。因此,内部客户端可通过以下两种方式来调用 Service:
- 使用
clusterIP
和port
。 - 使用节点的内部 IP 地址和
nodePort
。
对于某些集群配置,Google Cloud HTTP(S) 负载平衡器使用 NodePort
类型的 Service。如需了解详情,请参阅使用 Ingress 设置 HTTP 负载平衡。
请注意,HTTP(S) 负载平衡器是代理服务器,与本主题中 LoadBalancer 类型的 Service 下介绍的网络负载平衡器完全不同。
LoadBalancer 类型的 Service
创建 LoadBalancer
类型的 Service 时,Google Cloud 控制器会在您的项目中唤醒并配置网络负载平衡器。负载平衡器具有稳定的 IP 地址,您可以从项目外部访问该 IP 地址。
请注意,网络负载平衡器不是代理服务器。它会转发数据包,但不更改来源和目标 IP 地址。
以下是 LoadBalancer
类型的 Service 的清单:
apiVersion: v1 kind: Service metadata: name: my-nlb-service spec: selector: app: metrics department: engineering type: LoadBalancer ports: - port: 80 targetPort: 8080
创建 Service 后,您可以使用 kubectl get service -o yaml
查看其规范并查看稳定的外部 IP 地址:
spec: clusterIP: 10.11.242.115 externalTrafficPolicy: Cluster ports: - nodePort: 32676 port: 80 protocol: TCP targetPort: 8080 selector: app: metrics department: engineering sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 203.0.113.100
在输出中,网络负载平衡器的 IP 地址显示在 loadBalancer:ingress:
下方。外部客户端使用负载平衡器的 IP 地址和 port
指定的 TCP 端口来调用 Service。请求将转发到 targetPort
指定的 TCP 端口上的其中一个成员 Pod。因此,对于上述示例,客户端在 TCP 端口 80 上调用 203.0.113.100 的 Service。 请求将转发到 TCP 端口 8080 上的其中一个成员 Pod。
成员 Pod 必须拥有一个侦听 TCP 端口 8080 的容器。
LoadBalancer Service 类型是 NodePort 类型的扩展,而 NodePort 类型是 ClusterIP 类型的扩展。
ExternalName 类型的 Service
ExternalName
类型的 Service 为外部 DNS 名称提供内部别名。内部客户端使用内部 DNS 名称发出请求,然后请求会被重定向到外部名称。
以下是 ExternalName
类型的 Service 的清单:
apiVersion: v1 kind: Service metadata: name: my-xn-service spec: type: ExternalName externalName: example.com
创建 Service 时,Kubernetes 会创建一个 DNS 名称,内部客户端可以使用该名称来调用 Service。对于上述示例,DNS 名称是 my-xn-service.default.svc.cluster.local。当内部客户端向 my-xn-service.default.svc.cluster.local 发出请求时,请求会被重定向到 example.com。
ExternalName
Service 类型与其他 Service 类型完全不同。事实上,ExternalName
类型的 Service 不符合本主题开头提出的 Service 定义。ExternalName
类型的 Service 不与一组 Pod 相关联,也没有稳定的 IP 地址。相反,ExternalName
类型的 Service 从内部 DNS 名称映射到外部 DNS 名称。
Service 抽象
Service 是一个抽象概念,因为它不是侦听某个网络接口的进程。部分抽象在集群节点的 iptables 规则中实现。根据 Service 类型,抽象的其他部分通过网络负载平衡或 HTTP(S) 负载平衡实现。
任意 Service 端口
Service 清单中 port
字段的值是任意的。但是,targetPort
的值不是任意值。每个成员 Pod 必须拥有一个侦听 targetPort
的容器。
以下是 port
值为 50000 的 LoadBalancer
类型的 Service:
apiVersion: v1 kind: Service metadata: name: my-ap-service spec: clusterIP: 10.11.241.93 externalTrafficPolicy: Cluster ports: - nodePort: 30641 port: 50000 protocol: TCP targetPort: 8080 selector: app: parts department: engineering sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 203.0.113.200
客户端在 TCP 端口 50000 上调用 203.0.113.200 的 Service。请求将转发到 TCP 端口 8080 上的其中一个成员 Pod。
多个端口
Service 的 ports
字段是一组 ServicePort 对象。ServicePort 对象具有以下字段:
name
protocol
port
targetPort
nodePort
如果您具有多个 ServicePort,则每个 ServicePort 必须具有唯一的名称。
以下是具有两个 ServicePort
对象的 LoadBalancer
类型的 Service:
apiVersion: v1 kind: Service metadata: name: my-tp-service spec: clusterIP: 10.11.242.196 externalTrafficPolicy: Cluster ports: - name: my-first-service-port nodePort: 31233 port: 60000 protocol: TCP targetPort: 50000 - name: my-second-service-port nodePort: 31081 port: 60001 protocol: TCP targetPort: 8080 selector: app: tests department: engineering sessionAffinity: None type: LoadBalancer status: loadBalancer: ingress: - ip: 203.0.113.201
在上述示例中,如果客户端在 TCP 端口 60000 上调用 203.0.113.201 的 Service,则请求将转发到 TCP 端口 50000 上的成员 Pod。但是,如果客户端在 TCP 端口 60001 上调用 203.0.113.201 的 Service,则请求将转发到 TCP 端口 8080 上的成员 Pod。
每个成员 Pod 必须拥有一个侦听 TCP 端口 50000 的容器和一个侦听 TCP 端口 8080 的容器。这可以是具有两个线程的单个容器,也可以是在同一 Pod 中运行的两个容器。
Service 端点
创建 Service 时,Kubernetes 会创建一个与 Service 同名的 Endpoints 对象。Kubernetes 使用 Endpoints 对象来跟踪哪些 Pod 是 Service 的成员。