k8s service原理

发布时间 2023-03-28 17:19:06作者: 独揽风月

1. 为什么需要service

Pod是非永久性资源,会动态创建和销毁,pod的ip会变化,而service会动态感知pod的变化,而对调用方无感知,调用方只需要访问固定的service name就可以动态地访问后端的pod。

实现这个功能不单只靠service这个组件,还需要kube-dnsendpointkube-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的作用

  1. 监听service资源的变化,创建dns记录。
  2. 提供域名解析服务:pod通过service名称访问服务时,先从kube-dns里解析到clusterIP,然后通过iptables规则将请请求转发到后端pod。