kubernetes存儲卷:
咱們知道默認狀況下容器的數據都是非持久化的,在容器銷燬之後數據也跟着丟失,因此docker提供了volume機制以便將數據持久化存儲。相似的,k8s提供了更強大的volume機制和豐富的插件,解決了容器數據持久化和容器間共享數據的問題。html
volume:
咱們常常會說:容器和 Pod 是短暫的。
其含義是它們的生命週期可能很短,會被頻繁地銷燬和建立。容器銷燬時,保存在容器內部文件系統中的數據都會被清除。爲了持久化保存容器的數據,可使用k8s volume。
Volume 的生命週期獨立於容器,Pod 中的容器可能被銷燬和重建,但 Volume 會被保留。node
k8s支持的volume類型有emptydir,hostpath,persistentVolumeClaim,gcePersistentDisk,awsElasticBlockStore,nfs,iscsi,gitRepo,secret等等,完整列表及詳細文檔可參考 http://docs.kubernetes.org.cn/429.html。mysql
在本文中主要實踐如下幾種volume類型:git
1,EmptyDir(臨時存儲):
emptyDir 是最基礎的 Volume 類型。正如其名字所示,一個 emptyDir Volume 是 Host 上的一個空目錄。也就是宿主機上沒有指定的目錄或文件,直接由pod內部映射到宿主機上。(相似於docker中的docker manager volume 掛載方式)sql
咱們經過下面的例子來實踐emptydir:docker
[root@master yaml]# vim emptydir.yaml apiVersion: v1 kind: Pod metadata: name: read-write spec: containers: - name: write image: busybox volumeMounts: #定義數據持久化 - mountPath: /write #定義掛載目錄,該目錄是pod內部的目錄 name: share-volume args: - /bin/sh - -c - echo "hello volumes" > /write/hello; sleep 3000; - name: read #在該pod內定義第二個容器 image: busybox volumeMounts: - mountPath: /read name: share-volume args: - /bin/sh - -c - cat /read/hello; sleep 30000; volumes: - name: share-volume emptyDir: {} #定義一個數據持久化的類型empytdir
咱們模擬一個pod裏運行了兩個容器,兩個容器共享一個volume,一個負責寫入數據,一個負責讀取數據。數據庫
//運行該pod, 並進行查看: [root@master yaml]# kubectl apply -f emptydir.yaml pod/read-write created
[root@master yaml]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES read-write 2/2 Running 0 14s 10.244.2.2 node02 <none> <none>
//咱們分別查看兩個容器中的掛載內容: [root@master yaml]# kubectl exec -it read-write -c read cat /read/hello hello volumes [root@master yaml]# kubectl exec -it read-write -c write cat /write/hello hello volumes
參數解釋:
-c :爲指定某個容器,是--container= 的縮寫,能夠經過--help進行查看。vim
由於 emptyDir 是 Docker Host 文件系統裏的目錄,其效果至關於執行了 docker run -v /write 和 docker run -v /read。咱們在node02
上經過 docker inspect 分別查看容器的詳細配置信息,咱們發現兩個容器都 mount 了同一個目錄:api
"Mounts": [ { "Type": "bind", "Source": "/var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume", "Destination": "/read", "Mode": "", "RW": true, "Propagation": "rprivate" }, { "Type": "bind", "Source": "/var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume", "Destination": "/write", "Mode": "", "RW": true, "Propagation": "rprivate" },
這裏的"/var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume"就是emptydir 掛載到dockerhost上的真正路徑。
因此咱們能夠進入到該路徑下進行查看:服務器
[root@node02 ~]# cd /var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume/ [root@node02 share-volume]# cat hello hello volumes
總結emptydir:
同個pod裏邊的不一樣容器,共享同一個持久化目錄。當pod節點刪除時,volume的內容也會被刪除,但若是僅是容器被銷燬,pod還在,則volume不受影響。也就是說emptydir的數據持久化的生命週期和使用的pod一致。通常做爲臨時存儲使用,以及長時間任務的中間過程checkpoint的臨時保存目錄,及多容器共享目錄。
好比 kube-apiserver 和 kube-controller-manager 就是這樣的應用。
咱們經過"kubectl edit -n kube-system pod kube-apiserver-master"命令來查看 kube-apiserver Pod 的配置,下面是 Volume 的相關部分:
volumeMounts: - mountPath: /etc/ssl/certs name: ca-certs readOnly: true - mountPath: /etc/pki name: etc-pki readOnly: true - mountPath: /etc/kubernetes/pki name: k8s-certs readOnly: true
volumes: - hostPath: path: /etc/ssl/certs type: DirectoryOrCreate name: ca-certs - hostPath: path: /etc/pki type: DirectoryOrCreate name: etc-pki - hostPath: path: /etc/kubernetes/pki type: DirectoryOrCreate name: k8s-certs
這裏定義了三個 hostPath volume 分別是k8s-certs、ca-certs 和etc- pki,分別對應 Host 目錄 /etc/kubernetes/pki、/etc/ssl/certs 和 /etc/pki。
若是 Pod 被銷燬了,hostPath 對應的目錄也還會被保留,從這點看,hostPath 的持久性比 emptyDir 強。不過一旦 Host 崩潰,hostPath 也就無法訪問了。
NFS PersistentVolume
經過 NFS 實踐PV和PVC。
1)咱們在master節點上部署nfs服務:
[root@master ~]# yum -y install nfs-utils [root@master ~]# mkdir /nfsdata [root@master ~]# vim /etc/exports #編寫nfs配置文件 /nfsdata 172.16.1.0/24(rw,sync,no_root_squash) [root@master ~]# systemctl enable rpcbind [root@master ~]# systemctl start rpcbind [root@master ~]# systemctl enable nfs-server [root@master ~]# systemctl start nfs-server
[root@master ~]# showmount -e #查看是否掛載成功 Export list for master: /nfsdata 172.16.1.0/24
2)建立pv:
[root@master yaml]# vim nfs-pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Recycle storageClassName: nfs nfs: path: /nfsdata #指定nfs共享目錄 server: 172.16.1.30 #指定的是nfs服務器的ip地址
//經過如下命令來運行pv: [root@master yaml]# kubectl apply -f nfs-pv.yaml persistentvolume/nfs-pv created
字段解釋: capacity:指定pv的容量大小,目前,capacity僅支持空間設定,未來應該還能夠指定IOPS和throughput。 accessModes:訪問模式,有如下幾種模式: ReadWriteOnce: 以讀寫的方式掛載到單個節點,命令行中簡寫爲RWO。 ReadOnlyMany:以只讀的方式掛載到多個節點,命令行中簡寫爲ROX。 ReadWriteMany: 以讀寫的方式掛載到多個節點,命令行中簡寫爲RWX。 persistentVolumeReclaimPolicy:pv空間釋放時的回收策略,有如下幾種策略: Recycle:清除pv中的數據,而後自動回收。(自動回收策略是由pvc的保護機制保護的,當pv刪除後,只要pvc還在數據就還在) Retain: 保持不動,由管理員手動回收。 Delete: 刪除雲存儲資源,僅部分雲儲存系統支持,若是AWS,EBS,GCE PD,Azure Disk和Cinder。 注意:這裏的回收策略是指在pv被刪除以後,所存儲的源文件是否刪除。 storageClassName:pv和pvc關聯的依據。
//驗證pv是否可用: [root@master yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-pv 1Gi (容量爲1GB) RWO (讀寫) Recycle (自動回收) Available(可用的,確保是該狀態纔可被使用) nfs(基於nfs來作的) 18m(時間)
3)建立一個pvc:
[root@master yaml]# vim nfs-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteOnce #pv和pvc的訪問模式必須一致 resources: #在該字段下的requests子字段中定義要申請的資源 requests: storage: 1Gi storageClassName: nfs
運行該pvc: [root@master yaml]# kubectl apply -f nfs-pvc.yaml persistentvolumeclaim/nfs-pvc created
//驗證pvc是否可用: [root@master yaml]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-pvc Bound nfs-pv 1Gi RWO nfs 3m53s [root@master yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-pv 1Gi RWO Recycle Bound default/nfs-pvc nfs 29m
確保此時pv和pvc的狀態都爲Bound,則表示綁定成功。
接下來咱們實踐mysql的pv使用:
1)建立一個mysql的pod:
[root@master yaml]# vim mysql-pod.yaml apiVersion: extensions/v1beta1 kind: Deployment metadata: name: mysql spec: template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.7 env: #定義一個變量,將容器中mysqlroot密碼映射到本地 - name: MYSQL_ROOT_PASSWORD value: 123.com #密碼爲123.com ports: - containerPort: 3306 volumeMounts: #定義數據持久化 - name: mysql-pv-storage mountPath: /var/lib/mysql #該目錄爲默認的mysql數據持久化目錄 volumes: #該volumes字段爲上面的一個解釋 - name: mysql-pv-storage #注意名稱要與上面的名稱相同 persistentVolumeClaim: #指定pvc,注意下面聲明的pvc要於以前建立的pvc名稱一致 claimName: nfs-pvc --- apiVersion: v1 #建立一個service資源對象 kind: Service metadata: name: mysql spec: type: NodePort ports: - port: 3306 targetPort: 3306 nodePort: 30000 selector: app: mysql
經過如下命令來運行pod: [root@master yaml]# kubectl apply -f mysql-pod.yaml deployment.extensions/mysql created service/mysql created
//查看pod是否正常運行: [root@master yaml]# kubectl get pod -o wide mysql-68d65b9dd9-hf2bf NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mysql-68d65b9dd9-hf2bf 1/1 Running 0 9m34s 10.244.1.3 node01 <none> <none>
2)登陸mysql數據庫,進行寫入數據:
[root@master yaml]# kubectl exec -it mysql-68d65b9dd9-hf2bf -- mysql -u root -p123.com Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
mysql> create database volumes_db; #建立庫 Query OK, 1 row affected (0.01 sec) mysql> use volumes_db; #進入庫中 Database changed mysql> create table my_id( #建立表 -> id int primary key, -> name varchar(25) -> ); Query OK, 0 rows affected (0.04 sec) mysql> insert into my_id values(1,'zhangsan'); #往表中寫入數據 Query OK, 1 row affected (0.01 sec) mysql> select * from my_id; #查看數據 +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.00 sec)
3)進行驗證:
(1)手動刪除pod,驗證數據庫內數據是否還會存在
[root@master ~]# kubectl delete pod mysql-68d65b9dd9-hf2bf pod "mysql-68d65b9dd9-hf2bf" deleted
[root@master ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mysql-68d65b9dd9-bf9v8 1/1 Running 0 26s 10.244.1.4 node01 <none> <none>
刪除pod後,kubernetes會生成新的pod,咱們登陸mysql查看
數據是否還會存在。
[root@master ~]# kubectl exec -it mysql-68d65b9dd9-bf9v8 -- mysql -u root -p123.com Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> select * from volumes_db.my_id; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.01 sec)
能夠看到數據依舊會存在。
2)模擬pod運行所在節點宕機,在新生成的pod內,數據是否恢復正常。
從上面查看pod的信息中,咱們知道pod是運行在node01上,因此咱們將集羣中的node01主機關機。
##[root@node01 ~]# systemctl poweroff
過一段時間後,kubernetes會將pod遷移至集羣中node02主機上:
[root@master ~]# kubectl get nodes #得知node01節點已經宕機 NAME STATUS ROLES AGE VERSION master Ready master 39d v1.15.0 node01 NotReady <none> 39d v1.15.0 node02 Ready <none> 39d v1.15.0
[root@master ~]# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES mysql-68d65b9dd9-bf9v8 1/1 Terminating 0 15m 10.244.1.4 node01 <none> <none> mysql-68d65b9dd9-mvxdg 1/1 Running 0 83s 10.244.2.3 node02 <none> <none>
能夠看到pod已經遷移到了node02上。
最後咱們登陸mysql,驗證數據是否恢復:
[root@master ~]# kubectl exec -it mysql-68d65b9dd9-mvxdg -- mysql -u root -p123.com Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> select * from volumes_db.my_id; +----+----------+ | id | name | +----+----------+ | 1 | zhangsan | +----+----------+ 1 row in set (0.09 sec)
能夠得知在pod遷移以後,mysql服務正常運行,且數據也並無丟失。。。
pv和pvc實現了mysql數據的持久化,分離了管理員和普通用戶的職責,更適合生產環境。