一個替代手工合併檔案的shell指令碼
一、簡介
在Kubernetes系統中,Pod的管理物件RC、Deployment、DaemonSet和Job都面向無狀態的服務。但是有很多服務是有狀態的,特別是一些複雜的中介軟體叢集,例如MySQL叢集、MongoDB叢集、Kafka叢集、zookeeper叢集等,這些應用叢集有4個共同點:
-
每個節點都有固定的身份ID,通過這個ID,叢集中的成員可以相互發現並通訊
-
叢集的規模是比較固定的,叢集規模不能隨意變動
-
叢集中的每個節點都是有狀態的,通常會持久化資料到永久儲存中
-
如果磁碟損壞,則叢集裡的某個節點無法正常執行,叢集功能受損
StatefulSet旨在與有狀態的應用及分散式系統一起使用,它有如下特性:
-
StatefulSet裡每個Pod都有穩定、唯一的網路標識,可以用來發現叢集內的其他成員。假設StatefulSet的名稱為Kafka,那麼第一個Pod叫Kafka-0,第二個叫Kafka-1,以此類推
-
StatefulSet控制的Pod副本啟停順序是受控的,操作第n個Pod時,前n-1個Pod已經是執行且準備好的狀態
-
StatefulSet的Pod採用穩定的持久化儲存卷,通過PV或者PVC來實現,刪除Pod時預設不會刪除與StatefulSet相關的儲存卷
StatefulSet除了要與PV卷捆綁使用以儲存Pod的狀態資料,還要與Headless Service配合使用,即在每個StatefulSet定義中都要宣告它屬於哪個Headless Service。Headless Service於普通Service的關鍵區別在於,它沒有Cluster IP,如果解析Headless Service的DNS域名,則返回的是該Service對應的全部Pod的Endpoint列表。StatefulSet在Headless Service的基礎上又為StatefulSet控制的每個Pod例項建立了一個DNS域名,這個域名格式為: $(podname).$(headless service name)
二、使用StatefulSet搭建MongoDB叢集
為了完成MongoDB叢集的搭建,需要建立如下三個資源物件
-
一個StorageClass,用於StatefulSet自動為各個應用Pod申請PVC
-
一個Headless Service,用於維護MongoDB的叢集狀態
-
一個StatefulSet
2.1建立一個StorageClass物件
storageclass-fast.yaml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast provisioner: kubernetes.io/glusterfs parameters: restful: http://192.168.10.106:18080
執行kubectl create建立該storage class
# kubectl create -f storageclass-fast.yaml
storageclass.storage.k8s.io/fast created
2.2 授權ServiceAccount
在2.4步驟需要使用mongo-sidecar的pod來配置管理mongo pod。
由於預設的service account僅僅只能獲取當前Pod自身的相關屬性,無法觀察到其他名稱空間Pod的相關屬性資訊。如果想要擴充套件Pod,或者一個Pod需要用於管理其他Pod或者是其他資源物件,是無法通過自身的名稱空間的serviceaccount進行獲取其他Pod的相關屬性資訊的,因此需要進行手動建立一個serviceaccount,並在建立Pod時進行定義。或者直接將預設的serviceaccount進行授權。
defaultaccount.yaml
kind: ClusterRoleBinding metadata: name: default-view subjects: - kind: ServiceAccount name: default namespace: default roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io
2.3 建立Headless Service
mongodb-sidecar作為MongoDB叢集的管理者,將使用此Headless Service來維護各個MongoDB例項之間的叢集關係,以及叢集規模變化時的自動更新
mongodb-headless-service.yaml
apiVersion: v1 kind: Service metadata: name: mongo labels: name: mongo spec: ports: - port: 27017 targetPort: 27017 clusterIP: None selector: role: mongo
執行kubectl create命令建立該Headless Service
# kubectl create -f mongodb-headless-service.yaml
service/mongo created
2.4 MongoDB StatefulSet
statefulset-mongo.yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: mongo spec: serviceName: mongo # 宣告它屬於哪個Headless Service replicas: 3 selector: # has to match .sepc.template.metadata.labels matchLabels: role: mongo environment: test template: metadata: labels: # has to match .spec.selector.matchLabels role: mongo environment: test spec: terminationGracePeriodSeconds: 10 containers: - name: mongo image: mongo:3.4 command: - mongod - "--replSet" - rs0 - "--bind_ip" - 0.0.0.0 - "--smallfiles" - "--noprealloc" ports: - containerPort: 27017 volumeMounts: - name: mongo-persistent-storage mountPath: /data/db - name: mongo-sidecar image: cvallance/mongo-k8s-sidecar env: - name: MONGO_SIDECAR_POD_LABELS value: "role=mongo,environment=test" - name: KUBERNETES_MONGO_SERVICE_NAME value: "mongo" volumeClaimTemplates: - metadata: name: mongo-persistent-storage annotations: volume.beta.kubernetes.io/storage-class: "fast" spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 2Gi
其中主要配置說明如下:
(1)在該statefulset定義中包含連個容器:mongo和mongo-sidecar。mongo是主服務程式,mongo-sidecar是將多個mongo例項進行叢集設定的工具。mongo-sidecar中的環境變數如下:
-
MONGO_SIDECAR_POD_LABELS:設定為mongo容器的標籤,用於sidecar查詢它所要管理的MongoDB叢集例項
-
KUBERNETES_MONGO_SERVICE_NAME: 它的值為mongo,表示sidecar將使用mongo這個服務名來完成MongoDB叢集的設定
(2)replicas=3 表示MongoDB叢集由3個mongo例項組成
(3)volumeClaimTemplates是 StatefulSet最重要的儲存設定。在annotations段設定volume.beta.kubernetes.io/storage-class="fast" 表示使用名為fast的StorageClass自動為每個mongo Pod例項分配後端儲存
(4)resources.requests.storage=2Gi 表示為每個mongo例項都分配2G的磁碟空間
2.5 驗證MongoDB叢集
最終可以看到StatefulSet依次建立並啟動了3個mongo Pod例項,它們的名字依次為mongo-0、mongo-1、mongo-2:
# kubectl get pods -l role=mongo NAME READY STATUS RESTARTS AGE mongo-0 2/2 Running 0 72m mongo-1 2/2 Running 0 71m mongo-2 2/2 Running 0 64m
StatefulSet會用volumeClaimTemplates中定義為每個Pod副本都建立一個PVC例項,每個PVC的名稱由StatefulSet定義中volumeClaimTemplates的名稱和Pod副本的名稱組合而成:
# kubectl get pvc -l role=mongo NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mongo-persistent-storage-mongo-0 Bound pvc-63b576fc-1324-46db-b708-0c40f5896103 2Gi RWO fast 86m mongo-persistent-storage-mongo-1 Bound pvc-6b2dfbc3-f57e-4e05-9cd7-dfabb3c5b00e 2Gi RWO fast 75m mongo-persistent-storage-mongo-2 Bound pvc-24ed1a31-b9a8-4214-a189-137cf9eccc12 2Gi RWO fast 67m
下面是mongo-0這個Pod中volume設定,可以看到系統自動為其掛載了對應的PVC:
# kubectl get pod mongo-0 -o yaml | grep -A 3 volumes volumes: - name: mongo-persistent-storage persistentVolumeClaim: claimName: mongo-persistent-storage-mongo-0
登入任意一個mongo Pod,在mongo命令列介面使用rs.status()命令檢視MongoDB叢集狀態,該mongodb叢集已由sidecar完成了建立。在叢集中包含3個節點的名稱都是StatefulSet設定的DNS域名格式的網路標識名稱:
mongo-0.mongo.default.svc.cluster.local mongo-1.mongo.default.svc.cluster.local mongo-2.mongo.default.svc.cluster.local
同時,可以檢視每個mongodb例項的各自角色(PRIMARY或SECONDARY)
rs.status() ... ... ... "members" : [ { "_id" : 0, "name" : "mongo-0.mongo.default.svc.cluster.local:27017", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 100, "optime" : { "ts" : Timestamp(1592286258, 1), "t" : NumberLong(1) }, "optimeDate" : ISODate("2020-06-16T05:44:18Z"), "syncingTo" : "", "syncSourceHost" : "", "syncSourceId" : -1, "infoMessage" : "could not find member to sync from", "electionTime" : Timestamp(1592286196, 2), "electionDate" : ISODate("2020-06-16T05:43:16Z"), "configVersion" : 5, "self" : true, "lastHeartbeatMessage" : "" }, { "_id" : 1, "name" : "mongo-1.mongo.default.svc.cluster.local:27017", "health" : 1, "state" : 2, "stateStr" : "SECONDARY", "uptime" : 45, "optime" : {
...
...