六、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        

  

  总结一下:

  1. StatefulSet 不用于Deployment,其Pod name不再是随机生成,且重新创建时Pod name会使用之前的名称
  2. StatefulSet一般和 Headless Service 一起使用,此时集群内可以直接使用Pod的 fqdn地址进行通信,svc域名也直接解析到pod
  3. Loadblance Service 一般用于云环境中,LB地址可以直接转发到绑定的Pod 。

  

posted @ 2021-07-21 17:27  梦君子  阅读(872)  评论(0编辑  收藏  举报