Statefulset詳細解析


StatefulSet實現Pod的拓撲狀態

     Stateful狀態集在創建和擴展的時候有特殊的限制,如果一個有狀態集期望的Pod數量是N,那么有StatefulSet會從0開始依次創建這些Pod在第一個Pod正常運行之前是不會創建第二個Pod.在刪除Pod的時候,則是從第N個Pod開始反向依次刪除

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

     只要知道一個Pod的名字以及它對應的Service的名字,就可以通過這條DNS記錄訪問到Pod的IP地址(pod的名稱.service名稱) -> Pod的IP

     定義Stateful的對象中有一個serviceName字段來告訴Stateful控制器使用具體的service來解析它所管理的Pod的IP地址

     Pod的名稱由StatfulSet對象的名稱+Pod創時所在的索引組成 StatefulSet使用這個DNS記錄解析規則來維持Pod的拓撲狀態

     StatefulSet給它所管理的所有Pod的名字進行了編號,編號規則是: - .而且這些編號都是從0開始累加與StatefulSet的每個Pod實例一一對應 絕不重復

     這些Pod的創建也是嚴格按照編號順序進行的.比如,在web-0進入到Running 狀態、並且細分狀態(Conditions)成為Ready之前,web-1會一直處於Pending狀態
     把這兩個Pod刪除之后Kubernetes會按照原先編號的順序,創建出了兩個新的 Pod.並且Kubernetes依然為它們分配了與原來相同的“網絡身份”:web-0.nginx和 web-1.nginx

     通過永遠不改變Pod名稱的方式StatefulSet保證了Pod網絡標識的穩定性.不管Pod是被刪除重啟還是被調度到其他節點上都不會改變Pod的名稱

     StatefulSet管理的pod使用的鏡像是一樣的,但是每個pod的命令和初始化流程可以完全不一樣來實現主從Pod的拓撲部署

    盡管web-0.nginx這條DNS記錄本身不會變但它解析到的Pod的IP地址並不是固定的.這就意味着,對於“有狀態應用”實例的訪問必須使用DNS記錄或者hostname的方式而絕不應該直接訪問這些Pod的IP地址

StatefulSet實現Pod的存儲狀態

      通過PVC機制來實現存儲狀態管理

      在StatefulSet對象中除了定義PodTemplate還會定義一個volumeClaimTemplates凡是被這個StatefulSet管理的Pod都會聲明一個對應的PVC,這個PVC的定義就來自於 volumeClaimTemplates這個模板字段

這個PVC的名字,會被分配一個與這個Pod完全一致的編號

 把一個Pod比如web-0刪除之后,這個Pod對應的PVC和PV並不會被刪除,而這個Volume 里已經寫入的數據,也依然會保存在遠程存儲服務里

 StatefulSet在重新創建web-0這個pod的時候.它聲明使用的PVC的名字還是叫作:www-web-0 這個PVC的定義,還是來自於PVC模板(volumeClaimTemplates)這是StatefulSet創建 Pod的標准流程

 Kubernetes為它查找名叫www-web-0的PVC時,就會直接找到舊Pod遺留下來的同名的 PVC進而找到跟這個PVC綁定在一起的PV.這樣新的Pod就可以掛載到舊Pod對應的那個Volume並且獲取到保存在Volume里的數據.通過這種方式Kubernetes的StatefulSet就實現了對應用存儲狀態的管理

StatefulSet其實就是一種特殊的Deployment,而其獨特之處在於,它的每個Pod都被編號了.而且,這個編號會體現在Pod的名字和hostname等標識信息上,這不僅代表了Pod的創建順序,也是Pod的重要網絡標識(即:在整個集群里唯一的、可被的訪問身份).有了這個編號后StatefulSet就使用Kubernetes里的兩個標准功能:Headless Service 和 PV/PVC,實現了對 Pod 的拓撲狀態和存儲狀態的維護

StatefulSet搭建Mysql有狀態集群

     1.Master節點和Slave節點需要有不同的配置文件(即:不同的 my.cnf)

       只需要給主從節點分別准備兩份不同的 MySQL 配置文件  然后根據Pod的序號(Index)掛載進去即可

     2.Master節點和Slave節點需要能夠傳輸備份信息文件

     3.在Slave節點第一次啟動之前需要執行一些初始化SQL操作

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  labels:
    app: mysql
data:
  master.cnf: |
     [mysqld]
     log-bin
  slave.cnf: |
     [mysqld]
     super-read-only
configmap.yaml
apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  clusterIP: None
  selector:
    app: mysql

---
apiVersion: v1
kind: Service
metadata:
  name: mysql-read
  labels:
    app: mysql
spec:
  ports:
  - name: mysql
    port: 3306
  selector:
    app: mysql
service.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
spec:
  nfs:
   path: /data/volumes/v1
   server: 192.168.164.141
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
   path: /data/volumes/v2
   server: 192.168.164.141
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
   path: /data/volumes/v3
   server: 192.168.164.141
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
   path: /data/volumes/v4
   server: 192.168.164.141
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
   path: /data/volumes/v5
   server: 192.168.164.141
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 20Gi
pv.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  serviceName: mysql
  replicas: 3
  template:
    metadata:
      labels:
        app: mysql
    spec:
      initContainers:
      - name: init-mysql
        image: mysql:5.7
        command:
        - bash
        - "-c"
        - |
          set -ex
          [[ `hostname`  =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          echo [mysqld] > /mnt/conf.d/server-id.cnf
          echo server-id=$((100 + $ordinal )) >> /mnt/conf.d/server-id.cnf
          if [[ $ordinal -eq 0 ]]; then
            cp /mnt/config-map/master.cnf /mnt/conf.d/
          else
            cp /mnt/config-map/slave.cnf /mnt/conf.d/
          fi
        volumeMounts:
        - name: conf
          mountPath: /mnt/conf.d
        - name: config-map
          mountPath: /mnt/config-map
      - name: clone-mysql
        image: gcr.io/google-samples/xtrabackup:1.0
        command:
        - bash
        - "-c"
        - |
          set -ex
          [[ -d /var/lib/mysql/mysql ]] && exit 0
          [[ `hostname` =~ -([0-9]+)$ ]] || exit 1
          ordinal=${BASH_REMATCH[1]}
          [[ $ordinal -eq 0 ]] && exit 0
          ncat --recv-only mysql-$((ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
          xtrabackup --prepare  --target-dir=/var/lib/mysql
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ALLOW_EMPTY_PASSWORD
          value: "1"
        ports:
        - name: mysql
          containerPort: 3306
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
        resources:
          requests:
            cpu: 500m
            memory: 500Mi
        livenessProbe:
          exec:
            command: ["mysqladmin","ping"]
          initialDelaySeconds: 30
          periodSeconds: 10
          timeoutSeconds: 5
        readinessProbe:
          exec:
            command: ["mysql","-h","127.0.0.1","-e","SELECT 1"]
          initialDelaySeconds: 5
          periodSeconds: 2
          timeoutSeconds: 1
      - name: xtrabackup
        image: gcr.io/google-samples/xtrabackup:1.0
        ports:
        - name: xtrabackup
          containerPort: 3307
        command:
        - bash
        - "-c"
        - |
          set -ex
          cd /var/lib/mysql
          if [[ -f xtrabackup_slave_info ]]; then
             mv xtrabackup_slave_info change_master_to.sql.in
             rm -f xtrabackup_binlog_info
          elif [[ -f xtrabackup_binlog_info ]]; then
             [[ `cat xtrabackup_binlog_info` =~ ^(.*)[[:space:]]+(.*?)$ ]] || exit 1
             rm xtrabackup_binlog_info
             echo "change master to master_log_file='${BASH_REMATCH[1]}',\
                  MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
          fi
          if [[ -f change_master_to.sql.in ]]; then
             echo "waiting for mysqld to be ready"
             until mysql -h 127.0.0.1 -e "SELECT 1";do sleep 1;done
             echo "Initializing replication from clone position"
             mv change_master_to.sql.in change_master_to.sql.orig
             mysql -h 127.0.0.1 <<EOF
             $(<change_master_to.sql.orig),
              MASTER_HOST='mysql-0.mysql',
              MASTER_USER='root',
              MASTER_PASSWORD='',
              MASTER_CONNECT_RETRY=10;
          START SLAVE;
          EOF
          fi

          exec ncat --listen  --keep-open --send-only  --max-conns=1 3307 -c \
              "xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
          subPath: mysql
        - name: conf
          mountPath: /etc/mysql/conf.d
      volumes:
      - name: conf
        emptyDir: {}
      - name: config-map
        configMap:
          name: mysql
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 10Gi
StatefulSet.yaml

 

問題調試

    volumes字段屬於Pod對象的
    volumesMount字段屬於容器對象的
    volumeClaimTemplates字段屬於StatefulSet對象的

   - name: MYSQL_ALLOW_EMPTY_PASSWORD
   value: "1" 不能寫成value: 1 必須加上雙引號 否則會出現異常

   CrashLoopBackOff狀態   查看Pod中指定容器的日志信息
     kubectl   logs   mysql-0  init-mysql
     kubectl   logs   mysql-0  clone-mysql
     kubectl   logs   mysql-0  mysql
     kubectl   logs   mysql-0  xtrabackup

  Pending狀態
     kubectl describe pod mysql-2   一般是pod調度失敗

流程分析2

   1.安裝好MySQL的Master節點之后需要做的第一步工作就是通過XtraBackup將Master 節點的數據備份到指定目錄.這一步會自動在目標目錄里生成一個備份信息文件名叫:xtrabackup_binlog_info.這兩個信息會在接下來配置Slave節點的時候用到
   2.配置第一個Slave節點.Slave節點在第一次啟動前需要先把Master節點的備份數據,連同備份信息文件一起拷貝到自己的數據目錄(/var/lib/mysql)
   3.啟動第一個Slave節點它會使用備份信息文件中的二進制日志文件和偏移量,與主節點進行數據同步
   4.在這個集群中添加更多的Slave節點新添加的Slave節點的備份數據來自於已經存在的Slave節點我們需要將Slave節點的數據備份在指定目錄.而這個備份操作會自動生成另一種備份信息文件,名叫:xtrabackup_slave_info.我們就可以執行跟前面一樣的“CHANGE MASTER TO”和“START SLAVE”指令,來初始化並啟動這個新的Slave節點

   5.當master發生異常Pod在重啟的時候保證數據的安全性

       mysql主節點在重啟的時候當有寫請求提交過來時可以拋出異常提示用戶服務暫時不可用(提示下單失敗) 過一段時間后再進行訪問

 

  根據提示錯誤的行數信息 發現volumeMounts這個字段定義的時候縮進沒有和容器定義進行對齊 導致json解析異常.把yaml中的縮進對齊即可


免責聲明!

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



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