iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 13
0
Kubernetes

Kubernetes~成為Devops工程師的必經試煉系列 第 13

Day 13 Kubernetes 中處理有狀態 Container 如何運作 ~StatefulSets

前言

當要架設到 Kubernates 需要以有狀態系統的方式設計時,可以考慮使用 StatefulSets。
例如:Deploy 需要依循一定的順序等等。
這邊我們用 ZooKeeper 做一個簡單的示範

ZooKeeper 基礎

本篇教學就不詳述ZooKeeper的所有功能了,Apache ZooKeeper 是一個開源的協調開源的分散式協調服務。 ZooKeeper 允許你讀取、寫入數據和發現資料更新。資料按其結構組織在檔案系統中,複製到 ensemble(一個 ZooKeeper 服務的集合) 中所有的 ZooKeeper 服務。對資料的所有操作都是原子的和順序一致的。 ZooKeeper 通過 Zab 一致性協議在 ensemble 的所有服務之間複製一個狀態來確保這個特性。

ensemble 使用 Zab 協議選舉一個 leader,在選舉出 leader 前不能寫入數據。一旦選舉出了 leader,ensemble 使用 Zab 保證所有寫入被複製到一個 quorum,然後這些寫入操作才會被確認並對客戶端可用。如果沒有遵照加權 quorums,一個 quorum 表示包含當前 leader 的 ensemble 的多數成員。例如,如果 ensemble 有3個服務,一個包含 leader 的成員和另一個服務就組成了一個 quorum。如果 ensemble 不能達成一個 quorum,數據將不能被寫入。

ZooKeeper 在記憶體中存著它們的所有的狀態,但是每個改變都被寫入一個在存儲介質上的持久 WAL(Write Ahead Log)。當一個服務故障時,它能夠通過回放 WAL 恢復之前的狀態。為了防止 WAL 無限制的增長,ZooKeeper 服務會定期的將內存狀態快照保存到存儲介質。這些快照能夠直接加載到內存中,所有在這個快照之前的 WAL 條目都可以被安全的丟棄。

實際操作

首先我們建立一個 包含有ZooKeeper

apiVersion: v1
kind: Service
metadata:
  name: zk-headless
  labels:
    app: zk-headless
spec:
  ports:
  - port: 2888
    name: server
  - port: 3888
    name: leader-election
  clusterIP: None
  selector:
    app: zk
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: zk-config
data:
  ensemble: "zk-0;zk-1;zk-2"
  jvm.heap: "2G"
  tick: "2000"
  init: "10"
  sync: "5"
  client.cnxns: "60"
  snap.retain: "3"
  purge.interval: "1"
---
apiVersion: policy/v1beta1
kind: PodDisruptionBudget
metadata:
  name: zk-budget
spec:
  selector:
    matchLabels:
      app: zk
  minAvailable: 2
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: zk
spec:
  serviceName: zk-headless
  replicas: 3
  template:
    metadata:
      labels:
        app: zk
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
        
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values: 
                    - zk-headless
              topologyKey: "kubernetes.io/hostname"
      containers:
      - name: k8szk
        imagePullPolicy: Always
        image: gcr.io/google_samples/k8szk:v1
        resources:
          requests:
            memory: "4Gi"
            cpu: "1"
        ports:
        - containerPort: 2181
          name: client
        - containerPort: 2888
          name: server
        - containerPort: 3888
          name: leader-election
        env:
        - name : ZK_ENSEMBLE
          valueFrom:
            configMapKeyRef:
              name: zk-config
              key: ensemble
        - name : ZK_HEAP_SIZE
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: jvm.heap
        - name : ZK_TICK_TIME
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: tick
        - name : ZK_INIT_LIMIT
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: init
        - name : ZK_SYNC_LIMIT
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: tick
        - name : ZK_MAX_CLIENT_CNXNS
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: client.cnxns
        - name: ZK_SNAP_RETAIN_COUNT
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: snap.retain
        - name: ZK_PURGE_INTERVAL
          valueFrom:
            configMapKeyRef:
                name: zk-config
                key: purge.interval
        - name: ZK_CLIENT_PORT
          value: "2181"
        - name: ZK_SERVER_PORT
          value: "2888"
        - name: ZK_ELECTION_PORT
          value: "3888"
        command:
        - sh
        - -c
        - zkGenConfig.sh && zkServer.sh start-foreground
        readinessProbe:
          exec:
            command:
            - "zkOk.sh"
          initialDelaySeconds: 15
          timeoutSeconds: 5
        livenessProbe:
          exec:
            command:
            - "zkOk.sh"
          initialDelaySeconds: 15
          timeoutSeconds: 5
        volumeMounts:
        - name: datadir
          mountPath: /var/lib/zookeeper
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 20Gi

輸入以下指令開始建立 Zookeeper

$ kubectl create -f https://k8s.io/docs/tutorials/stateful-application/zookeeper.yaml

上述指令建立了 zk-headless Headless Service、zk-config ConfigMap、zk-budget PodDisruptionBudget 和 zk StatefulSet。

service "zk-headless" created
configmap "zk-config" created
poddisruptionbudget "zk-budget" created
statefulset "zk" created

在使用 kubectl get 查看 StatefulSet 建立的 Pods。

$ kubectl get pods -w -l app=zk
NAME      READY     STATUS    RESTARTS   AGE
zk-0      0/1       Pending   0          0s
zk-0      0/1       Pending   0         0s
zk-0      0/1       ContainerCreating   0         0s
zk-0      0/1       Running   0         19s
zk-0      1/1       Running   0         40s
zk-1      0/1       Pending   0         0s
zk-1      0/1       Pending   0         0s
zk-1      0/1       ContainerCreating   0         0s
zk-1      0/1       Running   0         18s
zk-1      1/1       Running   0         40s
zk-2      0/1       Pending   0         0s
zk-2      0/1       Pending   0         0s
zk-2      0/1       ContainerCreating   0         0s
zk-2      0/1       Running   0         19s
zk-2      1/1       Running   0         40s

觸發 ZooKeep 中的 Leader

由於ZooKeeper 的 leader 功能 無法在Private Network中停止,因為Zab 要求顯式的進行成員關係配置,以執行 leader 選舉,因此 Ensemble 中的每個服務都需要具有一個獨一無二的標識符,所有的服務均需要知道標識符的全集,並且每個label 都需要和一個IP相關聯。

$ for i in 0 1 2; do kubectl exec zk-$i -- hostname; done
zk-0
zk-1
zk-2

ZooKeeper ensemble 中的服務使用自然數作為唯一標識符,每個服務的標識符都保存在服務的數據目錄中一個名為 myid 的文件裡。
檢查每個服務的 myid 文件的內容。

$ for i in 0 1 2; do echo "myid zk-$i";kubectl exec zk-$i -- cat /var/lib/zookeeper/data/myid; done

參考連結

  1. Wiki Apache ZooKeeper
  2. 运行 ZooKeeper, 一个 CP 分布式系统

上一篇
Day 12 用來協調Deployment的中介者 ReplicaSets
下一篇
Day 14 檢查 Kubernetes 中 Pod的健康狀態 ~Health Check
系列文
Kubernetes~成為Devops工程師的必經試煉17
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言