• k8s控制器:StatefulSet


    k8s控制器:StatefulSet

    一、Statefulset控制器概述

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

    1.1、有状态/无状态服务

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

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

    1.2、Headless service

    1.2.1、什么是Headless service

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

    1.2.2、为什么要用headless 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

    2)StatefulSet会为关联的Pod保持一个不变的Pod Name:$(StatefulSet name)-$(pod序号)

    3)StatefulSet会为关联的Pod分配一个dnsName:$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local

    1.3、volumeClaimTemplate

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

    image-20210711080852884

    二、Statefulset使用案例:部署web站点

    # 创建存储类
    [root@k8s-master1 ~]# cat class-web.yaml 
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: nfs-web
    provisioner: example.com/nfs
    
    # 更新资源清单文件
    [root@k8s-master1 ~]# kubectl apply -f class-web.yaml
    [root@k8s-master1 ~]# kubectl get storageclass
    NAME      PROVISIONER       RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
    nfs-web   example.com/nfs   Delete          Immediate           false                  30s
    
    # 编写一个Statefulset资源清单文件
    [root@k8s-master1 ~]# cat 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
            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"
          resources:
            requests: 
              storage: 1Gi
    
    # 更新资源清单文件
    [root@k8s-master1 ~]# kubectl apply -f statefulset.yaml 
    service/nginx created
    statefulset.apps/web created
    
    # 查看无头服务
    [root@k8s-master1 ~]# kubectl describe svc nginx 
    Name:              nginx
    Namespace:         default
    Labels:            app=nginx
    Annotations:       <none>
    Selector:          app=nginx
    Type:              ClusterIP
    IP Families:       <none>
    IP:                None
    IPs:               None
    Port:              web  80/TCP
    TargetPort:        80/TCP
    Endpoints:         10.244.36.122:80,10.244.36.123:80
    Session Affinity:  None
    Events:            <none>
    
    # 查看statefulset是否创建成功
    [root@k8s-master1 ~]# kubectl get statefulset
    NAME   READY   AGE
    web    2/2     13s 
    
    # 查看pod: 可以看到创建的pod是有序的
    [root@k8s-master1 ~]# kubectl get pods -l app=nginx
    NAME    READY   STATUS    RESTARTS   AGE
    web-0   1/1     Running   0          35s
    web-1   1/1     Running   0          29s
    
    # 查看headless service
    [root@k8s-master1 ~]# kubectl get pods -l app=nginx -o wide
    NAME    READY   STATUS    RESTARTS   AGE     IP              NODE        NOMINATED NODE   READINESS GATES
    web-0   1/1     Running   0          4m22s   10.244.36.122   k8s-node1   <none>           <none>
    web-1   1/1     Running   0          4m16s   10.244.36.123   k8s-node1   <none>           <none>
    
    # 查看pvc
    [root@k8s-master1 ~]# kubectl get pvc
    NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    www-web-0     Bound    pvc-de5c7090-9d53-4597-b292-233f27534764   1Gi        RWO            nfs-web        92s
    www-web-1     Bound    pvc-b3a2c509-f011-448e-9091-afa76726ef40   1Gi        RWO            nfs-web        87s
    
    # 查看pv
    [root@k8s-master1 ~]# kubectl get pv
    NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   REASON   AGE
    pvc-b3a2c509-f011-448e-9091-afa76726ef40   1Gi        RWO            Delete           Bound    default/www-web-1     nfs-web                 2m2s
    pvc-de5c7090-9d53-4597-b292-233f27534764   1Gi        RWO            Delete           Bound    default/www-web-0     nfs-web                 2m8s
                        
    # 查看pod主机名
    [root@k8s-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@k8s-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.36.122  #解析的是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.36.123
    
    Name:	nginx.default.svc.cluster.local
    Address: 10.244.36.122
    
    root@web-1:/# dig -t A nginx.default.svc.cluster.local @10.96.0.10
    ; <<>> DiG 9.11.5-P4-5.1+deb10u5-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: 57675
    ;; 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: 01450c2da9081da1 (echoed)
    ;; QUESTION SECTION:
    ;nginx.default.svc.cluster.local. IN	A
    
    ;; ANSWER SECTION:
    nginx.default.svc.cluster.local. 30 IN	A	10.244.36.123
    nginx.default.svc.cluster.local. 30 IN	A	10.244.36.122
    
    ;; Query time: 1 msec
    ;; SERVER: 10.96.0.10#53(10.96.0.10)
    ;; WHEN: Sun Jul 11 00:34:04 UTC 2021
    ;; MSG SIZE  rcvd: 166
    

    三、Statefulset管理pod

    3.1、实现Pod的扩缩容

    方式一:修改配置文件里的replicas,然后kubectl apply

    方式二:kubectl edit sts web修改replicas

    3.2、实现Pod的版本更新

    方式一:修改配置文件里的image,然后kubectl apply

    方式二:kubectl edit sts web修改image

    作者:Lawrence

    -------------------------------------------

    个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!

    扫描上面二维码关注我
    如果你真心觉得文章写得不错,而且对你有所帮助,那就不妨帮忙“推荐"一下,您的“推荐”和”打赏“将是我最大的写作动力!
    本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.
  • 相关阅读:
    树莓派4 (1)一键配置
    Android编码学习之Fragment
    android编码学习
    自动化中app支持schema跳转
    jenkins持续集成
    测试环境运维文章集锦
    HTML5 data-* 自定义属性
    了解一下JavaScript的未来——ECMAScript5
    ECMAScript5的其它新特性
    ECMAScript5 Array新增方法
  • 原文地址:https://www.cnblogs.com/hujinzhong/p/14995652.html
Copyright © 2020-2023  润新知