kubernets之StatefulSet

1 StatefulSet解決的問題

對於kubernetes中的應用,如果同一個deployment中的pod存在依賴,或者對於數據存儲應用往往有多個實例,但每個實例都會在本地保存一份數據,如果應用實例重建,
那麼實例與本地數據的對應關係會丟失。這種實例的不對等關係以及對外部數據有依賴的應用,我們稱之爲“有狀態的應用”。
對於這種“有狀態的應用”如何管理,StatefulSet爲這個問題提供瞭解決辦法。

2 StatefulSet功能

StatefulSet把“有狀態的應用”抽象爲了兩種情況:

  • 拓撲狀態,應用之間不對等,啓動有先後順序
  • 存儲狀態,一個數據庫應用的多個實例

StatefulSet核心功能就是通過某種方式記錄這些狀態,然後在 Pod 被重新創建時,能夠爲新 Pod 恢復這些狀態。

3 StatefulSet之拓撲狀態

3.1 原理

Service 將一組Pod 暴露給外界訪問,那麼Service又改如何被訪問呢?

  • 以 Service 的 VIP(Virtual IP,即:虛擬 IP)方式

  • 以 Service 的 DNS 方式。比如:這時候,只要我訪問“my-svc.my-namespace.svc.cluster.local”這條 DNS 記錄,就可以訪問到名叫 my-svc 的 Service 所代理的某一個 Pod。可以分爲兩種處理方法:

    • 一是 Normal Service。這種情況下,你訪問“my-svc.my-namespacece.svc.cluster.local”解析到的,正是 my-svc 這個 Service 的 VIP,後面的流程就跟 VIP 方式一致了。

    • 二是 Headless Service。這種情況下,你訪問“my-svc.my-namespace.svc.cluster.local”解析到的,直接就是my-svc 代理的某一個 Pod 的 IP 地址。

    Normal Service和Headless Service 的區別是,後者不需要分配一個 VIP,可以直接以 DNS 記錄的方式解析出被代理 Pod 的 IP 地址。

Headless Service,其實仍是一個標準Service的YAML文件。只不過,它的 clusterIP 字段的值是:None,沒有VIP。

3.2 實例

statefulset.yaml 文件如下

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.9.1
        ports:
        - containerPort: 80
          name: web
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx

執行操作:

kubectl create -f statefulset.yaml -n cfd
# 查看過程
kubectl get pod -w -l app=nginx -n cfd

# 創建一個pod,用於訪問web pod
kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh -n cfd 

# 查看dns是否正常
nslookup web-0.nginx
nslookup web-1.nginx

# 刪除pod,查看啓動過程
kubectl delete pod -l app=nginx -n cfd
kubectl get pod -w -l app=nginx -n cfd

4 StatefulSet之存儲狀態

StatefulSet對存儲狀態的管理,主要使用的是Persistent Volume Claim的功能,同時也避免了用戶名、授權文件位置等信息的暴露。

對於一個pvc對象,Kubernetes會自動爲它綁定一個符合條件的Volume,這個Volume一般由運維人員維護。對於PVC和PV的設計,類似於“接口”和“實現”的思想。

4.1 實例

PV的YAML文件如下:

kind: PersistentVolume
apiVersion: v1
metadata:
  name: pv-volume
  labels:
    type: local
spec:
  capacity:
    storage: 10Gi
  accessModes:
  - ReadWriteOnce
  rbd:
    monitors:
    - '10.16.154.78:6789'
    - '10.16.154.82:6789'
    - '10.16.154.83:6789'
    pool: kube
    image: foo
    fsType: ext4
    readOnly: true
    user: admin
    keyring: /etc/ceph/keyring
    imageformat: "2"
    imagefeatures: "layering"

使用PVC的StatefulSet的YAML文件如下:

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

執行的操作:

kubectl create -f statefulset.yaml
# pvc 以“pvc名字-statefulset名字-編號”的方式命名
kubectl get pvc -l app=nginx
  NAME        STATUS    VOLUME                                     CAPACITY   ACCESSMODES   AGE
  www-web-0   Bound     pvc-15c268c7-b507-11e6-932f-42010a800002   1Gi        RWO           48s
  www-web-1   Bound     pvc-15c79307-b507-11e6-932f-42010a800002   1Gi        RWO           48s

# 在volume中寫入index.html文件
for i in 0 1; do kubectl exec web-$i -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'; done
# 訪問nginx服務器,返回index.html的內容
for i in 0 1; do kubectl exec -it web-$i -- curl localhost; done
  hello web-0
  hello web-1

# 刪除pod
kubectl delete pod -l app=nginx

# 在被重新創建出來的 Pod 容器裏訪問 http://localhost
$ kubectl exec -it web-0 -- curl localhost
  hello web-0

4.2 原理

根據以上的實例發現,在pod刪除時,並沒有刪除Pod對應的PVC和PV,而Volume寫入的數據也依然保存在遠程存儲服務中。
基於以上的現象,我們得出StatefulSet管理存儲狀態的原理如下所示:

    1. StatefulSet的控制器直接管理的是Pod,StatefulSet會在每個Pod實例後加一個編號,用於區分實例的不同;
    1. Kubernetes通過Headless Service,爲這些有編號的Pod,在DNS服務器中生成帶同樣編號的DNS記錄;
    1. StatefulSet爲每個pod創建一個同樣編號的PVC,這樣Kubernetes通過PV機制爲每個PVC綁定上對應的PV,保證每一個Pod一直擁有同一個獨立的Volume。
發佈了8 篇原創文章 · 獲贊 1 · 訪問量 4540
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章