目錄html
爲了保證數據的持久性,必須保證數據在外部存儲在
docker
容器中,爲了實現數據的持久性存儲,在宿主機和容器內作映射,能夠保證在容器的生命週期結束,數據依舊能夠實現持久性存儲。可是在k8s
中,因爲pod
分佈在各個不一樣的節點之上,並不能實現不一樣節點之間持久性數據的共享,而且,在節點故障時,可能會致使數據的永久性丟失。爲此,k8s
就引入了外部存儲卷的功能。
k8s的存儲卷類型:node
[root@k8s-master ~]# kubectl explain pod.spec.volumes #查看k8s支持的存儲類型 KIND: Pod VERSION: v1 經常使用分類: emptyDir(臨時目錄):Pod刪除,數據也會被清除,這種存儲成爲emptyDir,用於數據的臨時存儲。 hostPath(宿主機目錄映射): 本地的SAN(iSCSI,FC)、NAS(nfs,cifs,http)存儲 分佈式存儲(glusterfs,rbd,cephfs) 雲存儲(EBS,Azure Disk)
persistentVolumeClaim -->PVC(存儲卷建立申請)
當你須要建立一個存儲卷時,只須要進行申請對應的存儲空間便可使用,這就是PVC。其關聯關係如圖:nginx
上圖解析:在Pod上定義一個PVC,該PVC要關聯到當前名稱空間的PVC資源,該PVC只是一個申請,PVC須要和PV進行關聯。PV屬於存儲上的一部分存儲空間。可是該方案存在的問題是,咱們沒法知道用戶是何時去建立Pod,也不知道建立Pod時定義多大的PVC,那麼如何實現按需建立呢???web
不須要PV層,把全部存儲空間抽象出來,這一個抽象層稱爲存儲類,當用戶建立PVC須要用到PV時,能夠向存儲類申請對應的存儲空間,存儲類會按照需求建立對應的存儲空間,這就是PV的動態供給,如圖:docker
那麼PV的動態供給,其重點是在存儲類的定義,其分類大概是對存儲的性能進行分類的,如圖:金存儲類、銀存儲類、銅存儲類等。json
總結:
k8s要使用存儲卷,須要2步:
一、在pod定義volume,並指明關聯到哪一個存儲設備
二、在容器使用volume mount進行掛載vim
一個emptyDir 第一次建立是在一個pod被指定到具體node的時候,而且會一直存在在pod的生命週期當中,正如它的名字同樣,它初始化是一個空的目錄,pod中的容器均可以讀寫這個目錄,這個目錄能夠被掛在到各個容器相同或者不相同的的路徑下。當一個pod由於任何緣由被移除的時候,這些數據會被永久刪除。注意:一個容器崩潰了不會致使數據的丟失,由於容器的崩潰並不移除pod.後端
emptyDir 磁盤的做用:
(1)普通空間,基於磁盤的數據存儲
(2)做爲從崩潰中恢復的備份點
(3)存儲那些那些須要長久保存的數據,例web服務中的數據
默認的,emptyDir 磁盤會存儲在主機所使用的媒介上,多是SSD,或者網絡硬盤,這主要取決於你的環境。固然,咱們也能夠將emptyDir.medium的值設置爲Memory來告訴Kubernetes 來掛在一個基於內存的目錄tmpfs,由於
tmpfs速度會比硬盤塊度了,可是,當主機重啓的時候全部的數據都會丟失。api
[root@k8s-master ~]# kubectl explain pods.spec.volumes.emptyDir #查看emptyDir存儲定義 [root@k8s-master ~]# kubectl explain pods.spec.containers.volumeMounts #查看容器掛載方式 [root@k8s-master ~]# cd mainfests && mkdir volumes && cd volumes [root@k8s-master volumes]# cp ../pod-demo.yaml ./ [root@k8s-master volumes]# mv pod-demo.yaml pod-vol-demo.yaml [root@k8s-master volumes]# vim pod-vol-demo.yaml #建立emptyDir的清單 apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default labels: app: myapp tier: frontend annotations: magedu.com/create-by:"cluster admin" spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: #在容器內定義掛載存儲名稱和掛載路徑 - name: html mountPath: /usr/share/nginx/html/ - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /data/ #在容器內定義掛載存儲名稱和掛載路徑 command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done'] volumes: #定義存儲卷 - name: html #定義存儲卷名稱 emptyDir: {} #定義存儲卷類型 [root@k8s-master volumes]# kubectl apply -f pod-vol-demo.yaml pod/pod-vol-demo created [root@k8s-master volumes]# kubectl get pods NAME READY STATUS RESTARTS AGE pod-vol-demo 2/2 Running 0 27s [root@k8s-master volumes]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE ...... pod-vol-demo 2/2 Running 0 16s 10.244.2.34 k8s-node02 ...... 在上面,咱們定義了2個容器,其中一個容器是輸入日期到index.html中,而後驗證訪問nginx的html是否能夠獲取日期。以驗證兩個容器之間掛載的emptyDir實現共享。以下訪問驗證: [root@k8s-master volumes]# curl 10.244.2.34 #訪問驗證 Tue Oct 9 03:56:53 UTC 2018 Tue Oct 9 03:56:55 UTC 2018 Tue Oct 9 03:56:57 UTC 2018 Tue Oct 9 03:56:59 UTC 2018 Tue Oct 9 03:57:01 UTC 2018 Tue Oct 9 03:57:03 UTC 2018 Tue Oct 9 03:57:05 UTC 2018 Tue Oct 9 03:57:07 UTC 2018 Tue Oct 9 03:57:09 UTC 2018 Tue Oct 9 03:57:11 UTC 2018 Tue Oct 9 03:57:13 UTC 2018 Tue Oct 9 03:57:15 UTC 2018
hostPath宿主機路徑,就是把pod所在的宿主機之上的脫離pod中的容器名稱空間的以外的宿主機的文件系統的某一目錄和pod創建關聯關係,在pod刪除時,存儲數據不會丟失。服務器
(1)查看hostPath存儲類型定義 [root@k8s-master volumes]# kubectl explain pods.spec.volumes.hostPath KIND: Pod VERSION: v1 RESOURCE: hostPath <Object> DESCRIPTION: HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath Represents a host path mapped into a pod. Host path volumes do not support ownership management or SELinux relabeling. FIELDS: path <string> -required- #指定宿主機的路徑 Path of the directory on the host. If the path is a symlink, it will follow the link to the real path. More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath type <string> Type for HostPath Volume Defaults to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath type: DirectoryOrCreate 宿主機上不存在建立此目錄 Directory 必須存在掛載目錄 FileOrCreate 宿主機上不存在掛載文件就建立 File 必須存在文件 (2)清單定義 [root@k8s-master volumes]# vim pod-hostpath-vol.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-hostpath namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html hostPath: path: /data/pod/volume1 type: DirectoryOrCreate (3)在node節點上建立掛載目錄 [root@k8s-node01 ~]# mkdir -p /data/pod/volume1 [root@k8s-node01 ~]# vim /data/pod/volume1/index.html node01.magedu.com [root@k8s-node02 ~]# mkdir -p /data/pod/volume1 [root@k8s-node02 ~]# vim /data/pod/volume1/index.html node02.magedu.com [root@k8s-master volumes]# kubectl apply -f pod-hostpath-vol.yaml pod/pod-vol-hostpath created (4)訪問測試 [root@k8s-master volumes]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE ...... pod-vol-hostpath 1/1 Running 0 37s 10.244.2.35 k8s-node02 ...... [root@k8s-master volumes]# curl 10.244.2.35 node02.magedu.com [root@k8s-master volumes]# kubectl delete -f pod-hostpath-vol.yaml #刪除pod,再重建,驗證是否依舊能夠訪問原來的內容 [root@k8s-master volumes]# kubectl apply -f pod-hostpath-vol.yaml pod/pod-vol-hostpath created [root@k8s-master volumes]# curl 10.244.2.37 node02.magedu.com
hostPath能夠實現持久存儲,可是在node節點故障時,也會致使數據的丟失
nfs使的咱們能夠掛在已經存在的共享到的咱們的Pod中,和emptyDir不一樣的是,emptyDir會被刪除當咱們的Pod被刪除的時候,可是nfs不會被刪除,僅僅是解除掛在狀態而已,這就意味着NFS可以容許咱們提早對數據進行處理,並且這些數據能夠在Pod之間相互傳遞.而且,nfs能夠同時被多個pod掛在並進行讀寫
注意:必須先報紙NFS服務器正常運行在咱們進行掛在nfs的時候
(1)在stor01節點上安裝nfs,並配置nfs服務 [root@stor01 ~]# yum install -y nfs-utils ==》192.168.56.14 [root@stor01 ~]# mkdir /data/volumes -pv [root@stor01 ~]# vim /etc/exports /data/volumes 192.168.56.0/24(rw,no_root_squash) [root@stor01 ~]# systemctl start nfs [root@stor01 ~]# showmount -e Export list for stor01: /data/volumes 192.168.56.0/24 (2)在node01和node02節點上安裝nfs-utils,並測試掛載 [root@k8s-node01 ~]# yum install -y nfs-utils [root@k8s-node02 ~]# yum install -y nfs-utils [root@k8s-node02 ~]# mount -t nfs stor01:/data/volumes /mnt [root@k8s-node02 ~]# mount ...... stor01:/data/volumes on /mnt type nfs4 (rw,relatime,vers=4.1,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.56.13,local_lock=none,addr=192.168.56.14) [root@k8s-node02 ~]# umount /mnt/ (3)建立nfs存儲卷的使用清單 [root@k8s-master volumes]# cp pod-hostpath-vol.yaml pod-nfs-vol.yaml [root@k8s-master volumes]# vim pod-nfs-vol.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-nfs namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html nfs: path: /data/volumes server: stor01 [root@k8s-master volumes]# kubectl apply -f pod-nfs-vol.yaml pod/pod-vol-nfs created [root@k8s-master volumes]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-vol-nfs 1/1 Running 0 21s 10.244.2.38 k8s-node02 (3)在nfs服務器上建立index.html [root@stor01 ~]# cd /data/volumes [root@stor01 volumes ~]# vim index.html <h1> nfs stor01</h1> [root@k8s-master volumes]# curl 10.244.2.38 <h1> nfs stor01</h1> [root@k8s-master volumes]# kubectl delete -f pod-nfs-vol.yaml #刪除nfs相關pod,再從新建立,能夠獲得數據的持久化存儲 pod "pod-vol-nfs" deleted [root@k8s-master volumes]# kubectl apply -f pod-nfs-vol.yaml
咱們前面提到kubernetes提供那麼多存儲接口,可是首先kubernetes的各個Node節點能管理這些存儲,可是各類存儲參數也須要專業的存儲工程師才能瞭解,由此咱們的kubernetes管理變的更加複雜的。由此kubernetes提出了PV和PVC的概念,這樣開發人員和使用者就不須要關注後端存儲是什麼,使用什麼參數等問題。以下圖:
PersistentVolume(PV)是集羣中已由管理員配置的一段網絡存儲。 集羣中的資源就像一個節點是一個集羣資源。 PV是諸如卷之類的卷插件,可是具備獨立於使用PV的任何單個pod的生命週期。 該API對象捕獲存儲的實現細節,即NFS,iSCSI或雲提供商特定的存儲系統。
PersistentVolumeClaim(PVC)是用戶存儲的請求。PVC的使用邏輯:在pod中定義一個存儲卷(該存儲卷類型爲PVC),定義的時候直接指定大小,pvc必須與對應的pv創建關係,pvc會根據定義去pv申請,而pv是由存儲空間建立出來的。pv和pvc是kubernetes抽象出來的一種存儲資源。
雖然PersistentVolumeClaims容許用戶使用抽象存儲資源,可是常見的需求是,用戶須要根據不一樣的需求去建立PV,用於不一樣的場景。而此時須要集羣管理員提供不一樣需求的PV,而不只僅是PV的大小和訪問模式,但又不須要用戶瞭解這些卷的實現細節。 對於這樣的需求,此時能夠採用StorageClass資源。這個在前面就已經提到過此方案。
PV是集羣中的資源。 PVC是對這些資源的請求,也是對資源的索賠檢查。 PV和PVC之間的相互做用遵循這個生命週期:
Provisioning(配置)---> Binding(綁定)--->Using(使用)---> Releasing(釋放) ---> Recycling(回收)
這裏有兩種PV的提供方式:靜態或者動態
靜態-->直接固定存儲空間:
集羣管理員建立一些 PV。它們攜帶可供集羣用戶使用的真實存儲的詳細信息。 它們存在於Kubernetes API中,可用於消費。
動態-->經過存儲類進行動態建立存儲空間:
當管理員建立的靜態 PV 都不匹配用戶的 PVC 時,集羣可能會嘗試動態地爲 PVC 配置卷。此配置基於 StorageClasses:PVC 必須請求存儲類,而且管理員必須已建立並配置該類才能進行動態配置。 要求該類的聲明有效地爲本身禁用動態配置。
在動態配置的狀況下,用戶建立或已經建立了具備特定數量的存儲請求和特定訪問模式的PersistentVolumeClaim。 主機中的控制迴路監視新的PVC,找到匹配的PV(若是可能),並將 PVC 和 PV 綁定在一塊兒。 若是爲新的PVC動態配置PV,則循環將始終將該PV綁定到PVC。 不然,用戶老是至少獲得他們要求的內容,可是卷可能超出了要求。 一旦綁定,PersistentVolumeClaim綁定是排他的,無論用於綁定它們的模式。
若是匹配的卷不存在,PVC將保持無限期。 隨着匹配卷變得可用,PVC將被綁定。 例如,提供許多50Gi PV的集羣將不匹配要求100Gi的PVC。 當集羣中添加100Gi PV時,能夠綁定PVC。
Pod使用PVC做爲卷。 集羣檢查聲明以找到綁定的卷並掛載該卷的卷。 對於支持多種訪問模式的卷,用戶在將其聲明用做pod中的卷時指定所需的模式。
一旦用戶有聲明而且該聲明被綁定,綁定的PV屬於用戶,只要他們須要它。 用戶經過在其Pod的卷塊中包含PersistentVolumeClaim來安排Pods並訪問其聲明的PV。
當用戶完成卷時,他們能夠從容許資源回收的API中刪除PVC對象。 當聲明被刪除時,卷被認爲是「釋放的」,可是它還不能用於另外一個聲明。 之前的索賠人的數據仍然保留在必須根據政策處理的捲上.
PersistentVolume的回收策略告訴集羣在釋放其聲明後,該卷應該如何處理。 目前,卷能夠是保留,回收或刪除。 保留能夠手動回收資源。 對於那些支持它的卷插件,刪除將從Kubernetes中刪除PersistentVolume對象,以及刪除外部基礎架構(如AWS EBS,GCE PD,Azure Disk或Cinder卷)中關聯的存儲資產。 動態配置的卷始終被刪除
若是受適當的卷插件支持,回收將對卷執行基本的擦除(rm -rf / thevolume / *),並使其再次可用於新的聲明。
實驗圖以下:
[root@k8s-master ~]# kubectl explain pv #查看pv的定義方式 FIELDS: apiVersion kind metadata spec [root@k8s-master ~]# kubectl explain pv.spec #查看pv定義的規格 spec: nfs(定義存儲類型) path(定義掛載卷路徑) server(定義服務器名稱) accessModes(定義訪問模型,有如下三種訪問模型,以列表的方式存在,也就是說能夠定義多個訪問模式) ReadWriteOnce(RWO) 單節點讀寫 ReadOnlyMany(ROX) 多節點只讀 ReadWriteMany(RWX) 多節點讀寫 capacity(定義PV空間的大小) storage(指定大小) [root@k8s-master volumes]# kubectl explain pvc #查看PVC的定義方式 KIND: PersistentVolumeClaim VERSION: v1 FIELDS: apiVersion <string> kind <string> metadata <Object> spec <Object> [root@k8s-master volumes]# kubectl explain pvc.spec spec: accessModes(定義訪問模式,必須是PV的訪問模式的子集) resources(定義申請資源的大小) requests: storage:
[root@stor01 volumes]# mkdir v{1,2,3,4,5} [root@stor01 volumes]# vim /etc/exports /data/volumes/v1 192.168.56.0/24(rw,no_root_squash) /data/volumes/v2 192.168.56.0/24(rw,no_root_squash) /data/volumes/v3 192.168.56.0/24(rw,no_root_squash) /data/volumes/v4 192.168.56.0/24(rw,no_root_squash) /data/volumes/v5 192.168.56.0/24(rw,no_root_squash) [root@stor01 volumes]# exportfs -arv exporting 192.168.56.0/24:/data/volumes/v5 exporting 192.168.56.0/24:/data/volumes/v4 exporting 192.168.56.0/24:/data/volumes/v3 exporting 192.168.56.0/24:/data/volumes/v2 exporting 192.168.56.0/24:/data/volumes/v1 [root@stor01 volumes]# showmount -e Export list for stor01: /data/volumes/v5 192.168.56.0/24 /data/volumes/v4 192.168.56.0/24 /data/volumes/v3 192.168.56.0/24 /data/volumes/v2 192.168.56.0/24 /data/volumes/v1 192.168.56.0/24
這裏定義5個PV,而且定義掛載的路徑以及訪問模式,還有PV劃分的大小。
[root@k8s-master volumes]# kubectl explain pv [root@k8s-master volumes]# kubectl explain pv.spec.nfs [root@k8s-master volumes]# vim pv-demo.yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv001 labels: name: pv001 spec: nfs: path: /data/volumes/v1 server: stor01 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 1Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv002 labels: name: pv002 spec: nfs: path: /data/volumes/v2 server: stor01 accessModes: ["ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv003 labels: name: pv003 spec: nfs: path: /data/volumes/v3 server: stor01 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv004 labels: name: pv004 spec: nfs: path: /data/volumes/v4 server: stor01 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 4Gi --- apiVersion: v1 kind: PersistentVolume metadata: name: pv005 labels: name: pv005 spec: nfs: path: /data/volumes/v5 server: stor01 accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 5Gi [root@k8s-master volumes]# kubectl apply -f pv-demo.yaml persistentvolume/pv001 created persistentvolume/pv002 created persistentvolume/pv003 created persistentvolume/pv004 created persistentvolume/pv005 created [root@k8s-master volumes]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO,RWX Retain Available 7s pv002 2Gi RWO Retain Available 7s pv003 2Gi RWO,RWX Retain Available 7s pv004 4Gi RWO,RWX Retain Available 7s pv005 5Gi RWO,RWX Retain Available 7s
這裏定義了pvc的訪問模式爲多路讀寫,該訪問模式必須在前面pv定義的訪問模式之中。定義PVC申請的大小爲2Gi,此時PVC會自動去匹配多路讀寫且大小爲2Gi的PV,匹配成功獲取PVC的狀態即爲Bound
[root@k8s-master volumes ~]# vim pod-vol-pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc namespace: default spec: accessModes: ["ReadWriteMany"] resources: requests: storage: 2Gi --- apiVersion: v1 kind: Pod metadata: name: pod-vol-pvc namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html volumes: - name: html persistentVolumeClaim: claimName: mypvc [root@k8s-master volumes]# kubectl apply -f pod-vol-pvc.yaml persistentvolumeclaim/mypvc created pod/pod-vol-pvc created [root@k8s-master volumes]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO,RWX Retain Available 19m pv002 2Gi RWO Retain Available 19m pv003 2Gi RWO,RWX Retain Bound default/mypvc 19m pv004 4Gi RWO,RWX Retain Available 19m pv005 5Gi RWO,RWX Retain Available 19m [root@k8s-master volumes]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mypvc Bound pv003 2Gi RWO,RWX 22s
在存儲服務器上建立index.html,並寫入數據,經過訪問Pod進行查看,能夠獲取到相應的頁面。
[root@stor01 volumes]# cd v3/ [root@stor01 v3]# echo "welcome to use pv3" > index.html [root@k8s-master volumes]# kubectl get pods -o wide pod-vol-pvc 1/1 Running 0 3m 10.244.2.39 k8s-node02 [root@k8s-master volumes]# curl 10.244.2.39 welcome to use pv3
在pv和pvc使用過程當中存在的問題,在pvc申請存儲空間時,未必就有現成的pv符合pvc申請的需求,上面nfs在作pvc能夠成功的因素是由於咱們作了指定的需求處理。那麼當PVC申請的存儲空間不必定有知足PVC要求的PV事,又該如何處理呢???爲此,Kubernetes爲管理員提供了描述存儲"class(類)"的方法(StorageClass)。舉個例子,在存儲系統中劃分一個1TB的存儲空間提供給Kubernetes使用,當用戶須要一個10G的PVC時,會當即經過restful發送請求,從而讓存儲空間建立一個10G的image,以後在咱們的集羣中定義成10G的PV供給給當前的PVC做爲掛載使用。在此以前咱們的存儲系統必須支持restful接口,好比ceph分佈式存儲,而glusterfs則須要藉助第三方接口完成這樣的請求。如圖:
[root@k8s-master ~]# kubectl explain storageclass #storageclass也是k8s上的資源 KIND: StorageClass VERSION: storage.k8s.io/v1 FIELDS: allowVolumeExpansion <boolean> allowedTopologies <[]Object> apiVersion <string> kind <string> metadata <Object> mountOptions <[]string> #掛載選項 parameters <map[string]string> #參數,取決於分配器,能夠接受不一樣的參數。 例如,參數 type 的值 io1 和參數 iopsPerGB 特定於 EBS PV。當參數被省略時,會使用默認值。 provisioner <string> -required- #存儲分配器,用來決定使用哪一個卷插件分配 PV。該字段必須指定。 reclaimPolicy <string> #回收策略,能夠是 Delete 或者 Retain。若是 StorageClass 對象被建立時沒有指定 reclaimPolicy ,它將默認爲 Delete。 volumeBindingMode <string> #卷的綁定模式
StorageClass 中包含 provisioner、parameters 和 reclaimPolicy 字段,當 class 須要動態分配 PersistentVolume 時會使用到。因爲StorageClass須要一個獨立的存儲系統,此處就再也不演示。從其餘資料查看定義StorageClass的方式以下:
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Retain mountOptions: - debug
在平常單機甚至集羣狀態下,咱們須要對一個應用進行配置,只須要修改其配置文件便可。那麼在容器中又該如何提供配置 信息呢???例如,爲Nginx配置一個指定的server_name或worker進程數,爲Tomcat的JVM配置其堆內存大小。傳統的實踐過程當中一般有如下幾種方式:
- 啓動容器時,經過命令傳遞參數
- 將定義好的配置文件經過鏡像文件進行寫入
- 經過環境變量的方式傳遞配置數據
- 掛載Docker卷傳送配置文件
而在Kubernetes系統之中也存在這樣的組件,就是特殊的存儲卷類型。其並非提供pod存儲空間,而是給管理員或用戶提供從集羣外部向Pod內部的應用注入配置信息的方式。這兩種特殊類型的存儲卷分別是:configMap和secret
- Secret:用於向Pod傳遞敏感信息,好比密碼,私鑰,證書文件等,這些信息若是在容器中定義容易泄露,Secret資源可讓用戶將這些信息存儲在急羣衆,而後經過Pod進行掛載,實現敏感數據和系統解耦的效果。
- ConfigMap:主要用於向Pod注入非敏感數據,使用時,用戶將數據直接存儲在ConfigMap對象當中,而後Pod經過使用ConfigMap捲進行引用,實現容器的配置文件集中定義和管理。
[root@k8s-master volumes]# kubectl explain pods.spec.volumes ...... configMap <Object> ConfigMap represents a configMap that should populate this volume secret <Object> Secret represents a secret that should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret
Secret對象存儲數據的方式是以鍵值方式存儲數據,在Pod資源進行調用Secret的方式是經過環境變量或者存儲卷的方式進行訪問數據,解決了密碼、token、密鑰等敏感數據的配置問題,而不須要把這些敏感數據暴露到鏡像或者Pod Spec中。另外,Secret對象的數據存儲和打印格式爲Base64編碼的字符串,所以用戶在建立Secret對象時,也須要提供該類型的編碼格式的數據。在容器中以環境變量或存儲卷的方式訪問時,會自動解碼爲明文格式。須要注意的是,若是是在Master節點上,Secret對象以非加密的格式存儲在etcd中,因此須要對etcd的管理和權限進行嚴格控制。
Secret有4種類型:
Service Account :用來訪問Kubernetes API,由Kubernetes自動建立,而且會自動掛載到Pod的/run/secrets/kubernetes.io/serviceaccount目錄中;
Opaque :base64編碼格式的Secret,用來存儲密碼、密鑰、信息、證書等,類型標識符爲generic;
kubernetes.io/dockerconfigjson :用來存儲私有docker registry的認證信息,類型標識爲docker-registry。
kubernetes.io/tls:用於爲SSL通訊模式存儲證書和私鑰文件,命令式建立類型標識爲tls。
命令式建立
- 一、經過 --from-literal:
[root@k8s-master ~]# kubectl create secret -h Create a secret using specified subcommand. Available Commands: docker-registry Create a secret for use with a Docker registry generic Create a secret from a local file, directory or literal value tls Create a TLS secret Usage: kubectl create secret [flags] [options] Use "kubectl <command> --help" for more information about a given command. Use "kubectl options" for a list of global command-line options (applies to all commands). 每一個 --from-literal 對應一個信息條目。 [root@k8s-master ~]# kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123456 secret/mysecret created [root@k8s-master ~]# kubectl get secret NAME TYPE DATA AGE mysecret Opaque 2 6s
- 二、經過 --from-file:
每一個文件內容對應一個信息條目。
[root@k8s-master ~]# echo -n admin > ./username [root@k8s-master ~]# echo -n 123456 > ./password [root@k8s-master ~]# kubectl create secret generic mysecret --from-file=./username --from-file=./password secret/mysecret created [root@k8s-master ~]# kubectl get secret NAME TYPE DATA AGE mysecret Opaque 2 6s
- 三、經過 --from-env-file:
文件 env.txt 中每行 Key=Value 對應一個信息條目。
[root@k8s-master ~]# cat << EOF > env.txt > username=admin > password=123456 > EOF [root@k8s-master ~]# kubectl create secret generic mysecret --from-env-file=env.txt secret/mysecret created [root@k8s-master ~]# kubectl get secret NAME TYPE DATA AGE mysecret Opaque 2 10s
清單式建立
- 經過 YAML 配置文件:
#事先完成敏感數據的Base64編碼 [root@k8s-master ~]# echo -n admin |base64 YWRtaW4= [root@k8s-master ~]# echo -n 123456 |base64 MTIzNDU2 [root@k8s-master ~]# vim secret.yaml apiVersion: v1 kind: Secret metadata: name: mysecret data: username: YWRtaW4= password: MTIzNDU2 [root@k8s-master ~]# kubectl apply -f secret.yaml secret/mysecret created [root@k8s-master ~]# kubectl get secret #查看存在的 secret,顯示有2條數據 NAME TYPE DATA AGE mysecret Opaque 2 8s [root@k8s-master ~]# kubectl describe secret mysecret #查看數據的 Key Name: mysecret Namespace: default Labels: <none> Annotations: Type: Opaque Data ==== username: 5 bytes password: 6 bytes [root@k8s-master ~]# kubectl edit secret mysecret #查看具體的value,可使用該命令 apiVersion: v1 data: password: MTIzNDU2 username: YWRtaW4= kind: Secret metadata: ...... [root@k8s-master ~]# echo -n MTIzNDU2 |base64 --decode #經過 base64 將 Value 反編碼: 123456 [root@k8s-master ~]# echo -n YWRtaW4= |base64 --decode admin
Pod 能夠經過 Volume 或者環境變量的方式使用 Secret
[root@k8s-master volumes]# vim pod-secret-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-secret spec: containers: - name: pod-secret image: busybox args: - /bin/sh - -c - sleep 10;touch /tmp/healthy;sleep 30000 volumeMounts: #將 foo mount 到容器路徑 /etc/foo,可指定讀寫權限爲 readOnly。 - name: foo mountPath: "/etc/foo" readOnly: true volumes: #定義 volume foo,來源爲 secret mysecret。 - name: foo secret: secretName: mysecret [root@k8s-master volumes]# kubectl apply -f pod-secret-demo.yaml pod/pod-secret created [root@k8s-master volumes]# kubectl get pods pod-secret 1/1 Running 0 1m [root@k8s-master volumes]# kubectl exec -it pod-secret sh / # ls /etc/foo/ password username / # cat /etc/foo/username admin/ # / # cat /etc/foo/password 123456/ #
能夠看到,Kubernetes 會在指定的路徑 /etc/foo 下爲每條敏感數據建立一個文件,文件名就是數據條目的 Key,這裏是 /etc/foo/username 和 /etc/foo/password,Value 則以明文存放在文件中。
也能夠自定義存放數據的文件名,好比將配置文件改成:
[root@k8s-master volumes]# cat pod-secret-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-secret spec: containers: - name: pod-secret image: busybox args: - /bin/sh - -c - sleep 10;touch /tmp/healthy;sleep 30000 volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret items: #自定義存放數據的文件名 - key: username path: my-secret/my-username - key: password path: my-secret/my-password [root@k8s-master volumes]# kubectl delete pods pod-secret pod "pod-secret" deleted [root@k8s-master volumes]# kubectl apply -f pod-secret-demo.yaml pod/pod-secret created [root@k8s-master volumes]# kubectl exec -it pod-secret sh / # cat /etc/foo/my-secret/my-username admin / # cat /etc/foo/my-secret/my-password 123456
這時數據將分別存放在 /etc/foo/my-secret/my-username 和 /etc/foo/my-secret/my-password 中。
以 Volume 方式使用的 Secret 支持動態更新:Secret 更新後,容器中的數據也會更新。
將 password 更新爲 abcdef,base64 編碼爲 YWJjZGVm
[root@k8s-master ~]# vim secret.yaml apiVersion: v1 kind: Secret metadata: name: mysecret data: username: YWRtaW4= password: YWJjZGVm [root@k8s-master ~]# kubectl apply -f secret.yaml secret/mysecret configured / # cat /etc/foo/my-secret/my-password abcdef
經過 Volume 使用 Secret,容器必須從文件讀取數據,會稍顯麻煩,Kubernetes 還支持經過環境變量使用 Secret。
[root@k8s-master volumes]# cp pod-secret-demo.yaml pod-secret-env-demo.yaml [root@k8s-master volumes]# vim pod-secret-env-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-secret-env spec: containers: - name: pod-secret-env image: busybox args: - /bin/sh - -c - sleep 10;touch /tmp/healthy;sleep 30000 env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password [root@k8s-master volumes]# kubectl apply -f pod-secret-env-demo.yaml pod/pod-secret-env created [root@k8s-master volumes]# kubectl exec -it pod-secret-env sh / # echo $SECRET_USERNAME admin / # echo $SECRET_PASSWORD abcdef
經過環境變量 SECRET_USERNAME 和 SECRET_PASSWORD 成功讀取到 Secret 的數據。
須要注意的是,環境變量讀取 Secret 很方便,但沒法支撐 Secret 動態更新。
Secret 能夠爲 Pod 提供密碼、Token、私鑰等敏感數據;對於一些非敏感數據,好比應用的配置信息,則能夠用 ConfigMap。
configmap是讓配置文件從鏡像中解耦,讓鏡像的可移植性和可複製性。許多應用程序會從配置文件、命令行參數或環境變量中讀取配置信息。這些配置信息須要與docker image解耦,你總不能每修改一個配置就重作一個image吧?ConfigMap API給咱們提供了向容器中注入配置信息的機制,ConfigMap能夠被用來保存單個屬性,也能夠用來保存整個配置文件或者JSON二進制大對象。
ConfigMap API資源用來保存key-value pair配置數據,這個數據能夠在pods裏使用,或者被用來爲像controller同樣的系統組件存儲配置數據。雖然ConfigMap跟Secrets相似,可是ConfigMap更方便的處理不含敏感信息的字符串。 注意:ConfigMaps不是屬性配置文件的替代品。ConfigMaps只是做爲多個properties文件的引用。能夠把它理解爲Linux系統中的/etc目錄,專門用來存儲配置文件的目錄。下面舉個例子,使用ConfigMap配置來建立Kuberntes Volumes,ConfigMap中的每一個data項都會成爲一個新文件。
[root@k8s-master volumes]# kubectl explain cm KIND: ConfigMap VERSION: v1 FIELDS: apiVersion <string> binaryData <map[string]string> data <map[string]string> kind <string> metadata <Object>
與 Secret 同樣,ConfigMap 也支持四種建立方式:
- 一、 經過 --from-literal:
每一個 --from-literal 對應一個信息條目。
[root@k8s-master volumes]# kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-literal=server_name=myapp.magedu.com configmap/nginx-config created [root@k8s-master volumes]# kubectl get cm NAME DATA AGE nginx-config 2 6s [root@k8s-master volumes]# kubectl describe cm nginx-config Name: nginx-config Namespace: default Labels: <none> Annotations: <none> Data ==== server_name: ---- myapp.magedu.com nginx_port: ---- 80 Events: <none>
- 二、經過 --from-file:
每一個文件內容對應一個信息條目。
[root@k8s-master mainfests]# mkdir configmap && cd configmap [root@k8s-master configmap]# vim www.conf server { server_name myapp.magedu.com; listen 80; root /data/web/html; } [root@k8s-master configmap]# kubectl create configmap nginx-www --from-file=./www.conf configmap/nginx-www created [root@k8s-master configmap]# kubectl get cm NAME DATA AGE nginx-config 2 3m nginx-www 1 4s [root@k8s-master configmap]# kubectl get cm nginx-www -o yaml apiVersion: v1 data: www.conf: "server {\n\tserver_name myapp.magedu.com;\n\tlisten 80;\n\troot /data/web/html;\n}\n" kind: ConfigMap metadata: creationTimestamp: 2018-10-10T08:50:06Z name: nginx-www namespace: default resourceVersion: "389929" selfLink: /api/v1/namespaces/default/configmaps/nginx-www uid: 7c3dfc35-cc69-11e8-801a-000c2972dc1f
- 一、環境變量方式注入到pod
[root@k8s-master configmap]# vim pod-configmap.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-1 namespace: default labels: app: myapp tier: frontend annotations: magedu.com/created-by: "cluster admin" spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 env: - name: NGINX_SERVER_PORT valueFrom: configMapKeyRef: name: nginx-config key: nginx_port - name: NGINX_SERVER_NAME valueFrom: configMapKeyRef: name: nginx-config key: server_name [root@k8s-master configmap]# kubectl apply -f pod-configmap.yaml pod/pod-cm-1 created [root@k8s-master configmap]# kubectl exec -it pod-cm-1 -- /bin/sh / # echo $NGINX_SERVER_PORT 80 / # echo $NGINX_SERVER_NAME myapp.magedu.com
修改端口,能夠發現使用環境變化注入pod中的端口不會根據配置的更改而變化
[root@k8s-master volumes]# kubectl edit cm nginx-config configmap/nginx-config edited / # echo $NGINX_SERVER_PORT 80
- 二、存儲卷方式掛載configmap:
Volume 形式的 ConfigMap 也支持動態更新
[root@k8s-master configmap ~]# vim pod-configmap-2.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-2 namespace: default labels: app: myapp tier: frontend annotations: magedu.com/created-by: "cluster admin" spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 volumeMounts: - name: nginxconf mountPath: /etc/nginx/config.d/ readOnly: true volumes: - name: nginxconf configMap: name: nginx-config [root@k8s-master configmap ~]# kubectl apply -f pod-configmap-2.yaml pod/pod-cm-2 created [root@k8s-master configmap ~]# kubectl get pods [root@k8s-master configmap ~]# kubectl exec -it pod-cm-2 -- /bin/sh / # cd /etc/nginx/config.d / # cat nginx_port 80 / # cat server_name myapp.magedu.com [root@k8s-master configmap ~]# kubectl edit cm nginx-config #修改端口,再在容器中查看端口是否變化。 apiVersion: v1 data: nginx_port: "800" ...... / # cat nginx_port 800 [root@k8s-master configmap ~]# kubectl delete -f pod-configmap2.yaml
- 三、以nginx-www配置nginx
[root@k8s-master configmap ~]# vim pod-configmap3.yaml apiVersion: v1 kind: Pod metadata: name: pod-cm-3 namespace: default labels: app: myapp tier: frontend annotations: magedu.com/created-by: "cluster admin" spec: containers: - name: myapp image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 volumeMounts: - name: nginxconf mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: nginxconf configMap: name: nginx-www [root@k8s-master configmap ~]# kubectl apply -f pod-configmap3.yaml pod/pod-cm-3 created [root@k8s-master configmap ~]# kubectl get pods [root@k8s-master configmap]# kubectl exec -it pod-cm-3 -- /bin/sh / # cd /etc/nginx/conf.d/ /etc/nginx/conf.d # ls www.conf /etc/nginx/conf.d # cat www.conf server { server_name myapp.magedu.com; listen 80; root /data/web/html; }
至此,K8S的存儲捲到此結束!!!