之前寫的一篇關于k8s部署zabbix監控系統的文章中,我們有使用到通過hostPath來持久化存儲mysql的資料以及emptyDir的簡單使用。如果我們要在k8s上部署一個符合生産級别的應用,很顯然,就資料持久化而言,使用hostPath與emptyDir來持久化我們的資料是不可以的,我們還需要更加可靠的存儲來儲存應用的持久化資料,這樣容器在重建後,依然可以使用之前的資料。此篇文章将詳細介紹k8s中兩個非常重要的資源對象:pv、pvc來實作存儲管理。
kubernetes版本:1.16.0
概念
pv全稱為PersistentVolume(持久化卷),是對底層的共享存儲的一種抽象,它和具體的底層的共享存儲技術的實作方式有關,比如 Ceph、GlusterFS、NFS 等。
pvc全稱PersistentVolumeClaim(持久化卷聲明),PVC 是使用者存儲的一種聲明,PVC 消耗的是 PV 資源,對于真正使用存儲的使用者不需要關心底層的存儲實作細節,隻需要直接使用 PVC 即可。
NFS
k8s支援的 PV 類型有很多,常見的有 Ceph、GlusterFs、nfs以及 hostPath,不過 hostPath 僅僅可用于單機測試。友善起見,我們以NFS存儲資源進行示範。
接下來我們在節點192.168.248.139上面安裝nfs服務,共享的資料目錄為/data/nfs/
1、安裝配置nfs
yum install nfs-utils rpcbind -y
mkdir -p /data/nfs && chmod 755 /data/nfs/
cat /etc/exports
/data/nfs *(rw,sync,no_root_squash)
systemctl start rpcbind nfs && systemctl enable rpcbind nfs
在k8s上配置使用pv與pvc之前,我們需要在所有的node節點上安裝nfs用戶端,我所使用的環境節點如下:
[root@k8s-master-01 ~]# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
k8s-node-01 Ready <none> 90d v1.16.0 192.168.248.134 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.6
k8s-node-02 Ready <none> 90d v1.16.0 192.168.248.135 <none> CentOS Linux 7 (Core) 3.10.0-957.el7.x86_64 docker://18.9.6
必須在所有節點都安裝 nfs 用戶端,否則可能會導緻 PV 挂載不上的問題。
建立pv
部署完nfs存儲,接下來我們就可以通過編輯yaml檔案,來建立pv和pvc資源了。下面我們來建立一個 PV 資源對象,使用 nfs 類型的後端存儲,2G 的存儲空間,通路模式為 ReadWriteOnce,回收政策為 Recyle。
vim pv1.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-01
labels:
name: pv-01
spec:
nfs:
path: /data/nfs
server: 192.168.248.139
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 2Gi
對以上yaml檔案中一些參數做以下解釋
nfs:表示使用的後端存儲為nfs
path:表示後端存儲共享的資料目錄
accessMode:是用來對pv進行通路權限的設定,包括以下幾種方式:
- ReadWriteOnce(RWO):讀寫權限,隻能被單個節點挂載
- ReadOnlyMany(ROX):隻讀權限,可以被多個節點挂載
- ReadWriteMany(RWX):讀寫權限,可以被多個節點挂載
persistentVolumeReclaimPolicy:表示pv的回收政策,預設為Retain,目前支援的有三種:
- Retain(保留)
- Recycle(回收)
- Delete(删除)
然後使用kubectl指令建立即可
[root@k8s-master-01 pv]# kubectl apply -f pv1.yaml
persistentvolume/pv-01 created
[root@k8s-master-01 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mysql-pv-volume 20Gi RWO Retain Bound default/mysql-pv-claim manual 2d2h
pv-01 2Gi RWO Recycle Available 6s
如上,pv-01已經建立成功,狀态為Available,表示pv-01已經準備就緒,可以被pvc申請使用。
pv的生命周期中可能會處于4種不同的階段:
- Available(可用)
- Bound(已綁定)
- Released(已釋放)
- Failed(失敗)
建立pvc
對應的yaml檔案内容如下:
vim pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi
然後使用kubectl指令建立即可
[root@k8s-master-01 pv]# kubectl apply -f pvc-nfs.yaml
persistentvolumeclaim/pvc-nfs created
[root@k8s-master-01 pv]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/mysql-pv-volume 20Gi RWO Retain Bound default/mysql-pv-claim manual 2d3h
persistentvolume/pv-01 2Gi RWO Retain Bound default/pvc-nfs 19s
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mysql-pv-claim Bound mysql-pv-volume 20Gi RWO manual 2d3h
persistentvolumeclaim/pvc-nfs Bound pv-01 2Gi RWO 7s
可以看到 pvc-nfs已經建立成功,并且處于綁定狀态,pv也處于綁定狀态。
使用pvc
上面我們已經完成了pv和pvc的建立及綁定,接下來我們建立一個deployment,來使用上面的pvc
vim deployment-pvc.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-nginx-demo
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
nodePort: 31080
selector:
app: liheng
type: NodePort
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-pvc-demo
labels:
app: deployment-pvc-demo
annotations:
liheng86876/created-by: "LIHENG"
spec:
replicas: 3
selector:
matchLabels:
app: liheng
template:
metadata:
labels:
app: liheng
spec:
containers:
- name: web-test
image: nginx
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
persistentVolumeClaim:
claimName: pvc-nfs
[root@k8s-master-01 pv]# kubectl get deploy,pod,svc
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment-pvc-demo 3/3 3 3 2m6s
NAME READY STATUS RESTARTS AGE
pod/deployment-pvc-demo-77859488fc-bmlhd 1/1 Running 0 2m5s
pod/deployment-pvc-demo-77859488fc-c8xkn 1/1 Running 0 2m5s
pod/deployment-pvc-demo-77859488fc-pz6g9 1/1 Running 0 2m5s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 90d
service/svc-nginx-demo NodePort 10.0.0.194 <none> 80:31080/TCP 2m6s
可以看到pod已經處于running狀态,我們可以通過如下指令檢視deployment和svc的詳細資訊
[root@k8s-master-01 pv]# kubectl describe deploy deployment-pvc-demo
Name: deployment-pvc-demo
Namespace: default
CreationTimestamp: Mon, 17 Feb 2020 18:04:26 +0800
Labels: app=deployment-pvc-demo
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{"liheng86876/created-by":"LIHENG"},"labels":{"app":"deployment-pvc-...
liheng86876/created-by: LIHENG
Selector: app=liheng
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=liheng
Containers:
web-test:
Image: nginx
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts:
/usr/share/nginx/html/ from html (rw)
Volumes:
html:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: pvc-nfs
ReadOnly: false
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: deployment-pvc-demo-77859488fc (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 4m48s deployment-controller Scaled up replica set deployment-pvc-demo-77859488fc to 3
[root@k8s-master-01 pv]# kubectl describe svc svc-nginx-demo
Name: svc-nginx-demo
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"svc-nginx-demo","namespace":"default"},"spec":{"ports":[{"nodePor...
Selector: app=liheng
Type: NodePort
IP: 10.0.0.194
Port: <unset> 80/TCP
TargetPort: 80/TCP
NodePort: <unset> 31080/TCP
Endpoints: 10.244.0.134:80,10.244.0.135:80,10.244.1.129:80
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
通路測試
我們就可以通過任意節點的 IP:31080 端口來通路我們這裡的Nginx服務
為什麼會出現403呢???那是應為我們的nfs共享目錄沒有檔案導緻
[root@localhost nfs]# pwd
/data/nfs
[root@localhost nfs]# ls
[root@localhost nfs]#
我們建立一個index.html,然後通路測試
[root@localhost nfs]# echo "<h1>Welcome k8s</h1>" > index.html
然後在重新整理頁面:
我們可以看到已經可以正常通路到頁面。
資料持久化測試
測試方法:
1、我們将建立的nginx應用删除掉,然後重新建立nginx應用,然後通路測試
結果:後端nfs存儲裡面的資料不會丢失,頁面通路正常
2、我們将建立的nginx應用和pv及pvc全部删除,然後重新建立,然後通路測試