k8s service原理
1. 为什么需要service
Pod是非永久性资源,会动态创建和销毁,pod的ip会变化,而service会动态感知pod的变化,而对调用方无感知,调用方只需要访问固定的service name就可以动态地访问后端的pod。
实现这个功能不单只靠service
这个组件,还需要kube-dns
、endpoint
、kube-proxy
的配合。
2. 创建service
为了方便理解,这里创建一个没有selector选择器的service:
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
#clusterIP: "10.96.96.111"
type: NodePort
ports:
- protocol: TCP
port: 8000 #设定Serivce对外提供服务的端口,当service类型为headless时,不需要该配置
targetPort: 80 #设定容器(Pod)的端口,即Pod网络的端口。
nodePort: 32111 #它仅在type为NodePort时才需要指定.
创建完后观察service的事件变化,发现只有一个add事件,配置如下:
{
"metadata": {
"name": "my-service",
"namespace": "default",
"uid": "8529449e-57b0-4f19-9c7c-eebc1930c3cf",
"resourceVersion": "1074994",
"creationTimestamp": "2023-03-28T07:33:01Z",
"managedFields": [{
"manager": "kubectl",
"operation": "Update",
"apiVersion": "v1",
"time": "2023-03-28T07:33:01Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:spec": {
# ...
}
}
}]
},
"spec": {
"ports": [{
"protocol": "TCP",
"port": 8000,
"targetPort": 80,
"nodePort": 32111
}],
"clusterIP": "10.96.145.44",
"clusterIPs": ["10.96.145.44"],
"type": "NodePort",
"sessionAffinity": "None",
"externalTrafficPolicy": "Cluster",
"ipFamilies": ["IPv4"],
"ipFamilyPolicy": "SingleStack"
},
"status": {
"loadBalancer": {}
}
}
可以看到k8s立刻会为service分配一个ClusterIP,看看iptables里的记录:
iptables -t nat -L KUBE-SERVICES |egrep 'my-service'
此时是没有相关记录的。
3. 创建endpoint
一定要创建一个和service同名的endpoint:
apiVersion: v1
kind: Endpoints
metadata:
name: my-service
subsets:
- addresses:
- ip: 10.244.0.13
ports:
- port: 80
这里我们为endpoint绑定了一个podIP:10.244.0.13,再观察iptables记录:
root@local-dev-control-plane:/# iptables -t nat -L KUBE-SERVICES |egrep 'my-service'
KUBE-MARK-MASQ tcp -- !10.244.0.0/16 10.96.145.44 /* default/my-service cluster IP */ tcp dpt:8000
KUBE-SVC-FXIYY6OHUSNBITIX tcp -- anywhere 10.96.145.44 /* default/my-service cluster IP */ tcp dpt:8000
root@local-dev-control-plane:/# iptables -t nat -L KUBE-SVC-FXIYY6OHUSNBITIX
Chain KUBE-SVC-FXIYY6OHUSNBITIX (2 references)
target prot opt source destination
KUBE-SEP-6PNXU34HIRWIZKTJ all -- anywhere anywhere /* default/my-service */
root@local-dev-control-plane:/# iptables -t nat -L KUBE-SEP-6PNXU34HIRWIZKTJ
Chain KUBE-SEP-6PNXU34HIRWIZKTJ (1 references)
target prot opt source destination
KUBE-MARK-MASQ all -- 10.244.0.13 anywhere /* default/my-service */
DNAT tcp -- anywhere anywhere /* default/my-service */ tcp to:10.244.0.13:80
可以看到已经创建了相关的转发规则。
endpoint控制器
endpoint控制器会监听service资源的变化,来创建或更新endpoint资源。
如果我们创建一个带selector选择器的service,endpoint控制器就会创建一个同名的endpoint资源。
4. kube-proxy的作用
kube-proxy会同时监听service和endpoint的资源变化,来创建或更新iptables规则。这里就解释了为什么service和endpoint资源一定要同名,service里有clusterIP信息,endpoint里有podIP信息,kube-proxy根据两者的信息来创建iptables规则。
5. kube-dns的作用
- 监听service资源的变化,创建dns记录。
- 提供域名解析服务:pod通过service名称访问服务时,先从kube-dns里解析到clusterIP,然后通过iptables规则将请请求转发到后端pod。