k8s存儲卷-volumes
為什么要用volumes?
容器中的磁盤的生命周期是短暫的, 這就帶來了一些列的問題:
- 當一個容器損壞之后, kubelet會重啟這個容器, 但是文件會丟失, 這個容器將是一個全新的狀態
- 當很多容器運行在同一個pod中時, 很多時候需要數據文件的共享
- 在
k8s
中,由於pod
分布在各個不同的節點之上,並不能實現不同節點之間持久性數據的共享,並且,在節點故障時,可能會導致數據的永久性丟失。
volumes就是用來解決以上問題的
Volume 的生命周期獨立於容器,Pod 中的容器可能被銷毀和重建,但 Volume 會被保留。
volumes類型
emptyDir
一個emptyDir第一次被創建是在一個pod被指定到具體node的時候, 並且會一直存在在pod的生命周期中, 它初始化是一個空的目錄,pod中的容器都可以讀寫這個目錄,這個目錄可以被掛在到各個容器相同或者不相同的的路徑下。當一個pod因為任何原因被移除的時候,這些數據會被永久刪除。注意:一個容器崩潰了不會導致數據的丟失,因為容器的崩潰並不移除pod. |
apiVersion: v1
kind: Pod
metadata:
name: pod-demo #name必須小寫
namespace: default
labels:
app: myapp
tier: frontend
annotations:
create-by: tianpei.wang
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /data/web/html/
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data/
command: ["/bin/sh", "-c", "sleep 7200"]
volumes:
- name: html
emptyDir: {}
gitrepo
本質上還是一個emptyDir,創建的那一刻從git上clone下來文件,不會在更新,所以會借助sidecar容器來更新或者推送目錄中的文件代碼 |
hostPath
一個hostPath類型的磁盤就是掛在了主機的一個文件或者目錄,這個功能可能不是那么常用,但是這個功能提供了一個很強大的突破口對於某些應用來說 例如,如下情況我們舊可能需要用到hostPath!!!!!! 一. 某些應用需要用到docker的內部文件,這個時候只需要掛在本機的/var/lib/docker作為hostPath!!!!!! 二. 在容器中運行cAdvisor,這個時候掛在/dev/cgroups!!!!!! |
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-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
nfs
安裝部署nfs
yum install -y nfs-utils rpcbind
systemctl start rpcbind
systemctl start nfs
[root@test share]# cat /etc/exports
/data/share 10.0.0.0/24(rw,no_root_squash)
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-hostpath
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
path: /data/share
server: 10.0.0.53
k8s--PV, PVC
PV PVC帶來了哪些好處
Volume 提供了非常好的數據持久化方案,不過在可管理性上還有不足。
如前面nfs-volume舉例, 當我們創建一個掛載到nfs服務器上的pod時, 我們需要知道:
- nfs服務的ip
- nfs服務的共享目錄
Pod 通常是由應用的開發人員維護,而 Volume 則通常是由存儲系統的管理員維護。開發人員要獲得上面的信息:
- 要么詢問管理員。
- 要么自己就是管理員。
這樣就帶來一個管理上的問題:應用開發人員和系統管理員的職責耦合在一起了。如果系統規模較小或者對於開發環境這樣的情況還可以接受。但當集群規模變大,特別是對於生成環境,考慮到效率和安全性,這就成了必須要解決的問題。
Kubernetes 給出的解決方案是 PersistentVolume 和 PersistentVolumeClaim。
PersistentVolume (PV)
是外部存儲系統中的一塊存儲空間,由管理員創建和維護。與 Volume 一樣,PV 具有持久性,生命周期獨立於 Pod。
PersistentVolumeClaim (PVC)
是對 PV 的申請 (Claim)。PVC 通常由普通用戶創建和維護。需要為 Pod 分配存儲資源時,用戶可以創建一個 PVC,指明存儲資源的容量大小和訪問模式(比如只讀)等信息,Kubernetes 會查找並提供滿足條件的 PV。有了 PersistentVolumeClaim,用戶只需要告訴 Kubernetes 需要什么樣的存儲資源,而不必關心真正的空間從哪里分配,如何訪問等底層細節信息。這些 Storage Provider 的底層信息交給管理員來處理,只有管理員才應該關心創建 PersistentVolume 的細節信息。
- 一個pv只能對應一個pvc,但是一個pvc可以對應多個pod
- pv屬於集群級別的資源,整個集群都可以用;pvc屬於namespace級別的資源,只屬於所屬namespace
- pvc資源存儲在etcd中,只要etcd服務正常就不會丟失,和節點沒有關系
基於nfs配置pv和pvc
nfs的配置參考前文
定義pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs:
path: /data/volumes/test1
server: 10.0.0.53
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/test2
server: 10.0.0.53
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/test3
server: 10.0.0.53
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 7Gi
[root@master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 2Gi RWO,RWX Retain Available 14m
pv002 2Gi RWO,RWX Retain Available 14m
pv003 7Gi RWO,RWX Retain Available 14m
accessModes:
- ReadWriteOnce (RWO) – the volume can be mounted as read-write by a single node
- ReadOnlyMany (ROX) – the volume can be mounted read-only by many nodes
- ReadWriteMany (RWX) – the volume can be mounted as read-write by many nodes
定義pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 6Gi
---
apiVersion: v1
kind: Pod
metadata:
name: myapp-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
此時發現有符合要求的pv被綁定到了pod上
[root@master volumes]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv001 2Gi RWO,RWX Retain Available 15m
pv002 2Gi RWO,RWX Retain Available 15m
pv003 7Gi RWO,RWX Retain Bound default/mypvc 15m
以mysql:5.6鏡像為例
-
直接使用上例創建的pv
-
創建mysql的pvc和deployment
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mypvc namespace: default spec: accessModes: ["ReadWriteMany"] resources: requests: storage: 6Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: mysql-deployment namespace: default spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:5.6 imagePullPolicy: IfNotPresent args: - "--ignore-db-dir=lost+found" ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD value: "mysql" volumeMounts: - name: mysql mountPath: /var/lib/mysql volumes: - name: mysql persistentVolumeClaim: claimName: mypvc
-
然后在創建的pod中創建數據
kubectl exec -it pod mysql-deployment-5b9cf7df5c-mh94v -- /bin/sh #在pod中可以看到掛載好的nfs磁盤 # df -h Filesystem Size Used Avail Use% Mounted on overlay 20G 3.7G 16G 19% / tmpfs 64M 0 64M 0% /dev tmpfs 912M 0 912M 0% /sys/fs/cgroup /dev/sda2 20G 3.7G 16G 19% /etc/hosts shm 64M 0 64M 0% /dev/shm 10.0.0.53:/data/volumes/test3 20G 4.3G 16G 22% /var/lib/mysql #進入mysql # mysql -uroot -pmysql #創建新的數據庫 mysql> create database wtp; #進入新庫 mysql> use wtp; #創建新的表 mysql> CREATE TABLE `tbl_dept`( -> `id` INT(11) NOT NULL AUTO_INCREMENT, -> `deptName` VARCHAR(30) DEFAULT NULL, -> `locAdd` VARCHAR(40) DEFAULT NULL, -> PRIMARY KEY (`id`) -> )ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.12 sec) #刪除mysql的deployment kubectl delete deployments mysql-deployment #重新創建mysql的deployment kubectl apply -f pvc.yaml #進入新的mysql pod kubectl exec -it mysql-deployment-5b9cf7df5c-ztfwx -- /bin/sh #可以看到依舊掛載的之前的目錄 # df -h Filesystem Size Used Avail Use% Mounted on overlay 20G 3.7G 16G 19% / tmpfs 64M 0 64M 0% /dev tmpfs 912M 0 912M 0% /sys/fs/cgroup /dev/sda2 20G 3.7G 16G 19% /etc/hosts shm 64M 0 64M 0% /dev/shm 10.0.0.53:/data/volumes/test3 20G 4.3G 16G 22% /var/lib/mysql #進入mysql查看之前的數據都還在 mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | wtp | +--------------------+ 4 rows in set (0.08 sec) mysql> use wtp Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed mysql> show tables -> ; +---------------+ | Tables_in_wtp | +---------------+ | tbl_dept | +---------------+ 1 row in set (0.00 sec)