1. 程式人生 > 實用技巧 >Kubernetes進階之StatefulSet有狀態部署

Kubernetes進階之StatefulSet有狀態部署

K8s有狀態應用部署
目錄:分為兩類
1.Headless Service
2.StatefulSet

• 部署有狀態應用
• 解決Pod獨立生命週期,保持Pod啟動順序和唯一性

  • 穩定,唯一的網路識別符號,持久儲存
  • 有序,優雅的部署和擴充套件、刪除和終止
  • 有序,滾動更新

應用場景:資料庫

說在前面的話,像我們的Mysql或者Redis了,Zookerper等等這些適不適合部署在K8s中,其實呢不是太適合,但部署在裡面也可以,比如部署一個Mysql來講吧,部署到k8s中還是很容易的就一個Mysql例項,就像部署其他應用一樣,通過service、IP去訪問它,但是要是作為叢集的狀態去部署的話,那可能就比較麻煩了。
第一點:比如做一個Mysql的主從,Mysql主從它是有主從拓撲關係的,一個主一個從,而且各自的資料都不一樣,這就意味著,你要想搭建一個Mysql的主從,你要知道它的相互的ip地址,就是從肯定要知道主的ip地址,然後從連線主的ip地址,做資料的同步。
第二點:它的儲存,它兩個儲存的資訊都不太一樣,那怎麼去保證它兩個資料的儲存保證持久化呢,一個叢集中可能會有多個節點,要是部署到k8s中,必須要保證部署的應用,在任意的節點都能使用原來的狀態,也就是說某一個節點掛了,上面的pod飄移到另一個節點,能不能用到之前的狀態,所以要考慮這些問題。
而k8s設計的精髓在於並不是你部署一個單的例項,而是在於它的一個分散式一個部署,具有故障恢復能力的應用,所以就談到了有狀態和無狀態應用。

有狀態應用:DB,好比一個Mysql主從,考慮兩點(自己的儲存,必須是遠端的儲存,在任意節點掛載都恢復原來的狀態)而且還有網路ID的唯一,需要做主從的連線,我們的pod是短暫的,重建一個ip就換了,得保證這個ip一直去使用,不管是重建還是遷移pod,都能去使用。
無狀態應用:典型的就是web系統,本身就沒有什麼狀態去維護,比如部署了三個副本,不需要考慮其他兩個副本是什麼樣的,跟它沒有直接的關係,本地也沒有什麼持久化的資料,即使其中有一個副本掛了,幫它在其他節點起來,仍然可以繼續提供服務,對原基礎服務是沒有任何影響的,所以這是一個前提,典型的就是web。

在k8s中呢在1.10版本之後有狀態部署才支援好一點,但是剛開始在落地K8s的時候,而不會去考慮有狀態部署的,主要做無狀態的部署,而資料庫適不適合部署在k8s中,在看k8s的一些特性,k8s有適合的一些特性,比如具有一些訪問比較大的應用,版本迭代快的應用,或者彈性伸縮的一些應用,凡是這些是適合放在k8s,k8s最早就支援無狀態,也是一直在推薦,有狀態的也是比較複雜,複雜點就在與有狀態的都是一些叢集化的,比如zookerper,
Mysql主從,這些都是需要自身的一個狀態維護的,這些部署進去呢,可能去考慮它這個網路拓撲關係,還有儲存狀態的持久化,而資料庫不具備這些特點,部署一個數據庫一般配置比較高一些,可以會抗很多的併發量,而且要擴容的話也是很方便,而且傳統的部署文章也很多,也比較成熟,在k8s中部署這些東西,那絕對是一種挑戰,所以要根據不同的應用特點去考慮上k8s,不要一味地上k8s,而且得不償失,達不到預期的效果,領導也會批你,所以在談有狀態部署的話,可以在兩者出發,一個是Headless Service維護網路的,一個是StatefulSet維護儲存狀態的。

statefulSet是一個控制器,與Deployment存在的原則一樣,都是部署應用的,而Statefulset它主要是部署有狀態應用的,而deployment是部署無狀態應用的

Headless Service 其實和service差不多,這不過定義的這個叫無頭服務,它們之間唯一的區別就是將Cluster ip 設定為了none,不會幫你配置ip

[root@k8s-master demo]# mkdir headless-service
[root@k8s-master demo]# cd headless-service/
[root@k8s-master headless-service]# vim headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: my
-service spec: clusterIP: None selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 9376 [root@k8s-master headless-service]# kubectl create -f headless-svc.yaml service/my-service created [root@k8s-master headless-service]# kubectl get svc kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 23h my-service ClusterIP None <none> 80/TCP 6s service NodePort 10.1.207.32 <none> 80:30963/TCP 87m zhao ClusterIP 10.1.75.232 <none> 80/TCP 9m1s zhaocheng ClusterIP 10.1.27.206 <none> 80/TCP 10m

怎麼去訪問?我們給它定義一個標識
建立完之後會有這個識別符號,它會使用這個DNS來解析這個名稱,來相互的訪問,headless就不會通過ip去訪問了,必須通過名稱去訪問,

[root@k8s-master headless-service]# vim statefulset.yaml
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: nginx-statefulset
  namespace: default
spec:
  serviceName: my-service
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

[root@k8s-master headless-service]# kubectl apply -f statefulset.yaml 
[root@k8s-master headless-service]# kubectl get pod

my-pod                                   1/1     Running   0          3h50m
nfs-744d977b46-dh9xj                     1/1     Running   0          22h
nfs-744d977b46-kcx6h                     1/1     Running   0          22h
nfs-744d977b46-wqhc6                     1/1     Running   0          22h
nfs-client-provisioner  1/1     Running   0          4h
nginx-797db8dc57-tdd5s                   1/1     Running   0          100m
nginx-statefulset-0                      1/1     Running   0          73s
nginx-statefulset-1                      1/1     Running   0          46s
nginx-statefulset-2                      1/1     Running   0          24s

這裡的statfulset的 serviceName: my-service欄位要關聯起來,這樣才能去基於名稱去訪問
可以通過busybox測試工具通過nslookup去測試解析。解析我們的my-service就能解析到
這裡會分配一個名稱,這個my-service和這個編號是永久的,可以通過這個名稱訪問pod
要是mysql主從的話就可以通過訪問這個標籤來連線我們從庫的狀態,這個是維護的網路狀態
然後再來看一下儲存狀態

官方文件這個例項
https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/
這個其實我們也是部署一個nginx,使用的headless,ClusterIP為none,然後用headless來維護statefulset起得pod網路id為1,以 volumeClaimTemplates:來維護pod獨立的一個儲存

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 # has to match .spec.template.metadata.labels
  serviceName: "nginx"
  replicas: 3 # by default is 1
  template:
    metadata:
      labels:
        app: nginx # has to match .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:

- name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "managed-nfs-storage"
      resources:
        requests:
          storage: 1Gi

這是我們的儲存要寫我們nfs的名稱
managed-nfs-storage

[root@k8s-master headless-service]# kubectl get sc

managed-nfs-storage   fuseim.pri/ifs   22h

這裡會給我們自動建立pv,並掛載到我們的NFS上

[root@k8s-master headless-service]# kubectl get pod

my-pod                                   1/1     Running            0          6h4m
nfs                     1/1     Running            0          24h
nfs                    1/1     Running            0          24h
nfs                     1/1     Running            0          24h
nfs-client-provisioner-fbc  1/1     Running            0          6h23m
nginx-797db8dc57-tdd5s                   1/1     Running            0          3h54m
nginx-a1-6d5fd7b8dd-w647x                1/1     Running            0          3m28s
nginx-statefulset-0                      1/1     Running            0          135m
nginx-statefulset-1                      1/1     Running            0          135m
nginx-statefulset-2                      1/1     Running            0          134m
web-0                                    1/1     Running            0          3
web-1                                    1/1     Running            0          85s
web-2                                    1/1     Running            0          57s
[root@k8s-master headless-service]# kubectl get pv

pvc-06  1Gi        RWO            Delete           Bound    default/www-web-2   managed-nfs-storage            63s
pvc-4f   1Gi        RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            6m3s
pvc-a2   5Gi        RWX            Delete           Bound    default/my-pvc      managed-nfs-storage            6h4m
pvc-bc 1Gi        RWO            Delete           Bound    default/www-web-1   managed-nfs-storage           

headless保證它的網路,statefulset儲存模版來保證每個pod儲存的唯一性,這樣才解決了有狀態應用的兩大痛點