kubernetes services


pod是随时变化的,动态的伸缩,所以应用程序直接连接pod是不可靠的,所以kubernetes引入service,service是为一组功能相同的pod提供统一入口。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
kind: Service
apiVersion: v1
metadata:
name: httpd-deployment
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
selector:
app: http
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: http-app
spec:
selector:
matchLabels:
app: http
replicas: 2
template:
metadata:
labels:
app: http
spec:
containers:
- name: nginx
image: httpd
ports:
- containerPort: 80

上面例子,我们创建一个名为http-app的deployment,然后创建了个Service,selector labels方式将Service与deployment绑定,service类型为 cluster-ip,也就是内部访问类型

在kubernetes集群任意一个节点curl访问

端口类型

port
Service暴露出来的内部访问端口
targetPort
pod暴露出来的端口
NodePort
NodePort是kubernetes提供外部访问service的暴露端口,它暴露在集群所有宿主机上,默认端口范围为30000~32767

服务类型

ClusterIP(默认)
使用clusterip类型的Service默认会使用一个集群内部ip,通过kube-proxy调用iptables创建规则,将流量转发到pod中,需要注意的是clusterip是一个virtual_ip没有真正的网络设备绑定,所以是ping不通它的,直接在集群内部的访问就好。

NodePort
使用NodePort类型的Service时会在集群内部所有host上暴露一个端口用于外部访问

创建方法

1
2
3
4
5
6
7
8
9
10
11
12
kind: Service
apiVersion: v1
metadata:
name: httpd-deployment
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30080
selector:
app: http

不指定nodePort端口将从30000~32767里面随机选一个
LoadBlancer

使用loadblance类型时,会向cloud provider申请映射到service本身的负载均衡,比如AWS的ELB、google cloud 的GCP、Azure的azure-load-balancer。

外部访问pod

NodePort
loadblance
ingress

Service负载均衡

kube-proxy 会检测 API Server 上对于 service 和 endpoint 的新增或者移除。对于每个新的 service,在每个 node 上,kube-proxy 都会设置相应的 iptables 的规则来记录应该转发的地址。当一个 service 被删除的时候,kube-proxy 会在所有的 pod 上移除这些 iptables 的规则。默认转发规则是round robin 或session affinity
kube-proxy 模式:userspace、iptables、ipvs(beta)

当创建一个service后,service会后iptables添加如下规则,以上面创建的httpd-deployment service为例,它的cluster-ip为10.43.129.201

cluster-ip转发流程

在集群任意一台节点上查看iptables规则

1
iptables-save >/tmp/1

1
2
3
4
5
6
-A KUBE-SERVICES -d 10.43.129.201/32 -p tcp -m comment --comment "default/httpd-deployment: cluster IP" -m tcp --dport 80 -j KUBE-SVC-KO6WMUDK3F2YFERC
-A KUBE-SVC-KO6WMUDK3F2YFERC -m comment --comment "default/httpd-deployment:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-37DWITJLRCDPHWZD
-A KUBE-SEP-37DWITJLRCDPHWZD -s 10.42.0.87/32 -m comment --comment "default/httpd-deployment:" -j KUBE-MARK-MASQ
-A KUBE-SEP-37DWITJLRCDPHWZD -p tcp -m comment --comment "default/httpd-deployment:" -m tcp -j DNAT --to-destination 10.42.0.87:80
-A KUBE-SEP-BWU5RQOROOHNX3YY -s 10.42.1.82/32 -m comment --comment "default/httpd-deployment:" -j KUBE-MARK-MASQ
-A KUBE-SEP-BWU5RQOROOHNX3YY -p tcp -m comment --comment "default/httpd-deployment:" -m tcp -j DNAT --to-destination 10.42.1.82:80

第一条规则目的ip是cluster-ip,命中规则,然后将请求丢给KUBE-SVC-KO6WMUDK3F2YFERC处理
第二条规则链KUBE-SVC-KO6WMUDK3F2YFERC 实现了将报文按50%的统计概率随机匹配,转给KUBE-SEP-37DWITJLRCDPHWZD
第三条和第五条是指对pod的SNAT操作
第四条和第六条KUBE-SEP-37DWITJLRCDPHWZD链直接进行DNAT操作将cluster-ip的80端口映射到pod的80

NodePort转发流程

修改Service类型为NodePort

查看iptables

1
2
-A KUBE-NODEPORTS -p tcp -m comment --comment "default/httpd-deployment:" -m tcp --dport 30080 -j KUBE-SVC-KO6WMUDK3F2YFERC
-A KUBE-SERVICES -d 10.43.129.201/32 -p tcp -m comment --comment "default/httpd-deployment: cluster IP" -m tcp --dport 80 -j KUBE-SVC-KO6WMUDK3F2YFERC

第一条规则目的端口味30080的请求转发给KUBE-SVC-KO6WMUDK3F2YFERC处理
第二条规则将请求给cluster-ip10.43.129.201然后转发给KUBE-SVC-KO6WMUDK3F2YFERC
后面就根上面的cluster-ip转发流程是一样的了,所以NodePort就是在cluster-ip转发基础上加了层DNAT到cluster-ip

服务发现

两种方式
环境变量
DNS:1.10版之前是通过kube-dns实现服务发现,1.10版后可以用CoreDns替代kube-dns做服务发现
创建一个Service后,kubernetes会自动将servername做为服务名,添加一条dns记录

比如上面那个例子Service名为httpd-deployment,那么其他pod要访问直接访问httpd-deployment就会解析到对应cluster-ip,跨namespace的只需要在域名后接上.namespace_name 如httpd-deployment.default

http://www.dbsnake.net/how-kubernetes-use-iptables.html