在K8s中建立StatefulSet
遇到的問題:
使用Deployment建立的Pod是無狀態的,當掛在Volume之後,如果該Pod掛了,Replication Controller會再run一個來保證可用性,但是由於是無狀態的,Pod掛了的時候與之前的Volume的關係就已經斷開了,新起來的Pod無法找到之前的Pod。但是對於使用者而言,他們對底層的Pod掛了沒有感知,但是當Pod掛了之後就無法再使用之前掛載的磁碟了。
解決方案
使用K8s v1.5版本推出的StatefulSet可以保留Pod的狀態。
參考部落格
因為Kubernetes1.5版本釋出也沒過多久,國內的資料相當的少,除了tonybai等大牛部落格上有一些StatefulSet的資料外,只能去外網上搜索了。通過在google上搜索StatefulSet的建立方式,最終發現了一篇英文部落格,連結如下。對於這種新興框架,還是要多去google啊。
ofollow,noindex" target="_blank">https://thenewstack.io/deploy-highly-available-wordpress-instance-statefulset-kubernetes-1-5/
如何建立
在建立StatefulSet之前需要準備的東西,值得注意的是建立順序非常關鍵,建立順序如下:
- 1、Volume
- 2、Persistent Volume
- 3、Persistent Volume Claim
- 4、Service
- 5、StatefulSet
Volume可以有很多種型別,比如nfs、glusterfs等,我們這裡使用的ceph RBD來建立。
建立Volume
sudo rbd create {volume_name} --size 1024 -m {ceph-monitor-ip} -k /etc/ceph/ceph.client.admin.keyring //禁止掉一些rdb的feature,否則掛載會失敗 rbd feature disable volume101 exclusive-lock, object-map, fast-diff, deep-flatten
建立PersistentVolume
建立pv.yaml,內容如下:
apiVersion: v1 kind: PersistentVolume metadata: name: {pv_name} labels: {label_key}:{label_value} spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce rbd: monitors: - {ceph-monitor-ip} pool: rbd image: {volume_name} user: admin secretRef: name: ceph-secret fsType: ext4 readOnly: false persistentVolumeReclaimPolicy: Recycle
使用
kubectl create -f pv.yaml
來建立PV。
建立PersistentVolumeClaim
這一步非常非常的關鍵,因為如果建立的PVC的名稱和StatefulSet中的名稱沒有對應上,那麼StatefulSet中的Pod就肯定建立不成功,我在這一步被卡了一天之久,還好看到上面那篇外文部落格,才發現PVC和StatefulSet中的命名的規律。接下來細說一下需要注意的地方。
建立pvc.yaml如下:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: db-mysql-0 spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi
我們在這裡建立了一個叫做db-mysql-0 的PVC,這個名字是不是很奇怪,而且在這個yaml裡並沒有提到PV的名字,所以PV和PVC是怎麼bound起來的呢?是通過labels標籤下的key:value鍵值對來進行匹配的,我們在建立PV時指定了label的鍵值對,在PVC裡通過selector可以指定label。
然後再回到這個PVC的名稱定義:db-mysql-0 ,為什麼叫這樣一個看似有規律的名字呢,這裡需要看一下下一小節建立StatefulSet中的yaml,首先我們看到StatefulSet的name叫mysql ,設定的replicas為2個,volumeMounts和volumeClaimTemplates的name必須相同,為db ,所以StatefulSet建立的第一個Pod的name應該為mysql-0 ,第二個為mysql-1 。這裡StatefulSet中的Pod與PVC之間的繫結關係是通過名稱來匹配的,即:
PVC_name === volumeClaimTemplates_name + "-" + pod_name
所以這個問題就有點意思了,我們要先建立PVC,但是PVC的名稱實際上是由StatefulSet來確定的。我真的是不知道K8S設計者咋想的·····而且官方文件裡建立StatefulSet的例子是直接給了個yaml檔案,並沒有告訴說要先建立什麼再建立什麼。
建立Service 和 StatefulSet
在上一步中我們已經建立了名為db-mysql-0 的PVC了,接下來建立一個service和statefulset,service的名稱可以隨意取,但是statefulset的名稱已經定死了,為mysql ,並且statefulset中的volumeClaimTemplates_name必須為db ,volumeMounts_name也必須為db 。只有這樣,statefulset中的pod才能通過命名來匹配到PVC,否則會建立失敗。
statefulset.yaml
apiVersion: v1 kind: Service metadata: name: mysql-service labels: app: mysql spec: ports: - port: 80 name: my-port clusterIP: None selector: app: mysql --- apiVersion: apps/v1beta1 kind: StatefulSet metadata: name: mysql spec: serviceName: "mysql-service" replicas: 2 template: metadata: labels: app: mysql spec: terminationGracePeriodSeconds: 10 containers: - name: mysqlpod image: mysql:latest ports: - containerPort: 80 name: my-port volumeMounts: - name: db mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: db spec: accessModes: [ "ReadWriteOnce" ] resources: requests: storage: 1Gi
執行以下命令:
kubectl create -f statefulset.yaml
就可以建立statefulset了。
本文轉自中文社群-在K8s中建立StatefulSet