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)