六、k8s入门系列----StatefulSet、Headless Services、LoadBalancer Services
这节讲下 有状态服务应用 StatefulSet 和另外两种 Service:Headless 和 LoadBalancer 。
应用的状态有如下定义:
-
- 无状态应用(Stateless Application)是指应用不会在会话中保存下次会话所需要的客户端数据。每一个会话都像首次执行一样,不会依赖之前的数据进行响应
- 有状态的应用(Stateful Application)是指应用会在会话中保存客户端的数据,并在客户端下一次的请求中来使用那些数据
有状态应用关键点是可以复用原来的数据,而无状态应用每次都是新的状态。
Deployment 和 StatefulSet 分别应用于无状态服务应用和有状态服务应用,StatefulSet 常见的应用场景:
-
- 稳定的持久化存储,即POD重新调度后还是能访问到相同的持久化数据,基于PVC来实现
- 稳定的网络标识,即POD重新调度后其PodName 和 HostName 不变,基于 Headless Service 来实现
- 有序部署,有序扩展,即 POD 是有顺序的,在部署或者扩展的时候要依据定义的顺序依次进行(即使从0 到 N-1,在下一个Pod 运行之前所有之前的Pod必须都是Running Man和Ready状态),基于init contas来实现
- 有序收缩,有序删除(即从 N-1 到 0)
编写statefulset 资源配置文件,其中serviceName 为必填字段,关联一个Headless Service,其他配置跟deployment大同小异:
[root@ylserver10686071 ~]# cat statefulset.yml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateapp
namespace: prod
spec:
serviceName: stateapp-svc
selector:
matchLabels:
k8s-app: stateapp
replicas: 3
template:
metadata:
labels:
k8s-app: stateapp
spec:
containers:
- name: stateapp
image: tomcat:8.0
ports:
- name: stateapp-8080
containerPort: 8080
protocol: TCP
创建statefulset资源,并查看相关信息,可以看到 Pod 的名称是按照顺序命名的,不是随机生成的:
[root@ylserver10686071 ~]# kubectl apply -f statefulset.yml statefulset.apps/stateapp created [root@ylserver10686071 ~]# kubectl get statefulset -n prod -o wide NAME READY AGE CONTAINERS IMAGES stateapp 3/3 63s stateapp tomcat:8.0 [root@ylserver10686071 ~]# kubectl get pods -n prod -o wide |grep stateapp stateapp-0 1/1 Running 0 60s 10.233.72.43 ylserver10686073 <none> <none> stateapp-1 1/1 Running 0 48s 10.233.67.38 ylserver10686072 <none> <none> stateapp-2 1/1 Running 0 33s 10.233.75.66 ylserver10686071 <none> <none> [root@ylserver10686071 ~]#
Headless Services
创建statefulset的时候会关联一个Headless Service,Headless Service 其实也是一个没有ClusterIP 的 ClusterIP Service,其作用的不创建 ClusterIP 地址,即不创建负载均衡器,域名直接解析到 POD 的 IP 地址。
创建一个 Headless Service 资源配置文件:
[root@ylserver10686071 ~]# cat statefulset-svc.yml apiVersion: v1 kind: Service metadata: name: stateapp-svc namespace: prod spec: type: ClusterIP ports: - port: 8080 name: stateapp-svc targetPort: 8080 clusterIP: None selector: k8s-app: stateapp
创建 Headless Service 资源并查看相关信息,可以看到此时svc的CLUSTER-IP 为空:
[root@ylserver10686071 ~]# kubectl apply -f statefulset-svc.yml service/stateapp-svc created [root@ylserver10686071 ~]# kubectl get svc stateapp-svc -n prod NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE stateapp-svc ClusterIP None <none> 8080/TCP 7s [root@ylserver10686071 ~]# kubectl get endpoints stateapp-svc -n prod NAME ENDPOINTS AGE stateapp-svc 10.233.67.38:8080,10.233.72.43:8080,10.233.75.66:8080 11s [root@ylserver10686071 ~]#
查看下svc name解析情况,解析出来的IP地址为POD地址:
[root@ylserver10686071 ~]# kubectl exec -it mysql-client-858f464d57-64vbk -c tool -n prod -- sh / # nslookup stateapp-svc Server: 169.254.25.10 Address: 169.254.25.10#53 Name: stateapp-svc.prod.svc.cluster.local Address: 10.233.72.43 Name: stateapp-svc.prod.svc.cluster.local Address: 10.233.75.66 Name: stateapp-svc.prod.svc.cluster.local Address: 10.233.67.38
在Headless Service 模式下,可以用POD 的fqdn 进行通信,查看 stateapp-0 的 fqdn地址,地址构成规则为 [podname].[servicename].[namespace].svc.cluster.local:
[root@ylserver10686071 ~]# kubectl exec -it stateapp-0 -n prod -- bash root@stateapp-0:/usr/local/tomcat# hostname -f stateapp-0.stateapp-svc.prod.svc.cluster.local root@stateapp-0:/usr/local/tomcat# cat /etc/hosts # Kubernetes-managed hosts file. 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet fe00::0 ip6-mcastprefix fe00::1 ip6-allnodes fe00::2 ip6-allrouters 10.233.72.43 stateapp-0.stateapp-svc.prod.svc.cluster.local stateapp-0 root@stateapp-0:/usr/local/tomcat#
用 POD 的 fqdn地址解析一下:
[root@ylserver10686071 ~]# kubectl exec -it mysql-client-858f464d57-64vbk -c tool -n prod -- sh / # nslookup stateapp-0.stateapp-svc.prod.svc.cluster.local Server: 169.254.25.10 Address: 169.254.25.10#53 Name: stateapp-0.stateapp-svc.prod.svc.cluster.local Address: 10.233.72.43 / #
在微服务框架Eueeka 中,Headless Service 十分适用。
LoadBalancer Services
如果云厂商提供负载均衡器,可以将service 类型设置为 LoadBlance,云厂商提供的负载均衡器会有单独的域名或者IP地址,如果有多个服务需要暴露80端口给外部使用,就可以申请多个Loadblance,每个都有单独的地址。
这里以阿里云的LoadBlance为例,创建一个 k8dash dashboard 管理工具,阿里云用 annotations 注解中LB的id来绑定指定的LB:
[root@ylserver10686071 k8dash]# cat k8dash.yaml kind: Deployment apiVersion: apps/v1 metadata: name: k8dash namespace: kube-system spec: replicas: 1 selector: matchLabels: k8s-app: k8dash template: metadata: labels: k8s-app: k8dash spec: containers: - name: k8dash image: herbrandson/k8dash:latest ports: - containerPort: 4654 --- kind: Service apiVersion: v1 metadata: annotations: service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: "lb-id" name: k8dash namespace: kube-system spec: externalTrafficPolicy: Cluster ports: - port: 4654 protocol: TCP targetPort: 4654 nodePort: 34654 selector: k8s-app: k8dash type: LoadBalancer
查看 LoadBalancer 资源信息,其中 10.66.66.66 为LB 地址:
[root@ylserver10686071 k8dash]# kubectl get svc -n kube-system|egrep "k8dash|NAME" NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE k8dash LoadBalancer 172.21.10.82 10.66.66.66 4654:34654/TCP 122d [root@ylserver10686071 k8dash]#
查看 kube-ipvs0 虚拟网口,可以看到 配置了 LB 地址:
[root@ylserver10686071 ~]# ip a|grep -2 10.66.66.66 5: kube-ipvs0: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default link/ether 8e:9b:2f:47:7d:aa brd ff:ff:ff:ff:ff:ff inet 10.111.247.62/32 brd 10.66.66.66 scope global kube-ipvs0 valid_lft forever preferred_lft forever inet 172.21.0.10/32 brd 172.21.0.10 scope global kube-ipvs0 [root@iZbp19n36uysraoo1nmjwoZ ~]#
查看POD的IP地址和ipvs 转发规则,可以看到LB 地址直接转发到 POD:
[root@ylserver10686071 ~]# kubectl get pods -n kube-system -o wide|egrep "k8dash|NAME" NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES k8dash-84978cd779-897ds 1/1 Running 0 122d 172.20.5.3 ylserver10686071 <none> <none> [root@ylserver10686071 ~]# ipvsadm -Ln|grep -i1 "10.66.66.66:34654" -> 172.20.0.81:9104 Masq 1 0 10 TCP 10.66.66.66:34654 rr -> 172.20.5.3:4654 Masq 1 2 88
总结一下:
- StatefulSet 不用于Deployment,其Pod name不再是随机生成,且重新创建时Pod name会使用之前的名称
- StatefulSet一般和 Headless Service 一起使用,此时集群内可以直接使用Pod的 fqdn地址进行通信,svc域名也直接解析到pod
- Loadblance Service 一般用于云环境中,LB地址可以直接转发到绑定的Pod 。