15、volume
k8s的存储
·
Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。
本质上,Kubernetes Volume 是一个目录。当Volume被mount到Pod,Pod中的所有容器都可以访问这个Volume。
Kubernetes Volume 也支持多种 backend 类型,完整列表可参考
Volumes | Kubernetes,包括 emptyDir、hostPath、GCE Persistent Disk、AWS Elastic Block Store、NFS、Ceph 等,
一、emptyDir Volume
一个emptyDir Volume是Host上的一个空目录。
emptyDir Volume对于容器来说是持久的(在容器重新启动时能保留数据),对于Pod则不是。当Pod从节点删除,Volume的内容随之删除。但如果只是容器被销毁而Pod还在,则Volume不受影响。
emptyDir Volume 的生命周期与 Pod 一致。
emptyDir.yaml:
模拟了一个 producer-consumer 场景。Pod 有两个容器 producer和 consumer,它们共享一个 Volume。producer 负责往 Volume 中写数据,consumer 则是从 Volume 读取数据。
apiVersion: v1
kind: Pod
metadata:
name: producer-consumer
namespace: default # 命名空间
spec:
containers:
- name: producer
image: busybox
imagePullPolicy: IfNotPresent # 优先使用本地镜像,没有则下载
volumeMounts: # 2、producer容器将shared-volume mount到/producer_dir目录;
- mountPath: /producer_dir
name: shared-volume
args: # 3、producer 通过 echo 将数据写到文件 /producer_dir/hello 里。
- /bin/sh
- -c
- echo "hello world" > /producer_dir/hello; sleep 30000
- name: consumer
image: busybox
imagePullPolicy: IfNotPresent # 优先使用本地镜像,没有则下载
volumeMounts: # 4、consumer 容器将 shared-volume mount 到 /consumer_dir 目录。
- mountPath: /consumer_dir
name: shared-volume
args: # 5、 consumer 通过 cat 从文件 hello 读数据
- /bin/sh
- -c
- cat /consumer_dir/hello; sleep 30000
volumes: # 1、文件最底部volumes定义一个emptyDir类型的Volume shared-volume
- name: shared-volume
emptyDir: {}
执行如下命令创建Pod:
kubectl logs pod-name container-name显示容器consumer成功读到了producer 写入的数据,验证了两个容器共享emptyDir Volume。
因为emptyDir是Docker Host文件系统里的目录,其效果等同于执行
docker run -v /producer_dir 和
docker run -v /consumer_dir。通过
docker inspect container_id 查看容器的详细配置信息,我们发现两个容器都 mount 了同一个目录:
"/var/lib/kubelet/pods/b5b4093f-0791-430b-836e-32fc374690b2/volumes/kubernetes.io~empty-dir/shared-volume"就是emptyDir在Host上真正路径。
emptyDir是Host上创建的临时目录,优点是能够方便的为Pod中的容器提供共享存储,不需要额外的配置,但它不具备持久性,若Pod不在了,emptyDir也就没有了。
根据这个特性,emptyDir 特别适合 Pod 中的容器需要临时共享存储空间的场景,比如前面的生产者消费者用例。
二、hostPath Volume
hostPath Volume的作用是将Host文件系统中
已经存在的目录mount给Pod的容器。
大部分应用不会使用hostPath Volume,因为这个实际增加了Pod与节点的耦合,限制了Pod的使用。不过那些需要访问 Kubernetes 或 Docker 内部数据(配置文件和二进制库)的应用则需要使用 hostPath。
kubectl edit
--
namespace
=
kube
-
system pod kube
-
apiserver
-
master:
type取值:
-
DirectoryOrCreate:宿主机上不存在创建此目录
-
Directory 必须存在挂载目录
-
FileOrCreate:宿主机上不存在挂载文件就创建
-
File:必须存在文件
-
空字符串( 默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。
如果Pod被销毁,hostPath对应的目录还会保留。从这点看,hostPath 的持久性比 emptyDir 强。不过一旦 Host 崩溃,hostPath 也就没法访问了。
三、外部 Storage Provider
如果 Kubernetes 部署在诸如 AWS、GCE、Azure 等公有云上,可以直接使用云硬盘作为 Volume,下面是 AWS Elastic Block Store 的例子:
要在Pod中使用ESB volume,必须先在AWS中创建,然后通过volume-id引用。
Kubernetes Volume 也可以使用主流的分布式存,比如 Ceph、GlusterFS 等,下面是 Ceph 的例子:
Ceph 文件系统的 /some/path/in/side/cephfs 目录被 mount 到容器路径 /test-ceph。
最大特点就是不依赖 Kubernetes。Volume 的底层基础设施由独立的存储系统管理,与 Kubernetes 集群是分离的。数据被持久化后,即使整个 Kubernetes 崩溃也不会受损。
四、NFS挂载
NFS挂载是在其中一个node上将共享的目录发布出来,并且在各个node上都安装好nfs-utils工具,只要在创建Pod的时候指定要挂载的文件系统为nfs和挂载点、权限,即可自动完成挂载操作,并且能实现数据同步。
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis # Deployment名称
spec:
selector:
matchLabels: # 通过标签选择被控制的pod
app: redis
template: # pod信息
metadata:
labels:
app: redis # 给pod打上标签app=redis
spec:
containers:
- image: redis
name: redis
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379 # 对service暴露端口
name: redis6379
env:
- name: ALLOW_EMPTY_PASSWORD # 本地Key
value: "yes"
- name: REDIS_PASSWORD
value: "redis"
volumeMounts:
- name: redis-persistent-storage
mountPath: /data
volumes:
- name: redis-persistent-storage
nfs:
path: /k8s-nfs/redis/data # 共享出来的目录
server: 192.168.126.112 # 提前做好解析
五、PV & PVC
PersistentVolume(PV):外部存储系统中的一块存储空间,由
管理员创建与维护。
PV具有持久性,生命周期独立于Pod。
PersistentVolumeClaim(PVC):是对PV的申请,PVC通常由
普通用户创建和维护。需要为Pod分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes会查找并提供满足条件的PV。
有了 PersistentVolumeClaim,用户只需要告诉 Kubernetes 需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心创建 PersistentVolume 的细节信息。
5.1、 生命周期
5.2、PV类型
GCEPersistentDisk
AWSElasticBlockStore
AzureFile
AzureDisk
FC (Fibre Channel)
Flexvolume
Flocker
NFS
iSCSI
RBD (Ceph Block Device)
CephFS
Cinder (OpenStack block storage)
Glusterfs
VsphereVolume
Quobyte Volumes
HostPath (Single node testing only – local storage is not supported in any
way and WILL NOT WORK in a multi-node cluster)
Portworx Volumes
ScaleIO Volumes
StorageOS
5.3、PV卷阶段状
-
AVailable: 资源尚未被pvc使用
-
Bound: 卷已经被pvc绑定
-
Released: pvc被删除,卷处于释放状态,但未被集群回收
-
Failed:卷自动回收失败
5.4、 NFS PersistentVolume--通过NFS实现持久化存储
已经在master节点搭建了一个NFS服务器,目录为/nas:
showmount -e [ip]
5.4.1、创建一个PV,配置文件nfs-pv1.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: mypv1
namespace: default
labels: # 对 pv 打 label,关联pvc到特定的pv
pv: nfs-pv1
spec:
capacity: # 指定 PV 的容量为 1G
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: nfs # 指定PV的class为nfs,等同于为PV设置一个分类,PVC可以指定class申请相应的class的PV
nfs:
path: /nas/pv1 # 指定 PV 在 NFS 服务器上对应的目录,/nas/pv1这个目录得存在
server: 192.168.11.45
accessModes: 指定访问模式,支持的访问模式有:
-
ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点
-
ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点
-
ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点
persistentVolumeReclaimPolicy: 指定PV的回收策略,支持的策略有:
-
Retain - 管理员手工回收
-
Recycle - 清除PV中的数据,效果相等于rm -rf /thevolume/*
-
Delete - 删除Storage Provider上的对应存储资源,例如 AWS EBS、OpenStack Cinder Volume 等,NFS 的 PV 不支持 Delete
创建 mypv1与查看PV:
kubectl get pv 获取PV,STATUS为Avaliable,表明mypv1已就绪,可以被PVC申请。
5.4.2、创建 PVC mypvc1,配置文件 nfs-pvc1.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi # 只需要指定 PV 的容量,访问模式和 class
storageClassName: nfs
selector:
matchLabels: # 使用 matchLabel 来关联刚创建的 pv:nfs-pv1,绑定到特定的pv
pv: nfs-pv1
创建 mypvc1:
从
kubectl get pvc 和 kubectl get pv 的输出,可以看出mypvc1已经Bound到mypv1,申请成功。
5.4.3、在 Pod 中使用存储,Pod 配置文件 pod1.yaml:
apiVersion: v1
kind: Pod
metadata:
name: mypod1
spec:
containers:
- name: mypod1
image: busybox
args:
- /bin/sh
- -c
- sleep 30000
volumeMounts:
- mountPath: "/mydata"
name: mydata
volumes:
- name: mydata
persistentVolumeClaim:
claimName: mypvc1
创建 mypod1:
验证PV是否可用:
可见在Pod中创建的文件 /mydata/hello 已经保存到NFS服务器的目录/nas/pv1中。
5.5、 回收PV
如果不再需要使用 PV,可用删除 PVC 回收 PV。
需要先删除之前创建的 mypod1
当 PVC mypvc1 被删除后,我们发现 Kubernetes 启动了一个新 Pod recycler-for-mypv1,这个 Pod 的作用就是清除 PV mypv1 的数据。此时 mypv1 的状态为
Released,表示已经解除了与 mypvc1 的 Bound,正在清除数据,不过此时还不可用。
当数据清除完毕,mypv1 的状态重新变为 Available,此时则可以被新的 PVC 申请。
/nas/pv1/目录下的文件hello也被删除了,因为 PV 的回收策略设置为 Recycle,所以数据会被清除,但这可能不是我们想要的结果。如果我们希望保留数据,可以将策略设置为 Retain。
5.6、PV动态供给
提前创建了PV,然后通过PVC申请PV在Pod中使用,这种方式叫做
静态供给。
动态供给:如果没有满足PVC条件的PV,会动态创建PV。相比静态供给,动态供给有明显的优势:
不需要提前创建 PV,减少了管理员的工作量,效率高。
动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV。
StorageClass standard:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain # StorageClass 支持 Delete 和 Retain 两种 reclaimPolicy,默认是 Delete
StorageClass slow
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: slow
provisioner: kubernetes.io/aws-ebs
parameters:
type: io1
zones: us-east-1d, us-east-1c
iopsPerGB: "10"
这两个 StorageClass 都会动态创建 AWS EBS,不同在于 standard 创建的是 gp2 类型的 EBS,而 slow 创建的是 io1 类型的 EBS。不同类型的 EBS 支持的参数可参考 AWS 官方文档。
与之前一样,PVC 在申请 PV 时,只需要指定 StorageClass 和容量以及访问模式,比如:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
六、MySQL使用PV与PVC
怎样为MySQL数据库持久化存储,步骤如下:
-
创建PV与PVC
-
部署MySQL
-
向MySQL添加数据
-
模拟节点宕机故障,Kubernetes自动将MySQL迁移到其他节点
-
验证数据一致性
6.1、创建PV与PVC
mysql-pv.yaml:
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /nas/mysql-pv # 指定 PV 在 NFS 服务器上对应的目录,/nas/mysql-pv这个目录得存在
server: 192.168.11.45
mysql-pvc.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc1
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi # 只需要指定 PV 的容量,访问模式和 class
storageClassName: nfs
创建mysql-pv与mysql-pvc:
如果此时机器上有相同容量的其他PV,那怎样将PVC绑定到特定的PV上???---
k8s 如何关联pvc到特定的pv?_强哥之神的博客-CSDN博客_pvc指定pv
k8s 如何关联pvc到特定的pv?
6.2、部署MySQL
mysql.yaml:
apiVersion: apps/v1 # 当前配置格式的版本
kind: Deployment # kind 是要创建的资源类型
metadata: # metadata 是该资源的元数据,name 是必需的元数据项
name: mysql-deployment # deployment名称
spec: # spec 部分是该 Deployment 的规格说明
selector: # 通过标签选择被控制的pod
matchLabels:
app: mysql
replicas: 1 # 通过replicas声明pod个数是3
template: # template 定义 Pod 的模板,这是配置文件的重要部分
metadata: # metadata 定义 Pod 的元数据,至少要定义一个 label。label 的 key 和 value 可以任意指定
labels: # 给pod打上标签app=httpd
app: mysql
spec: # spec 描述 Pod 的规格,此部分定义 Pod 中每一个容器的属性,name 和 image 是必需的。
containers: # 声明容器的名称、镜像、端口
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: password
ports: # 需要暴露的端口库号列表
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-persistent-storage
mountPath: /var/lib/mysql
volumes:
- name: mysql-persistent-storage
persistentVolumeClaim:
claimName: mysql-pvc1
---
apiVersion: v1
kind: Service
metadata:
name: mysql-service
spec:
selector:
app: mysql # 将选择具有app: mysql标签的Pod作为管理范围
ports:
- port: 3306 # service监听端口
MySQL被部署到node2节点上,通过客户端访问Service Mysql:
kubectl run -it --rm --image=mysql:5.7 --restart=Never mysql-client -- mysql -h mysql-service -ppassword
6.3、添加数据
6.4、模拟故障
关闭node2,模拟node2节点宕机故障:
shutdown now
耐心等待一段时间后(5分钟 pod-eviction-timeout值),kubernetes将MySQL迁移到node1节点
6.5、验证数据的一致性
MySQL服务恢复,数据完整
七、参考
更多推荐
已为社区贡献3条内容
所有评论(0)