k8s之StatefulSet介紹(六)

複製有狀態的Pod
replicaSet經過一個pod模版建立多個pod副本。這些副本除了它們的名字和IP地址不一樣外,沒有別的差別。若是pod模版裏描述了一個關聯到特定持久卷聲明的數據卷,那麼ReplicaSet的全部副本都將共享這個持久卷聲明,也就是綁定到同一個持久卷聲明。
由於是在pod模版裏關聯持久卷聲明的,又會依據pod模版建立多個副本,則不能對每一個副本都指定獨立的持久卷聲明。因此也不能經過一個ReplicaSet來運行一個每一個實例都須要獨立存儲的分佈式數據存儲服務,至少經過單個ReplicaSet是作不到的。老實說,以前你學習到的全部API對象都不能提供這樣的數據存儲服務,還須要一個其餘的對象--StatefulSet
 
咱們先看不使用StatefulSet的狀況下有沒有方法實現多個副本有本身的持久卷聲明。
三種取巧的方法。
第一種方法,不使用ReplicaSet,使用Pod建立多個pod,每一個pod都有獨立的持久卷聲明。須要手動建立它們,當有的pod消失後(節點故障),須要手動建立它們。所以不是一個好方法。
第二種方法,多個replicaSet ,每一個rs只有一個pod副本。但這看起來很笨重,並且沒辦法擴縮容。
第三種方法,使用同一個ReplicaSet,你們也都掛載同一個持久卷聲明,應用內部作好互斥,建立多個data數據目錄,每個pod用一個標記爲在用,後面應用不能選被標記爲在用的目錄。這樣作很難保證協調的一點沒問題,同時你們用同一個持久卷,讀寫io將成爲整個應用的瓶頸。
 
除了上面的存儲需求,集羣應用也會要求每個實例擁有生命週期內惟一標識。pod能夠隨時被刪掉,而後被新的pod替代。當一個ReplicaSet中的pod被替換時,儘管新的pod也可能使用被刪除pod數據卷中的數據,但它倒是擁有全新主機名和IP的嶄新pod.在一些應用中,當啓動的實例擁有徹底新的網絡標識,但還使用舊實例的數據時,極可能引發問題,好比etcd存儲服務。
固然也能夠建立多個service ,每個replicaset對應一個service,那麼同樣很笨重,且顯得很低級。辛運的是,Kubernetes爲咱們提供了這類需求的完美解決方案--StatefulSet.
 
瞭解StatefulSet
能夠建立一個StatefulSet資源代替ReplicaSet來運行這類pod.它們是專門定製的一類應用,這類應用中每個實例都是不可替代的個體,都擁有穩定的名字和狀態。
對比StatefulSet 與 ReplicaSet 或 ReplicationController
RS或RC管理的pod副本比較像牛,它們都是無狀態的,任什麼時候候它們均可以被一個全新的pod替換。而後有狀態的pod須要不一樣的方法,當一個有狀態的pod掛掉後,這個pod實例須要在別的節點上重建,可是新的實例必須與被替換的實例擁有相同的名稱、網絡標識和狀態。這就是StatefulSet如何管理pod的。
StatefulSet 保證了pod在從新調度後保留它們的標識和狀態。它讓你方便地擴容、縮容。與RS相似,StatefulSet也會指按期望的副本數,它決定了在同一時間內運行的寵物數。也是依據pod模版建立的,與RS不一樣的是,StatefulSet 建立的pod副本並非徹底同樣的。每一個pod均可以擁有一組獨立的數據卷(持久化狀態)。另外pod的名字都是規律的(固定的),而不是每一個新pod都隨機獲取一個名字。
 
提供穩定的網絡標識
StatefulSet 建立的pod的名稱,按照從零開始的順序索引,這個會體如今pod的名稱和主機名稱上,一樣還會體如今pod對應的固定存儲上。
有狀態的pod與普通的pod不同的是,有狀態的pod有時候須要經過其主機名來定位,而無狀態的不須要,由於無狀態的都同樣,隨機選一個就行,但對於有狀態的來講,每個pod都不同,一般但願操做的是特定的一個。基於這個緣由,一個StatefulSet要求你建立一個用來記錄每一個pod網絡標記的headless Service。經過這個Service,每一個pod將擁有獨立的DNS記錄,這樣集羣裏它的夥伴或者客戶端就能夠經過主機名找到它。好比說一個屬於default命名空間,名爲foo的控制服務,它的一個pod名稱爲A-0,那麼完整域名爲:a-0.foo.default.svc.cluster.local。而在ReplicaSet是行不通的。
此外咱們能夠在容器中經過dig foo.default.svc.cluster.local對應的SRV記錄,獲取一個StatefulSet中全部pod的名稱.
 
StatefulSet擴縮容的特色
擴容,會按照索引進行
縮容,也會按照索引,刪除索引值最大的 pod
縮容StatefulSet任什麼時候候只會操做一個pod實例,因此會很慢,不是由於索引要順序進行,而是爲了不數據丟失。舉例來講,一個分佈式存儲應用副本數爲2,若是同時下線兩個,一份數據記錄就會丟失。
基於以上緣由,StatefulSet在有實例不健康的狀況下是不容許進行縮容操做的。一個不健康,你又縮容一個這樣至關於兩個同時下線。
持久卷的建立和刪除
擴容Statefulset增長一個副本,會建立兩個或更多的API對象(一個pod和一個與之關聯的持久卷聲明)。但對於縮容來將,只會刪除一個pod,而遺留下以前建立的聲明。由於當一個聲明被刪除後,與之綁定的持久卷就會被回收或刪除,其上面的數據就會丟失。基於這個緣由,你須要釋放特定的持久卷時,須要手動刪除對應的持久卷聲明。
 
StatefulSet的保障機制。
一個有狀態的pod總會被一個徹底一致的pod替換(二者相同的名稱,主機名和存儲等)。這個替換髮生在kubernetes發現舊pod不存在時(例如手動刪除這個pod).
那麼當Kubernetes不能肯定一個pod的狀態呢?若是它建立一個徹底一致的pod,那系統中就會有兩個徹底一致的pod在同時運行。這兩個pod會綁定到相同的存儲,因此這兩個相同標記的進程會同時寫相同的文件。
爲了保證兩個擁有相同標記和綁定相同持久卷聲明的有狀態的pod實例不會同時運行,statefulset遵循at-most-one語義。也就是說一個StatefulSet必須在準確確認一個pod再也不運行後,纔會去建立它的替換pod。這對如何處理節點故障有很大幫助。具體實現,內部的,暫不深刻。
講了那麼多StatefulSet實現有狀態pod的好處,下面看看如何建立。
 
咱們假設使用gec建立三個pv

 

kind: list
apiVersion: v1
item:
-   apiVersion: v1
  kind: PersistenVolume
  metadata:
    name: pv-a
  spec:
    capacity:
      storage: 1Mi
    accessModes:
    -    ReadWriteOnce
    persistenVolumeReclaimPolicy: Recycle  卷被聲明釋放後,空間會被回收再利用
    gcePersistentDisk:
      poName: pv-a
      fsType: nfs4
-   apiVersion: v1
  kind: PersistenVolume
  metadata:
    name: pv-b
...

 

準備好pv後,咱們接下來建立statefulset
 
如咱們以前將到的,在部署一個StatefulSet以前,須要建立一個用於在有狀態的pod之間提供網絡標識的headless Service

 

apiVersion: v1
kind: Service
metadata:
  name: kubia
spec:
  clusterIP: None        (StatefulSet的控制Service必須時None即headless模式)
  selector:
    app: kubia
  ports:
  -   name: http
    port: 80

 

建立StatefulSet詳單

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: kubia
spec:
  serviceName: kubia
  replicas: 2
  template:
    metadta:
      labels:
        app: kubia
    spec:
      containers:
      -   name: kubia
        image: luksa/kubia-pet
        ports:
        -   name: kubia
          containerPort: 8080

volumeMounts:

        - name: data
         mountPath: /var/data   volumeClaimTemplates:   - metadata:     name: data     spec:       resources:         requests:           storage: 1Mi       accessModes:       - ReadWriteOnce

 

建立:
kubectl create -f kubia-statefulset.yaml
 
列出pod:
kubectl get pod
Name READY
kubia-0 0/1 ...
看到會一個個進行
kubectl get pod
Name READY
kubia-0 1/1 ...
kubia-1 0/1 ...
 
查看pvc
kubectl get pvc
Name STATUS VOlUME
data-kubia-0 Bound pv - c ...
data-kubia-1 Bound pv - a ...
 
能夠看到生成的持久卷聲明的名稱由 volumeClaimTeplate 字段中定義的名稱和每一個pod的名稱組成。
 
如今你的數據存儲集羣節點都已經運行,能夠開始使用它們了。由於以前建立的Service處於headless模式,因此不能經過service來訪問你的pod。須要直接鏈接每一個單獨的pod來訪問(或者建立一個普通的Service,可是這樣仍是不容許你訪問指定的pod)
 
咱們來建立一個普通的service以下:

apiVersion: v1
kind: service
metadata:
  name: kubia-public
spec:
  selector:
    app: kubia
  ports:
  -   port: 80
    targetPort: 8080

 

 

StatefulSet 已經運行起來了,那麼咱們看下如何更新它的pod模版,讓它使用新的鏡像。同時你也會修改副本數爲3.一般會使用kubectl edit命令來更新StatefulSet
kubectl edit statefulset kubia
你會看到新的pod實例會使用新的鏡像運行,那已經存在的兩個副本呢?經過他們的壽命能夠看出它們沒有更新。這是符合預期的。由於,首先StatefulSet更像ReplicaSet,而不是Deployment,因此在模版被修改後,它們不會重啓更新,須要手動刪除這些副本,而後StatefulSet會根據新的模版從新調度啓動它們。
kubectl delete po kubia-0 kubia-1
注意: 從Kubernetes1.7版本開始,statefulSet支持與Deployment和DaemonSet同樣的滾動升級。經過kubectl explain 獲取StatefulSet的spec.updateStrategy 相關文檔來獲取更多信息。
 
前面咱們提到StatefulSet的保障機制,那麼當一個節點故障了,會出現什麼狀況。
statefulset在明確知道一個pod再也不運行以前,它不能或者不該當建立一個替換pod。只有當集羣的管理者告訴它這些信息時候,它才能明確知道。爲了作到這一點,管理者須要刪除這個pod,或者刪除整個節點。
當手動中止一個node的網卡,使用kubectl get node,會顯示Status notReady
由於控制檯不會再收到該節點發送的狀態更新,該節點上嗎的全部pod狀態都會變爲Unknown。
當一個pod狀態爲Unknown時會發生什麼
若該節點過段時間正常鏈接,而且從新彙報它上面的pod狀態,那這個pod就會從新被標記爲Runing。但若是這個pod的未知狀態持續幾分鐘後(這個時間是能夠配置的),這個pod就會自動從節點上驅逐。這是由主節點(kubernetes的控制組件)處理的。它經過刪除pod的資源來把它從節點上驅逐。
當kubelet發現這個pod標記爲刪除狀態後,它開始終止運行該pod。在上面的示例中,kubelet已不能與主節點通訊(由於網卡斷了),這意味着這個pod會一直運行着。查看
kubectl describe po kubia-0
發現status一直爲Terminating,緣由是NodeLost,在信息中說明的是節點不迴應致使不可達。
這時候你想要手動刪除pod
kubectl delete po kubia-0
執行完成後,你的想法是會再次運行一個kubia-0
可是kubectl get po會發現kubia-0 狀態爲 Unknown 而且仍是以前那個舊pod ,由於啓動時長沒變。
爲何會這樣?由於在刪除pod以前,這個pod已經被標記爲刪除。這是由於控制組件已經刪除了它(把它從節點驅逐)。這時你用kubectl describe po kubia-0 查看狀態依然是Terminating。
這時候只能進行強制刪除
kubectl delete po kubia-0 --force --grace-period 0
你須要同時使用--force和 --grace-period 0兩個選項。而後kubectl 會對你作的事發出
警告信息。若是你再次列舉pod,就能夠看到一個新的kubia-0 pod被建立出來。
警告: 除非你確認節點再也不運行或者不會再能夠訪問(永遠不會再能夠訪問),不然不要強制刪除有狀態的pod.
相關文章
相關標籤/搜索