• 11.Statefulset控制器


    StatefulSet是为了管理有状态服务的问题而设计的

    • 有状态服务
      StatefulSet是有状态的集合,管理有状态的服务,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。比如MySQL主从、redis集群等。

    • 无状态服务
      RC、Deployment、DaemonSet都是管理无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的。个体对整体无影响,所有pod都是共用一个数据卷的,部署的tomcat就是无状态的服务,tomcat被删除,在启动一个新的tomcat,加入到集群即可,跟tomcat的名字无关。

    • 组成部份

      • Headless Service:用来定义pod网路标识,生成可解析的DNS记录
      • volumeClaimTemplates:存储卷申请模板,创建pvc,指定pvc名称大小,自动创建pvc,且pvc由存储类供应。
      • StatefulSet:管理pod的

    扩展:什么是Headless service?
    Headless service不分配clusterIP,headless service可以通过解析service的DNS,返回所有Pod的dns和ip地址 (statefulSet部署的Pod才有DNS),普通的service,只能通过解析service的DNS返回service的ClusterIP。

    为什么要用headless service(没有service ip的service)?
    在使用Deployment时,创建的Pod名称是没有顺序的,是随机字符串,在用statefulset管理pod时要求pod名称必须是有序的 ,每一个pod不能被随意取代,pod重建后pod名称还是一样的。因为pod IP是变化的,所以要用Pod名称来识别。pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称。

    1. headless service会为service分配一个域名
    <service name>.$<namespace name>.svc.cluster.local
    

    K8s中资源的全局FQDN格式:

    Service_NAME.NameSpace_NAME.Domain.LTD.
    Domain.LTD.=svc.cluster.local.     #这是默认k8s集群的域名。
    

    FQDN 全称 Fully Qualified Domain Name 即全限定域名:同时带有主机名和域名的名称
    FQDN = Hostname + DomainName
    如 主机名是
    域名是 baidu.com
    FQDN= .baidu.com

    1. StatefulSet会为关联的Pod保持一个不变的Pod Name
    statefulset中Pod的名字格式为$(StatefulSet name)-$(pod序号)
    
    1. StatefulSet会为关联的Pod分配一个dnsName
    $<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
    

    为什么要用volumeClaimTemplate?
    对于有状态应用都会用到持久化存储,比如mysql主从,由于主从数据库的数据是不能存放在一个目录下的,每个mysql节点都需要有自己独立的存储空间。而在deployment中创建的存储卷是一个共享的存储卷,多个pod使用同一个存储卷,它们数据是同步的,而statefulset定义中的每一个pod都不能使用同一个存储卷,这就需要使用volumeClainTemplate,当在使用statefulset创建pod时,volumeClainTemplate会自动生成一个PVC,从而请求绑定一个PV,每一个pod都有自己专用的存储卷。Pod、PVC和PV对应的关系图如下:
    image

    Statefulset资源清单

    [root@master1 ~]# kubectl explain statefulset
    KIND:     StatefulSet
    VERSION:  apps/v1
    DESCRIPTION:
         StatefulSet represents a set of pods with consistent identities. Identities
         are defined as:
         - Network: A single stable DNS and hostname.
         - Storage: As many VolumeClaims as requested. The StatefulSet guarantees
         that a given network identity will always map to the same storage identity.
    FIELDS:
       apiVersion	<string> #定义statefulset资源需要使用的api版本
       kind	<string>          #定义的资源类型
       metadata	<Object>     #元数据
       spec	<Object>          #定义容器相关的信息
    

    查看statefulset.spec字段如何定义?

    [root@master1 ~]# kubectl explain statefulset.spec
    KIND:     StatefulSet
    VERSION:  apps/v1
    RESOURCE: spec <Object>
    DESCRIPTION:
         Spec defines the desired identities of pods in this set.
         A StatefulSetSpec is the specification of a StatefulSet.
    FIELDS:
       podManagementPolicy	<string> #pod管理策略
       replicas	<integer>  #副本数
       revisionHistoryLimit	<integer> #保留的历史版本
       selector	<Object> -required- #标签选择器,选择它所关联的pod
       serviceName	<string> -required-  #headless service的名字
       template	<Object> -required-     #生成pod的模板
       updateStrategy	<Object>   #更新策略
       volumeClaimTemplates	<[]Object> #存储卷申请模板
    

    查看statefulset的spec.template字段如何定义?
    对于template而言,其内部定义的就是pod,pod模板是一个独立的对象

    [root@master1 ~]# kubectl explain statefulset.spec.template
    KIND:     StatefulSet
    VERSION:  apps/v1
    RESOURCE: template <Object>
    DESCRIPTION:
         template is the object that describes the pod that will be created if
         insufficient replicas are detected. Each pod stamped out by the StatefulSet
         will fulfill this Template, but have a unique identity from the rest of the
         StatefulSet.
         PodTemplateSpec describes the data a pod should have when created from a
         template
    FIELDS:
       metadata	<Object>
       spec	<Object>  #定义容器属性的
    

    通过上面可以看到,statefulset资源中有两个spec字段。第一个spec声明的是statefulset定义多少个Pod副本(默认将仅部署1个Pod)、匹配Pod标签的选择器、创建pod的模板、存储卷申请模板,第二个spec是spec.template.spec:主要用于Pod里的容器属性等配置。
    .spec.template里的内容是声明Pod对象时要定义的各种属性,所以这部分也叫做PodTemplate(Pod模板)。还有一个值得注意的地方是:在.spec.selector中定义的标签选择器必须能够匹配到spec.template.metadata.labels里定义的Pod标签,否则Kubernetes将不允许创建statefulset。

    Statefulset使用案例:部署web站点

    创建存储类

    [root@master1 ~]# cat class-web.yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: nfs-web
    provisioner: example.com/nfs
    

    更新资源清单文件

    [root@master1 ~]# kubectl apply -f class-web.yaml
    

    编写一个Statefulset资源清单文件 statefulset.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: nginx
      labels:
         app: nginx
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: nginx
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx
      serviceName: "nginx"
      replicas: 2
      template:
        metadata:
         labels:
           app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
      - metadata:
          name: www
        spec:
          accessModes: ["ReadWriteOnce"]
          storageClassName: "nfs-web"
          resources:
            requests:
              storage: 1Gi
    

    更新资源清单文件

    [root@master1 ~]# kubectl apply -f statefulset.yaml 
    service/nginx created
    statefulset.apps/web created
    

    查看statefulset是否创建成功

    [root@master1 ~]# kubectl get statefulset
    NAME   READY   AGE
    web      2/2      42s
    

    查看pod

    [root@master1 ~]# kubectl get pods -l app=nginx
    NAME    READY   STATUS    RESTARTS   AGE
    web-0   1/1     Running   0          2m17s
    web-1   1/1     Running   0          115s
    

    通过上面可以看到创建的pod是有序的
    查看headless service

    [root@master1 ~]# kubectl get svc -l app=nginx
    NAME    TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    nginx    ClusterIP      None         <none>        80/TCP    3m19s
    

    查看pvc

    [root@master1 ~]# kubectl get pvc
    [root@master1 statefulset]# kubectl get pvc
    NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    www-web-0     Bound    pvc-39a9755f-3248-49ff-8f9e-5b068b609c8f   1Gi        RWO,RWX        nfs-web        7m45s
    www-web-1     Bound    pvc-be93d4a3-1aca-44cc-802f-ddeb38c05018   1Gi        RWO,RWX        nfs-web        7m41s
    

    查看pv

    [root@master1 ~]# kubectl get pv
    [root@master1 statefulset]# kubectl get pv
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                 STORAGECLASS   REASON   AGE
    pvc-39a9755f-3248-49ff-8f9e-5b068b609c8f   1Gi        RWO,RWX        Delete           Bound       default/www-web-0     nfs-web                 8m3s
    pvc-be93d4a3-1aca-44cc-802f-ddeb38c05018   1Gi        RWO,RWX        Delete           Bound       default/www-web-1     nfs-web                 7m59s
    

    查看pod主机名

    [root@master1 ~]# for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname';done 
    web-0
    web-1
    

    使用kubectl run运行一个提供nslookup命令的容器的,这个命令来自于dnsutils包,通过对pod主机名执行nslookup,可以检查它们在集群内部的DNS地址:

    [root@master1 ~]# kubectl exec -it web-1 -- /bin/bash
    root@web-1:/# apt-get update
    root@web-1:/# apt-get install dnsutils -y
    
    root@web-1:/# nslookup web-0.nginx.default.svc.cluster.local  
    Server:		10.96.0.10
    Address:	10.96.0.10#53
    Name:	web-0.nginx.default.svc.cluster.local 
    
    #statefulset创建的pod也是有dns记录的
    Address: 10.244.209.154  #解析的是pod的ip地址
    
    root@web-1:/# nslookup nginx.default.svc.cluster.local
    Server:		10.96.0.10
    Address:	10.96.0.10#53
    
    Name:	nginx.default.svc.cluster.local  #查询service dns,会把对应的pod ip解析出来
    Address: 10.244.209.139
    
    Name:	nginx.default.svc.cluster.local
    Address: 10.244.209.140
    
    root@web-1:/# dig -t A nginx.default.svc.cluster.local @10.96.0.10
    ; <<>> DiG 9.11.5-P4-5.1+deb10u3-Debian <<>> -t A nginx.default.svc.cluster.local @10.96.0.10
    ;; global options: +cmd
    ;; Got answer:
    ;; WARNING: .local is reserved for Multicast DNS
    ;; You are currently testing what happens when an mDNS query is leaked to DNS
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 27207
    ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1
    ;; WARNING: recursion requested but not available
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 4096
    ; COOKIE: f2f17492cf38ad44 (echoed)
    ;; QUESTION SECTION:
    ;nginx.default.svc.cluster.local. IN	A
    
    ;; ANSWER SECTION:
    nginx.default.svc.cluster.local. 30 IN	A	10.244.209.139
    nginx.default.svc.cluster.local. 30 IN	A	10.244.209.140
    
    ;; Query time: 0 msec
    ;; SERVER: 10.96.0.10#53(10.96.0.10)
    ;; WHEN: Fri Apr 09 15:10:40 UTC 2021
    ;; MSG SIZE  rcvd: 166
    

    dig的使用

    dig -t A nginx.default.svc.cluster.local @10.96.0.10
    格式如下:  
    @来指定域名服务器 
    A 为解析类型 ,A记录
    -t 指定要解析的类型 
    
    A记录:
      A记录是解析域名到IP
    

    资源清单详细解读:

    apiVersion: v1  #定义api版本
    kind: Service   #定义要创建的资源:service
    metadata: 
      name: nginx   #定义service的名字
      labels:
         app: nginx  #service的标签
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None  #创建一个没有ip的service
      selector:
        app: nginx     #选择拥有app=nginx标签的pod
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata: 
      name: web
    spec:
      selector:
        matchLabels:
          app: nginx
      serviceName: "nginx"  #headless service的名字
      replicas: 2              #副本数
      template:              #定义pod的模板
        metadata: 
         labels:
           app: nginx
        spec: 
          containers:
          - name: nginx
            image: nginx
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: www
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:     #存储卷申请模板
      - metadata:
          name: www
        spec:
          accessModes: ["ReadWriteOnce"]
    storageClassName: "nfs-web"  #指定从哪个存储类申请pv
          resources:
            requests: 
              storage: 1Gi   #需要1G的pvc,会自动跟符合条件的pv绑定 
    

    扩展:
    举例说明service 和headless service区别:
    1、通过deployment创建pod,pod前端创建一个service
    deploy-service.yaml

    apiVersion: v1
    kind: Service
    metadata:
      name: my-nginx
      labels:
        run: my-nginx
    spec:
      type: ClusterIP
      ports:
      - port: 80   #service的端口,暴露给k8s集群内部服务访问
        protocol: TCP
        targetPort: 80    #pod容器中定义的端口
      selector:
        run: my-nginx  #选择拥有run=my-nginx标签的pod
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-nginx
    spec:
      selector:
        matchLabels:
          run: my-nginx
      replicas: 2
      template:
        metadata:
          labels:
            run: my-nginx
        spec:
          containers:
          - name: my-nginx
            image: busybox
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 80
            command:
              - sleep
              - "3600"
    

    更新资源清单文件

    [root@master1 ~]# kubectl apply -f deploy-service.yaml
    

    查看service

    [root@master1 ~]# kubectl get svc -l run=my-nginx
    NAME       TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)
    my-nginx   ClusterIP     10.100.89.90   <none>        80/TCP
    

    查看pod

    [root@master1 ~]# kubectl get pods -l run=my-nginx
    NAME                        READY   STATUS    RESTARTS   AGE
    my-nginx-58f74fc5b6-jzbvk   1/1     Running   0          70s
    my-nginx-58f74fc5b6-n9lqv   1/1     Running   0          53s  
    

    通过上面可以看到deployment创建的pod是随机生成的
    进入到web-1的pod

    [root@master1 ~]# kubectl exec -it web-1 -- /bin/bash
    root@web-1:/# nslookup my-nginx.default.svc.cluster.local
    Server:		10.96.0.10
    Address:	10.96.0.10#53
    
    Name:	my-nginx.default.svc.cluster.local
    Address: 10.100.89.90   #解析的是service的ip地址
    

    Statefulset管理pod:扩容、缩容、更新

    Statefulset实现pod的动态扩容,如果我们觉得两个副本太少了,想要增加,只需要修改配置文件statefulset.yaml里的replicas的值即可,原来replicas: 2,现在变成replicaset: 3,修改之后,执行如下命令更新:

    [root@master1 ~]# kubectl apply -f statefulset.yaml 
    service/nginx unchanged
    statefulset.apps/web configured
    [root@master1 ~]# kubectl get sts
    NAME   READY   AGE
    web    3/3     60m
          [root@master1 ~]# kubectl get pods -l app=nginx
    NAME    READY   STATUS    RESTARTS   AGE
    web-0   1/1     Running   0          61m
    web-1   1/1     Running   0          60m
    web-2   1/1     Running   0          79s
    

    也可以直接编辑控制器实现扩容

    [root@master1 ~]# kubectl edit sts web
    #这个是我们把请求提交给了apiserver,实时修改
    

    image
    把上面的spec下的replicas 后面的值改成4,保存退出

    [root@master1 ~]#  kubectl get pods -l app=nginx
    NAME    READY   STATUS    RESTARTS   AGE
    web-0   1/1     Running   0          62m
    web-1   1/1     Running   0          62m
    web-2   1/1     Running   0          3m13s
    web-3   1/1     Running   0          26s
    

    Statefulset实现pod的动态缩容, 如果我们觉得4个Pod副本太多了,想要减少,只需要修改配置文件statefulset.yaml里的replicas的值即可,把replicaset:4变成replicas: 2,修改之后,执行如下命令更新:

    [root@master1 ~]# kubectl apply -f statefulset.yaml
    service/nginx unchanged
    statefulset.apps/web configured
    [root@master1 ~]#  kubectl get pods -l app=nginx
    NAME    READY   STATUS    RESTARTS   AGE
    web-0   1/1     Running   0          64m
    web-1   1/1     Running   0          64m
    

    Statefulset实现pod的更新

    [root@master1 ~]# kubectl edit sts web
    #修改镜像nginx变成- image: ikubernetes/myapp:v2,修改之后保存退出  
    [root@master1 ~]# kubectl get pods -o wide -l app=nginx
    NAME    READY   STATUS    RESTARTS   AGE   IP               NODE       NOMINATED NODE   READINESS GATES
    web-0   1/1     Running   0          18s   10.244.209.156   node1   
    web-1   1/1     Running   0          36s   10.244.187.115   node2
    #查看pod详细信息
    [root@master1 ~]# kubectl describe pods web-0
    

    image
    通过上面可以看到pod已经使用刚才更新的镜像ikubernetes/myapp:v2了

  • 相关阅读:
    Seven Puzzle Aizu
    Cheese
    Curling 2.0
    Ball
    Property Distribution
    Red and Black
    Lake Counting
    Ants
    剑桥雅思写作高分范文ESSAY20
    剑桥雅思写作高分范文ESSAY19
  • 原文地址:https://www.cnblogs.com/forlive/p/15976045.html
Copyright © 2020-2023  润新知