Service 概述
Service 被抽象为一组或多组 Pod 的静态 IP 地址 (也可以将 Service 看作是一个代理),任何到达 Service 的请求都会被转发到属于该服务背后的某个 Pod 中的应用。
与 Service 紧密关联的两个概念是 Pod 和 EndPoint, 其中,Pod 是 Kubernetes 中应用运行的最小单位,而 EndPoint 是 Service 指向的实际地址,定义了 Service 所指向的具体 Pod 的 IP 地址和端口。
- 创建一个 Service 时,Kubernetes 会自动创建关联的 EndPoint
- EndPoint 中包含了 Service 对应的所有 Pod 的 IP 地址和端口
- 当有 Pod 加入 Service 或者从 Service 的中删除时 (通过标签选择器),Kubernetes 会自动更新 EndPoint 相关信息
三者的关系如下图所示::
上面的图中定义了 2 个 Service, 每个 Service 有 1 个 EndPoint, 每个 EndPoint 包含 3 个 Pod 的网络位置。
查看 Service 代理的 Pod
可以通过 kubectl describe
命令查看 Service 代理了哪些后端 Pod:
$ kubectl describe svc svc-name
Name: api-demo-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=api-demo
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: None
IPs: None
Port: api-demo-svc 8080/TCP
TargetPort: 8080/TCP
# 代理的 Pod IP 地址列表
Endpoints: 172.24.102.212:8080,172.24.102.59:8080,172.24.102.23:8080 + 2 more...
Session Affinity: None
Events: <none>
通过输出结果中的 Endpoints
字段,可以看到 Service 代理的后端 Pod IP 地址列表。
Service 示例
例如,假定有一组 Pod,每个 Pod 都在侦听 TCP 端口 9376,并且它们还被打上 app.kubernetes.io/name=MyApp
标签。你可以定义一个 Service 来发布该 TCP listener。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app.kubernetes.io/name: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
应用上述清单时,系统将创建一个名为 “my-service” 的、 类型默认为 ClusterIP 的 Service。 该 Service 指向带有标签 app.kubernetes.io/name: MyApp
的所有 Pod 的 TCP 端口 9376。
没有选择算符的 Service
由于选择算符的存在,Service 的最常见用法是为 Kubernetes Pod 集合提供访问抽象, 但是当与相应的 EndpointSlice 对象一起使用且没有设置选择算符时,Service 也可以为其他类型的后端提供抽象, 包括在集群外运行的后端。
例如:
- 你希望在生产环境中使用外部数据库集群,但在测试环境中使用自己的数据库。
- 你希望让你的 Service 指向另一个名字空间(Namespace)中或其它集群中的服务。
- 你正在将工作负载迁移到 Kubernetes 上来。在评估所采用的方法时,你仅在 Kubernetes 中运行一部分后端。
在所有这些场景中,你都可以定义不指定用来匹配 Pod 的选择算符的 Service。例如:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
由于此 Service 没有选择算符,因此不会自动创建对应的 EndpointSlice(和旧版的 Endpoints)对象。 你可以通过手动添加 EndpointSlice 对象,将 Service 映射到该服务运行位置的网络地址和端口:
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: my-service-1 # 按惯例将 Service 的名称用作 EndpointSlice 名称的前缀
labels:
# 你应设置 "kubernetes.io/service-name" 标签。
# 设置其值以匹配 Service 的名称
kubernetes.io/service-name: my-service
addressType: IPv4
ports:
- name: '' # 应与上面定义的 Service 端口的名称匹配
appProtocol: http
protocol: TCP
port: 9376
endpoints: # 此列表中的 IP 地址可以按任何顺序显示
- addresses:
- "10.4.5.6"
- addresses:
- "10.1.2.3"
Service 类型
ClusterIP
通过集群的内部 IP 公开 Service,选择该值时 Service 只能够在集群内部访问。 这也是你没有为 Service 显式指定 type
时使用的默认值。 你可以使用 Ingress 或者 Gateway API 向公共互联网公开服务。
NodePort
通过每个节点上的 IP 和静态端口(NodePort
)公开 Service。 为了让 Service 可通过节点端口访问,Kubernetes 会为 Service 配置集群 IP 地址, 相当于你请求了 type: ClusterIP
的 Service。
LoadBalancer
使用云平台的负载均衡器向外部公开 Service。Kubernetes 不直接提供负载均衡组件; 你必须提供一个,或者将你的 Kubernetes 集群与某个云平台集成。
ExternlName
将服务映射到 externalName
字段的内容(例如,映射到主机名 api.foo.bar.example
)。 该映射将集群的 DNS 服务器配置为返回具有该外部主机名值的 CNAME
记录。 集群不会为之创建任何类型代理。
想要原文可以加作者v:mkjnnm