Kubernetes之StatefulSet


什么是StatefulSet

StatefulSet 是Kubernetes中的一種控制器,他解決的什么問題呢?我們知道Deployment是對應用做了一個簡化設置,Deployment認為一個應用的所有的pod都是一樣的,他們之間沒有順序,也無所謂在那台宿主機上。需要擴容的時候就可以通過pod模板加入一個,需要縮容的時候就可以任意殺掉一個。但是實際的場景中,並不是所有的應用都能做到沒有順序等這種狀態,尤其是分布式應用,他們各個實例之間往往會有對應的關系,例如:主從、主備。還有數據存儲類應用,它的多個實例,往往會在本地磁盤存一份數據,而這些實例一旦被殺掉,即使從建起來,實例與數據之間關系也會丟失,而這些實例有不對等的關系,實例與外部存儲有依賴的關系的應用,被稱作“有狀態應用”。StatefulSet與Deployment相比,相同於他們管理相同容器規范的Pod,不同的時候,StatefulSet為pod創建一個持久的標識符,他可以在任何編排的時候得到相同的標識符。

StatefulSet的應用特點:

  • 穩定且有唯一的網絡標識符 當節點掛掉,既pod重新調度后其PodName和HostName不變,基於Headless Service來實現
  • 穩定且持久的存儲  當節點掛掉,既pod重新調度能訪問到相同的持久化存儲,基於PVC實現
  • 有序、平滑的擴展、部署 即Pod是有順序的,在部署或者擴展的時候要依據定義的順序依次進行(即從0到N-1,在下一個Pod運行之前所有之前的Pod必須都是Running和Ready狀態),基於init containers來實現。
  • 有序、平滑的收縮、刪除 既Pod是有順序的,在收縮或者刪除的時候要依據定義的順序依次進行(既從N-1到0,既倒序)。

我們可以把這些抽象成兩種應用狀態:

  • 拓撲狀態。是應用多個實例之間的不完全對等的關系,這些應用實例是必須按照定義的順序啟動的。例如主應用A先於從應用B啟動,如果把A和B刪掉,應用還要按照先啟動主應用A再啟動從應用B,且創建的應用必須和原來的應用的網絡標識一樣(既PodName和HostName)。這樣他們就可以按照原來的順序創建了。
  • 之間不是完全對等的關系

    極客時間版權所有: https://time.geekbang.org/column/article/41017

    存儲狀態。應用實例分別綁定了不同的數據存儲,Pod A第一次讀到的數據要和10分鍾后讀到的數據,是同一份。哪怕這期間Pod A被重建。這種典型的例子就是數據庫應用的多個存儲實例。

所以 StatefulSet的核心功能就是,通過某種方式記錄應用狀態,在Pod被重建的時候,通過這種方式還可以恢復原來的狀態。

從上面的應用場景可以發現,StatefulSet由以下幾個部分組成:

  • Headless Service 用於定義網絡標識(DNS)
  • volumeClaimTemplates  用於創建PV
  • StatefulSet  用於定義具體應用

講解Headless Service

我們知道kubernetes中的service是定義pod暴露外部訪問的一種機制,例如:3個pod,我們可以定義一個service通過標簽選擇器選到這三個pod,然后讓問這個service就可以訪問這個pod。可以出門左轉,看一下 Service的講解。 我們這里具體講一下Headless service。

Headless service是Service通過DNS訪問的其中一種方式,只要我們訪問"mypod.stsname.namespace.svc.cluster.local",我們就會訪問到stsname下的mypod。而Service DNS的方式下有兩種處理方法:

  • Normal Service 這里訪問"mypod.stsname.namespace.svc.cluster.local"的時候會得到mypod的service的IP,既VIP。
  • Headless Service 這里訪問"mypod.stsname.namespace.svc.cluster.local"的時候會得到mypod的IP,這里我們可以看到區別是,Headless Service 不需要分配一個VIP,而是通過DNS訪問的方式可以解析出帶代理的Pod的IP

Headleaa Service的定義方式:

apiVersion: v1
kind: Service
metadata:
  name: myapp-headless
  namespace: default
spec:
  selector:
    app: myapp
    release: dev
  clusterIP: "None"
  ports:
  - port: 80
    targetPort: 80

Headless Service也是一個標准的Service的YAML文件,只不過clusterIP定義為None,既,這個service沒有VIP作為"頭"。以DNS會記錄的方式記錄所有暴露它代理的Pod。而它代理的Pod依然會采用標簽選擇器的機制選擇。既:所有攜帶了 app=myapp 標簽的pod。都會被service代理起來。

DNS格式:

pod-name.svc-name.namespace.svc.cluster.local

StatefulSet詳解

kubectl explain sts.spec 主要字段解釋:

  • replicas   副本數
  • selector  那個pod是由自己管理的
  • serviceName  必須關聯到一個無頭服務商
  • template 定義pod模板(其中定義關聯那個存儲卷)
  • volumeClaimTemplates  生成PVC

部署一個statefulset服務

這里我們用的storageClass,PV和PVC會動態創建。這個跑成功必須創建一個rook服務的動態存儲,創建方法參考 rook官網

apiVersion: v1
kind: Service
metadata:
  name: myapp-sts
  labels:
    app: myapp-sts
spec:
  ports:
  - port: 80
    name: web
  clusterIP: "None"
  selector:
    app: myapp-pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myapp
spec:
  serviceName: myapp-sts-svc
  replicas: 2
  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"]
      storageClassName: "rook-ceph-block"
      resources:
        requests:
          storage: 5Gi

查看一下服務

$ kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
myapp-sts    ClusterIP   None           <none>        80/TCP    5m

 查看pv/pvc

$ kubectl get pvc
NAME                STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
myappdata-myapp-0   Bound     pvc-550493cf-dc1f-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   43m
myappdata-myapp-1   Bound     pvc-5a4276b4-dc1f-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   43m
$  kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM                       STORAGECLASS      REASON    AGE
pvc-550493cf-dc1f-11e8-b8c9-005056930126   5Gi        RWO            Delete           Bound     default/myappdata-myapp-0   rook-ceph-block             43m
pvc-5a4276b4-dc1f-11e8-b8c9-005056930126   5Gi        RWO            Delete           Bound     default/myappdata-myapp-1   rook-ceph-block             43m

 查看pod

$ kubectl get pod
NAME                          READY     STATUS    RESTARTS   AGE
myapp-0                       1/1       Running   0          17h
myapp-1                       1/1       Running   0          17h

驗證解析

$ kubectl exec -it myapp-1 -- /bin/sh 
/ # nslookup  myapp-1.myapp-sts-svc.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolve

Name:      myapp-1.myapp-sts-svc.default.svc.cluster.local
Address 1: 10.244.3.37 myapp-1.myapp-sts-svc.default.svc.cluster.local

擴容(擴展應該是按順序擴展)

$ kubectl scale sts myapp --replicas=5

$ kubectl get pod -w 
NAME                          READY     STATUS    RESTARTS   AGE
myapp-0                       1/1       Running   0          18h
myapp-1                       1/1       Running   0          18h
myapp-2   0/1       Pending   0         0s
myapp-2   0/1       Pending   0         0s
myapp-2   0/1       Pending   0         0s
myapp-2   0/1       ContainerCreating   0         0s
myapp-2   1/1       Running   0         15s
myapp-3   0/1       Pending   0         0s
myapp-3   0/1       Pending   0         1s
myapp-3   0/1       Pending   0         1s
myapp-3   0/1       ContainerCreating   0         1s
$ kubectl get pvc
NAME                STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
myappdata-myapp-0   Bound     pvc-550493cf-dc1f-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   18h
myappdata-myapp-1   Bound     pvc-5a4276b4-dc1f-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   18h
myappdata-myapp-2   Bound     pvc-25e46dbd-dcba-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   2m
myappdata-myapp-3   Bound     pvc-2f420e8c-dcba-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   1m
myappdata-myapp-4   Bound     pvc-4607d3c8-dcba-11e8-b8c9-005056930126   5Gi        RWO            rook-ceph-block   1m

縮容 (按倒序縮容)

$ kubectl scale sts myapp --replicas=3

$  kubectl get pod -w 
NAME                          READY     STATUS    RESTARTS   AGE
myapp-0                       1/1       Running   0          18h
myapp-1                       1/1       Running   0          18h
myapp-2                       1/1       Running   0          3m
myapp-3                       1/1       Running   0          3m
myapp-4                       1/1       Running   0          2m
myapp-4   1/1       Terminating   0         2m
myapp-4   0/1       Terminating   0         2m
myapp-4   0/1       Terminating   0         2m
myapp-4   0/1       Terminating   0         2m
myapp-3   1/1       Terminating   0         3m
myapp-3   0/1       Terminating   0         3m
myapp-3   0/1       Terminating   0         3m
myapp-3   0/1       Terminating   0         3m

升級

查看升級策略

kubectl explain sts.spec.updateStrategy

  • rollingUpdate  滾動更新

kubectl explain sts.spec.updateStrategy.rollingUpdate

  • partition  分區更新,默認partition的值是0,當partition等N,N+的都會更新。

默認partition是從0開始更新

 

 當partition等於4的時候,4以后的都要更新。

 

$ kubectl set image sts/myapp myapp=ikubernetes/myapp:v2
$ kubectl describe pod  myapp-2  
Name:               myapp-2
Namespace:          default
Priority:           0
PriorityClassName:  <none>
Node:               k8s-node01/172.16.138.41
Start Time:         Thu, 01 Nov 2018 02:33:00 -0400
Labels:             app=myapp-pod
                    controller-revision-hash=myapp-5775ff7474
                    statefulset.kubernetes.io/pod-name=myapp-2
Annotations:        <none>
Status:             Running
IP:                 10.244.1.13
Controlled By:      StatefulSet/myapp
Containers:
  myapp:
    Container ID:   docker://75d5e6b3958f053908eb3e5fa1c2846ce91d90c9ff696f27e6220a66d2e8cc7c
    Image:          ikubernetes/myapp:v2
    Image ID:       docker-pullable://ikubernetes/myapp@sha256:85a2b81a62f09a414ea33b74fb8aa686ed9b168294b26b4c819df0be0712d358
    Port:           80/TCP
    Host Port:      0/TCP
.....

 

Normal Service

極客時間版權所有

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM