zoukankan      html  css  js  c++  java
  • 12 . Kubernetes之Statefulset 和 Operator

    Statefulset简介

    k8s权威指南这样介绍的

    “在Kubernetes系统中,Pod的管理对象RC、Deployment、DaemonSet和Job都面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如MySQL集群、MongoDB集群、Akka集群、ZooKeeper集群等,这些应用集群有4个共同点。"

    (1)每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现并通信。
    (2)集群的规模是比较固定的,集群规模不能随意变动。
    (3)集群中的每个节点都是有状态的,通常会持久化数据到永久存储中。
    (4)如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。

    如果通过RC或Deployment控制Pod副本数量来实现上述有状态的集群,就会发现第1点是无法满足的,因为Pod的名称是随机产生的,Pod的IP地址也是在运行期才确定且可能有变动的,我们事先无法为每个Pod都确定唯一不变的ID。另外,为了能够在其他节点上恢复某个失败的节点,这种集群中的Pod需要挂接某种共享存储,为了解决这个问题,Kubernetes从1.4版本开始引入了PetSet这个新的资源对象,并且在1.5版本时更名为StatefulSet,StatefulSet从本质上来说,可以看作Deployment[…]”

    “StatefulSet除了要与PV卷捆绑使用以存储Pod的状态数据,还要与Headless Service配合使用,即在每个StatefulSet定义中都要声明它属于哪个Headless Service。Headless Service与普通Service的关键区别在于,它没有Cluster IP,如果解析Headless Service的DNS域名,则返回的是该Service对应的全部Pod的Endpoint列表。StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod实例都创建了一个DNS域名,这个域名的格式为:

    $(podname).(headless server name)   
    FQDN: $(podname).(headless server name).namespace.svc.cluster.local
    

    比如一个3节点的Kafka的StatefulSet集群对应的Headless Service的名称为kafka,StatefulSet的名称为kafka,则StatefulSet里的3个Pod的DNS名称分别为kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些DNS名称可以直接在集群的配置文件中固定下来。”

    StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
    在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。

    应用场景

    StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括

    • 1、稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
    • 2、稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现
    • 3、有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现有序收缩,有序删除(即从N-1到0)
    特点
    # 1. 稳定且唯一的网络标识符
    # 2. 稳定且持久的存储.
    # 3. 有序、平滑地部署和扩展.
    # 4. 有序、平滑的删除和终止.
    # 5. 有序的滚动更新
    
    三个组件
    # headless service(无头服务)
    # statefuleset
    # volumeClaimTemplate(存储卷申请模板)
    

    Operator

    Kubernetes operator是把专家平常的经验,流程,比如写在wiki里面的诀窍,使用Operator来固化。这些经验就会集成在Operator软件里面。

    换句话说,这个叫做Best practices. 也是软件工程里面把logic封装起来的一个例子。It’s a fancy script.

    比如failover,用软件来建立模型。使用K8S的原语,比如stateless workload,stateful workload,服务发现等来实现。

    好处是到处可以使用,跨平台。

    Kubernetes提供了一个Operator框架,供大家使用。控制集群里面的节点。

    Operator SDK for Build
    Operator Lifecycle manager for Run, 多个Operator的生命周期,比如版本。
    Operator Metering for Operate,收集统计信息。
    业界Open operators, 提供在github。比如etcd,Spark, MongoDB.

    例如,mongoDB提供了operator,封装了创造ReplicaSet的best practice。在PROD namespace,用户提供High level configuration,提供Intention about如何部署。Operator会帮助deploy。

    另外一个例子,根据Luke Bond的video, Cassandra需要把3节点扩展到5节点的时候,因为是stateful应用,需要做一系列的动作,这个知识就可以封装在operator。就像Kubectl增加instance的数量一样。

    Statefulset应用

    Example1

    创建pv
    cat /root/volume/pod-pv.yaml 
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv001
      labels:
        name: pv001
    spec:
      nfs:
        path: /data/volumes/v1
        server: nfs1
      accessModes: ["ReadWriteMany","ReadWriteOnce"]
      capacity:
        storage: 2Gi
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv002
      labels:
        name: pv002
    spec:
      nfs:
        path: /data/volumes/v2
        server: nfs1
      accessModes: ["ReadWriteMany"]
      capacity:
        storage: 2Gi
    ---
    apiVersion: v1
    kind: PersistentVolume
    metadata:
      name: pv003
      labels:
        name: pv003
    spec:
      nfs:
        path: /data/volumes/v3
        server: nfs1
      accessModes: ["ReadWriteMany","ReadWriteOnce"]
      capacity:
        storage: 2Gi
    
    创建StatefulSet
    cat pod-statefulset.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: myapp
      labels:
        app: myapp
    spec:
      ports:
      - port: 80
        name: web
      clusterIP: None
      selector:
        app: myapp-pod
    ---
    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: myapp
    spec:
      serviceName: myapp 
      replicas: 3
      selector:
        matchLabels:
          app: myapp-pod 
      template:
        metadata:
          labels:
            app: myapp-pod 
        spec:
          containers:
          - name: myapp 
            image: ikubernetes/myapp:v1 
            ports:
            - containerPort: 80
              name: web
            volumeMounts:
            - name: myappdata
              mountPath: /usr/share/nginx/html
      volumeClaimTemplates:
      - metadata:
          name: myappdata
        spec: 
          accessModes: [ "ReadWriteOnce" ]
          resources:
            requests:
              storage: 2Gi
    
    查看创建的Statefulset
    kubectl get svc
    # NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
    # kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   7d
    # myapp        ClusterIP   None         <none>        80/TCP    44s
    
    kubectl get sts
    # NAME    READY   AGE
    # myapp   3/3     46s
    
    kubectl get pods
    # NAME           READY   STATUS    RESTARTS   AGE
    # myapp-0        1/1     Running   0          48s
    # myapp-1        1/1     Running   0          40s
    # myapp-2        1/1     Running   0          39s
    
    StateFulSet扩缩容
    kubectl scale sts myapp --replicas=4
    kubectl patch sts myapp -p '{"spec":{"replicas":4}}'
    kubectl get pods -w
    NAME      READY   STATUS    RESTARTS   AGE
    myapp-0   1/1     Running   0          15m
    myapp-1   1/1     Running   0          15m
    myapp-2   1/1     Running   0          15m
    myapp-3   0/1     Pending   0          0s
    myapp-3   0/1     Pending   0          0s
    myapp-3   0/1     ContainerCreating   0          0s
    myapp-3   1/1     Running             0          2s
    
    
    # 我们进入pod创建一个文件,即使我们缩容删掉Pod,但是存储卷数据还在
    [root@master statefulset]# kubectl exec -it myapp-0 -- sh
    / # ls
    bin    etc    lib    mnt    root   sbin   sys    usr
    dev    home   media  proc   run    srv    tmp    var
    / # ls /usr/share/nginx/html/
    / # echo 1324 > /usr/share/nginx/html/index.html
    
    [root@nfs1 ~]# tree /data/volumes/
    /data/volumes/
    ├── v1
    │   └── index.html
    ├── v2
    ├── v3
    └── v4	
    
    [root@master statefulset]# kubectl scale sts myapp --replicas=1
    
    [root@master statefulset]# kubectl scale sts myapp --replicas=3
    
    [root@master statefulset]# kubectl exec -it myapp-0 /bin/sh
    kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.
    / # ls /usr/share/nginx/html/
    index.html
    
    控制更新策略
    # 默认为滚动更新
    kubectl describe sts myapp |grep Update 
    Update Strategy:    RollingUpdate
    kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
    # 留下两个不更新
    
    # 更换镜像
    kubectl set image sts/myapp myapp=ikubernetes/myapp:v2
    
    # 查看镜像版本
    kubectl get sts -o wide
    NAME    READY   AGE   CONTAINERS   IMAGES
    myapp   4/4     29m   myapp        ikubernetes/myapp:v2
    
    
    # 我们会发现有两个Pod版本还是以前的,可以算金丝雀发布
    kubectl patch sts myapp -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
    # 全部更新.
    
  • 相关阅读:
    ST_Geometry效率的测试与分析
    ArcEngine中加载ArcGIS Server地图服务
    正则表达式入门教程&&经典Javascript正则表达式(share)
    实现文件上传,以及表单提交成功的回调函数
    Jquery+asp.net实现Ajax方式文件下载实例代码
    Jquery 中 ajaxSubmit使用讲解
    其它课程中的python---4、Matplotlib最最最最简单使用
    其它课程中的python---3、numpy总结(非常全)
    其它课程中的python---2、NumPy模块
    其它课程中的python---1、python基础
  • 原文地址:https://www.cnblogs.com/you-men/p/13234975.html
Copyright © 2011-2022 走看看