对接分布式存储
学习pv、pvc
在 Kubernetes 中,PV(PersistentVolume)和 PVC(PersistentVolumeClaim)是用于持久化存储的核心概念。
PV 表示集群中的一个可用的持久化存储资源;
而 PVC 则是一个声明,它定义了应用程序需要的持久化存储资源的属性。
PVC 实际上是对 PV 的请求。
以下是为什么需要使用 PV 和 PVC 的几个原因:
- 数据持久化:在容器中,所有数据都是易失的。在容器被删除或重启时,数据将丢失。PV 和 PVC 使数据持久化,这意味着即使容器被删除或重启,数据仍然存在。
- 资源隔离:PV 和 PVC 允许将存储资源与应用程序分离。这使得应用程序能够使用独立于底层存储系统的存储资源,从而增强了应用程序的可移植性。
- 存储资源管理:使用 PV 和 PVC,管理员可以更好地管理和监视存储资源。管理员可以设置 PV 的属性,如容量、存储类、访问模式等,以及监视 PV 和 PVC 的使用情况。
综上所述,使用 PV 和 PVC 可以使存储资源的管理和使用更加可靠和灵活,同时还能提供数据持久化、资源隔离和管理等优势。
之前怎么做的数据持久化
k8s存储的目的就是保证Pod重建后,数据不丢失。
简单的数据持久化的下述方式:
emptyDir
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: webserver
volumeMounts:
- mountPath: /cache
name: cache-volume # 2.容器共享该数据
- image: k8s.gcr.io/test-redis
name: redis
volumeMounts:
- mountPath: /data
name: cache-volume # 3.容器共享该数据
volumes:
- name: cache-volume # 1.定义共享持久化目录
emptyDir: {} # 4.但是pod删除数据自动删除
- Pod内的容器共享卷的数据
- 存在于Pod的生命周期,Pod销毁,数据丢失
- Pod内的容器自动重建后,数据不会丢失
hostPath
apiVersion: v1
kind: Pod
metadata:
name: test-pod
spec:
containers:
- image: k8s.gcr.io/test-webserver
name: test-container
volumeMounts:
- mountPath: /test-pod
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /data
# this field is optional
type: Directory
通常配合nodeSelector使用
nfs存储
...
volumes:
- name: redisdata #卷名称
nfs: #使用NFS网络存储卷
server: 192.168.31.241 #NFS服务器地址
path: /data/redis #NFS服务器共享的目录
readOnly: false #是否为只读
...
k8s支持诸多持久化方案
volume支持的种类众多(参考 https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes ),每种对应不同的存储后端实现,因此为了屏蔽后端存储的细节,同时使得Pod在使用存储的时候更加简洁和规范,k8s引入了两个新的资源类型,PV和PVC。

PV是什么
在Kubernetes(k8s)中,PV指的是Persistent Volume(持久卷),是一种 Kubernetes 资源对象,用于提供对持久存储的抽象。
PV 可以看做是一个独立于 Pod 的存储资源,它与底层存储设施解耦,可以独立创建、销毁、管理。PV 可以用于让一个 Pod 能够使用独立的存储资源,而不需要直接关注这些资源所在的存储设备。
PV 具有以下特点:
- 独立性:PV 是一个独立于 Pod 的资源,它的生命周期不会受到 Pod 的影响。
- 静态配置:PV 的配置是静态的,它们在创建后就不会自动调整。
- 持久性:PV 存在于存储设备中,即使 Pod 删除或重启,PV 仍然可以保持数据的持久存储。
- 动态供应:PV 可以动态地供应给 Pod,即在 Pod 创建时自动绑定已有的 PV。
PV 的作用是解耦存储设备与 Pod,它可以让管理员在不影响应用的情况下对存储设备进行管理和调整。同时,PV 可以通过定义 StorageClass 来自动化存储设备的分配和管理,使得使用者无需关心底层存储设备的具体实现,只需要定义自己需要的存储资源即可。因此,PV 在 Kubernetes 中是非常重要的资源对象。
如使用PV对接NFS存储。
先定义PV资源,定义好你要用什么类型外部存储。
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /data/k8s
server: 172.21.65.226
pv参数解释
- capacity,存储能力, 目前只支持存储空间的设置, 就是我们这里的 storage=1Gi,不过未来可能会加入 IOPS、吞吐量等指标的配置。
- accessModes,访问模式, 是用来对 PV 进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:
- ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载
- ReadOnlyMany(ROX):只读权限,可以被多个节点挂载
- ReadWriteMany(RWX):读写权限,可以被多个节点挂载
- persistentVolumeReclaimPolicy,pv的回收策略, 目前只有 NFS 和 HostPath 两种类型支持回收策略
- Retain(保留)- 保留数据,需要管理员手工清理数据
- Recycle(回收)- 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
- Delete(删除)- 与 PV 相连的后端存储完成 volume 的删除操作,当然这常见于云服务商的存储服务,比如 ASW EBS。
因为PV是直接对接底层存储的,就像集群中的Node可以为Pod提供计算资源(CPU和内存)一样,PV可以为Pod提供存储资源。
因此PV不是namespaced的资源,属于集群层面可用的资源。
Pod如果想使用该PV,需要通过创建PVC挂载到Pod中。
PVC是什么
PVC全写是PersistentVolumeClaim(持久化卷声明),PVC 是用户存储的一种声明,创建完成后,可以和PV实现一对一绑定。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。
在Kubernetes(k8s)中,PVC指的是Persistent Volume Claim(持久卷声明),是一个请求创建 Persistent Volume(PV)的资源对象。PVC 允许 Pod 声明所需的存储资源(如容量、访问模式、存储类别等),Kubernetes 会自动为 Pod 绑定可用的 PV,以提供可持久化的存储。
PVC 有以下特点:
- 动态绑定:PVC 可以在 Pod 创建时自动绑定可用的 PV。
- 动态调整:PVC 可以根据 Pod 的需要调整存储资源的容量。
- 独立性:PVC 是独立于 Pod 的资源对象,因此可以随时创建、删除、更新等。
需要使用 PVC 的原因是:
- 管理灵活:PVC 允许管理员在不影响应用的情况下对存储设备进行管理和调整。例如,可以在 PV 中定义存储设备的容量和类型,然后在 PVC 中声明自己所需的容量和类型,Kubernetes 会自动为 Pod 绑定符合条件的 PV。
- 应用可移植性:使用 PVC 可以提高应用的可移植性,因为应用只需要声明自己所需的存储资源即可,而不需要关心底层存储设备的具体实现。
- 数据持久性:使用 PVC 可以实现数据的持久性存储,即使 Pod 被删除或重启,数据仍然可以被保存在 PV 中。这对于需要长期存储数据的应用非常重要。
因此,PVC 是 Kubernetes 中非常重要的资源对象,它提供了灵活、可移植、持久的存储资源管理方式,是实现应用持久化存储的关键组件。
1.创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
2.创建pod,使用pvc
...
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts: #挂载容器中的目录到pvc nfs中的目录
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim: #指定pvc
claimName: pvc-nfs
...
图解pod、pv、pvc关系
PVC(Persistent Volume Claim)是 Kubernetes 中一种声明式的对象,用于请求存储资源。PV(Persistent Volume)是 Kubernetes 中提供的抽象层,用于表示存储资源。在 Kubernetes 中,PV 是在集群级别上管理的,而 PVC 是在命名空间级别上管理的。
要将 PVC 绑定到 PV 上,需要满足以下条件:
- PV 必须存在,且其状态必须为 "Available"。
- PV 的存储类(StorageClass)必须与 PVC 的存储类匹配,或者 PVC 没有指定存储类,PV 也没有指定存储类。
- PVC 的请求资源必须小于等于 PV 的可用资源。
如果上述条件都满足,Kubernetes 就会将 PVC 绑定到 PV 上,使其可以使用 PV 的存储资源。可以使用 kubectl 命令来查看 PVC 和 PV 的状态,例如:
kubectl get pvc
kubectl get pv
如果 PVC 和 PV 都处于 "Bound" 状态,则表示它们已经成功绑定。

实践Pod使用NFS
1.装NFS服务端
[root@docker01 ~]#yum install nfs-utils rpcbind -y
# 共享目录
$ mkdir -p /data/k8s && chmod 755 /data/k8s
$ echo '/data/k8s *(insecure,rw,sync,no_root_squash)'>>/etc/exports
$ systemctl enable rpcbind && systemctl start rpcbind
$ systemctl enable nfs && systemctl start nfs
# 创建一个用于共享数据的目录
mkdir -p /data/k8s/yc-nginx
# 查看共享
[root@docker01 ~]#showmount -e 127.0.0.1
Export list for 127.0.0.1:
/data/k8s
2.客户端所有节点
客户端机器想使用NFS,也得安装nfs-utils
yum install nfs-utils rpcbind -y
3.创建PV
创建PV、属于底层资源,是跨namespace的
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1Gi # 可以用1G数据
accessModes:
- ReadWriteMany # 可以有多个pod去同时读写
persistentVolumeReclaimPolicy: Retain # PV回收策略
nfs: # pv关联NFS
path: /data/k8s/yc-nginx
server: 10.0.0.66
查看pv
[root@k8s-master ~/k8s-all]#kubectl create -f pv-nfs.yaml
persistentvolume/nfs-pv created
[root@k8s-master ~/k8s-all]#kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv 1Gi RWX Retain Available 3s
[root@k8s-master ~/k8s-all]#
一个 PV 的生命周期中,可能会处于4中不同的阶段:
- Available(可用):表示可用状态,还未被任何 PVC 绑定
- Bound(已绑定):表示 PV 已经被 PVC 绑定
- Released(已释放):PVC 被删除,但是资源还未被集群重新声明
- Failed(失败): 表示该 PV 的自动回收失败
4.创建PVC
我想申请1G的资源
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs
namespace: yuchao
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
在 Kubernetes 中,Persistent Volume(PV)是一种表示存储资源的对象,可以是物理存储设备(例如硬盘、SSD 等)或云存储服务(例如 AWS EBS、Google Cloud Persistent Disk 等)。Persistent Volume Claim(PVC)是请求存储资源的对象,它与应用程序的 Pod 相关联,用于声明所需的存储资源。
当一个应用程序需要使用存储资源时,它会创建一个 PVC 对象来请求这些资源。Kubernetes 根据 PVC 的规范,自动找到一个符合要求的 PV,并将 PVC 绑定到该 PV 上。如果没有符合要求的 PV,Kubernetes 会等待 PV 可用,并在 PV 可用时将 PVC 绑定到该 PV 上。
PVC 通常具有以下属性:
- 访问模式(Access Modes):指定访问 PV 的方式,可以是 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany。
- 存储类(Storage Class):指定所需的存储类型(例如 SSD、HDD、高性能、低成本等)。
- 存储容量(Storage Capacity):指定所需的存储容量。
PV 通常具有以下属性:
- 存储类(Storage Class):指定存储类型。
- 容量(Capacity):指定存储容量。
- 访问模式(Access Modes):指定可用于访问 PV 的方式。
- 持久化卷插件(Persistent Volume Plugins):指定 PV 的类型和所需的特性(例如 NFS、iSCSI、本地存储等)。
在 Kubernetes 中,一个 Persistent Volume(PV)只能绑定到一个 Persistent Volume Claim(PVC)上,而一个 PVC 也只能绑定到一个 PV 上。
这是因为 PVC 是对 PV 的抽象,它描述了对存储资源的需求,并且只能与一个 PV 匹配。如果多个 PVC 绑定到同一个 PV 上,则可能会导致冲突和数据丢失。
所以是一对一绑定关系。
多个 PVC 可以共享同一个 Storage Class,以指定它们所需的存储类型和属性。当 PVC 需要绑定到 PV 时,Kubernetes 会自动选择符合 PVC 要求的 PV,只要该 PV 的存储类匹配 PVC 的存储类,并且该 PV 还未绑定到其他 PVC。
如果没有符合要求的 PV,则 Kubernetes 会等待 PV 可用,并在 PV 可用时将 PVC 绑定到该 PV 上。
[root@k8s-master ~/k8s-all]#kubectl -n yuchao get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound nfs-pv 1Gi RWX 4s
[root@k8s-master ~/k8s-all]#kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-pv 1Gi RWX Retain Bound yuchao/pvc-nfs 125m
这里会发现、pvc、pvc自动的绑定了
5.PVC怎么找到的PV
上面于超老师并没有在pvc中指定用哪个pv,pvc会怎么找到pv?
在 Kubernetes 中,可以使用不同的方法来匹配 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)。
一种常见的方法是通过 StorageClass 来匹配 PV 和 PVC。PVs 可以被标记为属于某个特定的 StorageClass。
当 PVCs 请求特定的 StorageClass 时,Kubernetes 将会自动寻找一个匹配的 PV。
在你提供的 YAML 文件中,没有指定 StorageClass 字段,因此 Kubernetes 将会使用默认的 StorageClass。
如果没有使用
StorageClass或者默认的StorageClass中没有符合 PVC 要求的 PV,Kubernetes 将会查找所有的 PV 来寻找一个匹配的 PV。原理在这里
↓↓↓↓↓↓
在这种情况下,Kubernetes 会考虑 PV 的容量、访问模式、存储介质类型等因素,以找到最佳匹配的 PV。如果找不到匹配的 PV,PVC 将会处于
Pending状态,直到有一个合适的 PV 可用。
因此,当你创建一个 PVC 而没有显式地指定要匹配哪个 PV 时,Kubernetes 将会自动寻找一个匹配的 PV,并将其绑定到该 PVC 上。
# 查看pvc详细yaml
[root@k8s-master ~/k8s-all]#kubectl -n yuchao get pvc -oyaml
apiVersion: v1
items:
- apiVersion: v1
kind: PersistentVolumeClaim
metadata:
annotations:
pv.kubernetes.io/bind-completed: "yes"
pv.kubernetes.io/bound-by-controller: "yes"
creationTimestamp: "2023-04-21T09:39:49Z"
finalizers:
- kubernetes.io/pvc-protection
name: pvc-nfs
namespace: yuchao
resourceVersion: "4118187"
uid: 788ba904-7aff-4dc0-b824-c54b7839b0c2
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
volumeMode: Filesystem
volumeName: nfs-pv # 可知PVC已经和PV绑定了
status:
accessModes:
- ReadWriteMany
capacity:
storage: 1Gi
phase: Bound
kind: List
metadata:
resourceVersion: ""
#访问模式,storage大小(pvc大小需要小于pv大小),以及 PV 和 PVC 的 storageClassName 字段必须一样,这样才能够进行绑定。
#PersistentVolumeController会不断地循环去查看每一个 PVC,是不是已经处于 Bound(已绑定)状态。如果不是,那它就会遍历所有的、可用的 PV,并尝试将其与未绑定的 PVC 进行绑定,这样,Kubernetes 就可以保证用户提交的每一个 PVC,只要有合适的 PV 出现,它就能够很快进入绑定状态。
# 而所谓将一个 PV 与 PVC 进行“绑定”,其实就是将这个 PV 对象的名字,填在了 PVC 对象的 spec.volumeName 字段上。
6.创建Pod挂载pvc
$ cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-pvc
namespace: yuchao
spec:
replicas: 1
selector: #指定Pod的选择器
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts: #挂载容器中的目录到pvc nfs中的目录
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim: #指定pvc
claimName: pvc-nfs
创建
[root@k8s-master ~/k8s-all]#kubectl create -f pvc-deployment.yaml
deployment.apps/nfs-pvc created
[root@k8s-master ~/k8s-all]#kubectl -n yuchao get po |grep nfs
nfs-pvc-79f876c88d-6pzpq 1/1 Running 0 42s
# 查看pod内挂载的nfs数据
[root@k8s-master ~/k8s-all]#kubectl -n yuchao exec -it nfs-pvc-79f876c88d-6pzpq -- sh
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # ls
index.html
/usr/share/nginx/html # cat index.html
chaoge666
/usr/share/nginx/html #
/usr/share/nginx/html #
[root@k8s-master ~/k8s-all]#curl 10.244.0.84/index.html
chaoge666
# 查看NFS服务端的数据
root@docker01 /data/k8s/yc-nginx]#echo 'chaoge666' > index.html
[root@docker01 /data/k8s/yc-nginx]#ls
index.html
[root@docker01 /data/k8s/yc-nginx]#ll
total 4
-rw-r--r-- 1 root root 10 Apr 21 17:47 index.html
[root@docker01 /data/k8s/yc-nginx]#
7.图解流程

storageClass动态挂载
在Kubernetes中,PV(Persistent Volume)是对集群中的物理存储资源的抽象表示,而PVC(Persistent Volume Claim)则是Pod请求存储资源的声明。PV和PVC是用来解决容器化应用程序中持久性存储的问题。
StorageClass是一种Kubernetes对象,它定义了如何动态地为PV和PVC分配存储资源。StorageClass可以指定用于创建PV的存储后端类型和配置选项,以及动态地分配和管理PV的策略。
在Kubernetes中,PV和PVC需要StorageClass来实现存储资源的动态分配和管理。通过指定一个特定的StorageClass,可以为PVC请求的存储资源分配相应的PV。如果没有指定StorageClass,将会使用默认的StorageClass来分配存储资源。
因此,使用StorageClass可以方便地进行存储资源的管理和分配,以满足不同应用程序的不同需求。StorageClass可以通过定义不同的存储后端类型和配置选项来支持不同的应用程序需求。例如,对于需要高性能和低延迟的应用程序,可以使用基于快速磁盘的StorageClass,而对于需要高容错性和可扩展性的应用程序,可以使用基于网络存储的StorageClass。
另外,StorageClass还可以动态地创建和管理PV。例如,可以定义一个基于云存储的StorageClass,当需要更多存储空间时,StorageClass可以动态地创建新的PV,并将其分配给PVC,以便应用程序可以无缝地扩展存储空间。
因此,StorageClass是Kubernetes中实现持久性存储的重要概念,它可以简化存储资源的管理和分配,以提高应用程序的可靠性和可扩展性。
工作里都用storageClass实现自动挂载。
正因为手工用pv、pvc的过程太繁琐,因此还有更方便的办法。
创建pv及pvc过程是手动,且pv与pvc一一对应,手动创建很繁琐。
因此,通过storageClass + provisioner的方式来实现通过PVC自动创建并绑定PV。

安装provisioner
Provisioner 和 storageClass 是 Kubernetes 中与存储相关的两个重要概念。
Provisioner 是 Kubernetes 中的一种插件机制,用于动态创建和删除持久卷(PersistentVolume)和持久卷声明(PersistentVolumeClaim)。
它能够自动化地将外部存储系统(如 NFS、GlusterFS、Ceph 等)中的存储资源映射为 Kubernetes 中的持久卷。
storageClass 是 Kubernetes 中的一种资源对象,用于定义动态分配的持久卷的属性。一个 storageClass 包含一组属性,如存储介质类型、I/O 类型、复制策略等,这些属性会被用于创建符合要求的持久卷。
当一个 Pod 请求使用持久卷时,Kubernetes 会通过 storageClass 查找符合要求的持久卷,并将其绑定到 Pod 中。如果没有符合要求的持久卷,Kubernetes 会调用对应的 provisioner 创建新的持久卷,并将其绑定到 Pod 中。
因此,可以将 provisioner 和 storageClass 看作是 Kubernetes 中存储资源的动态分配和管理机制。
它们可以方便地将外部存储系统中的资源映射为 Kubernetes 中的持久卷,并根据需要动态创建和删除持久卷。
创建NFS驱动器
https://github.com/kubernetes-retired/external-storage
在这个仓库里寻找驱动器安装yaml
nfs-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs-provisioner
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner # 1.先创建SA为何认证、鉴权,还要创建RBAC
containers:
- name: nfs-client-provisioner
image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME # 驱动器之一的名称
value: yuchao-nfs
- name: NFS_SERVER
value: 10.0.0.66
- name: NFS_PATH
value: /data/k8s
volumes:
- name: nfs-client-root
nfs:
server: 10.0.0.66
path: /data/k8s
nfs-rbac.yaml
kind: ServiceAccount
apiVersion: v1
metadata:
name: nfs-client-provisioner
namespace: nfs-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
namespace: nfs-provisioner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
namespace: nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: nfs-provisioner
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
namespace: nfs-provisioner
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
namespace: nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs-provisioner
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
Storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: "true" # 设置为default StorageClass
name: nfs
provisioner: yuchao-nfs
parameters:
archiveOnDelete: "true"
创建所有yaml
[root@k8s-master ~/k8s-all]#kubectl create ns nfs-provisioner
namespace/nfs-provisioner created
[root@k8s-master ~/k8s-all]#kubectl create -f nfs-rbac.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#kubectl create -f nfs-provisioner.yaml
deployment.apps/nfs-client-provisioner created
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#kubectl create -f storage-class.yaml
storageclass.storage.k8s.io/nfs created
[root@k8s-master ~/k8s-all]#
#检查pod,该驱动器是否运行
[root@k8s-master ~/k8s-all]#kubectl -n nfs-provisioner get po
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-6bf7c9796c-7m2pl 1/1 Running 0 27s
#检查storageclass
[root@k8s-master ~/k8s-all]#kubectl get storageclasses.storage.k8s.io
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs (default) yuchao-nfs Delete Immediate false 48s
[root@k8s-master ~/k8s-all]#
测试动态pv、pvc
如刚才所说,你已经创建好了nfs驱动器、storageClass
只需要直接编写pvc即可
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#cat pvc-auto-nginx.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
namespace: yuchao
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
storageClassName: nfs
创建且查看pvc、pvc的自动绑定
[root@k8s-master ~/k8s-all]# kubectl create -f pvc-auto-nginx.yaml
[root@k8s-master ~/k8s-all]#kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-cc925348-84eb-4469-8cba-60018e1244e2 1Gi RWX Delete Bound yuchao/test-pvc nfs 2m
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#kubectl -nyuchao get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pvc Bound pvc-cc925348-84eb-4469-8cba-60018e1244e2 1Gi RWX nfs 39h
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#
[root@k8s-master ~/k8s-all]#kubectl get storageclasses.storage.k8s.io
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs (default) yuchao-nfs Delete Immediate false 40h
[root@k8s-master ~/k8s-all]#
查看NFS服务端
pv自动对应了该nfs的文件夹
[root@docker01 ~]#
[root@docker01 ~]#cd /data/k8s/
[root@docker01 /data/k8s]#ls
yc-nginx yuchao-test-pvc-pvc-cc925348-84eb-4469-8cba-60018e1244e2
[root@docker01 /data/k8s]#
[root@docker01 /data/k8s]#ls -l
total 0
drwxr-xr-x 2 root root 24 Apr 21 17:47 yc-nginx
drwxrwxrwx 2 root root 6 Apr 23 10:46 yuchao-test-pvc-pvc-cc925348-84eb-4469-8cba-60018e1244e2
[root@docker01 /data/k8s]#cd yuchao-test-pvc-pvc-cc925348-84eb-4469-8cba-60018e1244e2/
pod使用NFS
$ cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: auto-nfs-pod
namespace: yuchao
spec:
replicas: 2
selector: #指定Pod的选择器
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts: #挂载容器中的目录到pvc nfs中的目录
- name: www
mountPath: /usr/share/nginx/html
volumes:
- name: www
persistentVolumeClaim: #指定pvc
claimName: test-pvc
测试访问pod、以及NFS
[root@k8s-master ~/k8s-all]#kubectl -n yuchao get po -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
auto-nfs-pod-7787455c49-nshmv 1/1 Running 0 18s 10.244.1.77 k8s-slave2 <none> <none>
auto-nfs-pod-7787455c49-r8spq 1/1 Running 0 18s 10.244.2.93 k8s-slave1 <none> <none>
[root@k8s-master ~/k8s-all]#curl 10.244.1.77
It's ok .
[root@k8s-master ~/k8s-all]#curl 10.244.2.93
It's ok .
###
[root@docker01 /data/k8s/yuchao-test-pvc-pvc-cc925348-84eb-4469-8cba-60018e1244e2]#echo "It's ok ." > index.html
[root@docker01 /data/k8s/yuchao-test-pvc-pvc-cc925348-84eb-4469-8cba-60018e1244e2]#ls
index.html
总结NFS动态挂载
在Kubernetes中,Storage-class、Provisioner、PV和PVC是存储相关的概念,它们的关系如下:
- Storage-class(存储类)是定义持久卷(Persistent Volume,PV)的类型的抽象。它是一个对象,定义了一组参数,这些参数可以被用来创建 PV。多个 PV 可以使用同一个 StorageClass,它会根据定义的参数动态地创建 PV。
- Provisioner(供应商)是一个 Kubernetes 控制器,用于自动化地创建 PV 和 PVC。Provisioner 监听 Kubernetes API,当 PVC 被创建时,它会自动创建对应的 PV,并将它们绑定在一起。
- PV(Persistent Volume)是 Kubernetes 中的一个对象,代表一个持久化存储卷。PV 是一个资源,它可以被分配给一个 Pod 使用,Pod 可以访问 PV 中的数据。PV 可以是静态的(手动配置)或者动态的(由 Provisioner 动态创建)。
- PVC(Persistent Volume Claim)是 Kubernetes 中的一个对象,它是 Pod 对 PV 的请求,它指定了 Pod 所需的存储卷的大小、访问模式和其他参数。PVC 可以被认为是一个声明,它声明了 Pod 所需的存储资源。
简单来说,Storage-class 定义了 PV 的类型,Provisioner 负责动态地创建 PV 和 PVC 并将它们绑定在一起,PV 代表一个持久化存储卷,PVC 则是 Pod 对 PV 的请求。
它们的关系是:Storage-class 定义了 PV 的类型,Provisioner 根据 Storage-class 创建 PV 和 PVC,并将它们绑定在一起,Pod 使用 PVC 请求 PV 来获取存储资源。

练习(nfs、pvc、mysql)
需求改造你的mysql、存储改为NFS。
如上述所说,创建一个PVC即可
[root@k8s-master ~/k8s-all]#cat pvc-auto-mysql.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: auto-pvc-mysql
namespace: yuchao
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
storageClassName: nfs
选择的存储类如下、是NFS类型的,并且指定了provisioner: yuchao-nfs,可以自动创建PV。
[root@k8s-master ~/k8s-all]#kubectl get storageclasses.storage.k8s.io -oyaml
apiVersion: v1
items:
- apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: "true"
creationTimestamp: "2023-04-21T10:23:03Z"
name: nfs
resourceVersion: "4122251"
uid: cc1d5e3a-5bd7-4036-b089-d289d6a35a3b
parameters:
archiveOnDelete: "true"
provisioner: yuchao-nfs
reclaimPolicy: Delete
volumeBindingMode: Immediate
kind: List
metadata:
resourceVersion: ""
创建PVC,并且修改Pod
[root@k8s-master ~/k8s-all]#kubectl -n yuchao get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
auto-pvc-mysql Bound pvc-ae643077-64ca-49d3-85a4-68750cb4cb4b 5Gi RWX nfs 3s
test-pvc Bound pvc-cc925348-84eb-4469-8cba-60018e1244e2 1Gi RWX nfs 40h
[root@k8s-master ~/k8s-all]#
检查NFS服务端,是否自动创建了共享目录
[root@docker01 /data/k8s]#ll
total 0
drwxr-xr-x 2 root root 24 Apr 21 17:47 yc-nginx
drwxrwxrwx 2 root root 6 Apr 23 11:35 yuchao-auto-pvc-mysql-pvc-ae643077-64ca-49d3-85a4-68750cb4cb4b
drwxrwxrwx 2 root root 24 Apr 23 11:25 yuchao-test-pvc-pvc-cc925348-84eb-4469-8cba-60018e1244e2
[root@docker01 /data/k8s]#
检查自动创建的PV
[root@k8s-master ~/k8s-all]#kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-ae643077-64ca-49d3-85a4-68750cb4cb4b 5Gi RWX Delete Bound yuchao/auto-pvc-mysql nfs 86s
pvc-cc925348-84eb-4469-8cba-60018e1244e2 1Gi RWX Delete Bound yuchao/test-pvc nfs 49m
[root@k8s-master ~/k8s-all]#
数据迁移,把原来的mysql数据,迁移到NFS共享目录里,后续让多个新mysql共享数据目录
# 1.先停掉mysql服务
[root@k8s-master ~/k8s-all]#kubectl -n yuchao scale deployment mysql --replicas 0
deployment.apps/mysql scaled
[root@k8s-master ~/k8s-all]#kubectl -n yuchao get po |grep mysql
[root@k8s-master ~/k8s-all]#
# 2.压缩且拷贝数据(我们之前部署mysql是hostPath类型)
# [root@k8s-master /opt/mysql]#kubectl -n yuchao edit deployments.apps mysql
[root@k8s-master /opt/mysql]#cd /k8s-mysql/
[root@k8s-master /k8s-mysql]#ls
auto.cnf ca.pem client-key.pem ib_buffer_pool ib_logfile0 mysql private_key.pem server-cert.pem sys
ca-key.pem client-cert.pem eladmin ibdata1 ib_logfile1 performance_schema public_key.pem server-key.pem
[root@k8s-master /k8s-mysql]#
[root@k8s-master /k8s-mysql]#python -m SimpleHTTPServer 9000
Serving HTTP on 0.0.0.0 port 9000 ...
# 3.NFS服务端下载数据
[root@docker01 /data/k8s]#wget 10.0.0.80:9000/mysql.tgz
--2023-04-23 11:41:44-- http://10.0.0.80:9000/mysql.tgz
Connecting to 10.0.0.80:9000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6363557 (6.1M) [application/octet-stream]
Saving to: ‘mysql.tgz’
100%[=================================================================================================================================================>] 6,363,557 --.-K/s in 0.07s
2023-04-23 11:41:44 (93.1 MB/s) - ‘mysql.tgz’ saved [6363557/6363557]
[root@docker01 /data/k8s]#
[root@docker01 /data/k8s/yuchao-auto-pvc-mysql-pvc-ae643077-64ca-49d3-85a4-68750cb4cb4b]#tar -xf mysql.tgz
[root@docker01 /data/k8s/yuchao-auto-pvc-mysql-pvc-ae643077-64ca-49d3-85a4-68750cb4cb4b]#ls
auto.cnf ca.pem client-key.pem ib_buffer_pool ib_logfile0 mysql performance_schema public_key.pem server-key.pem
ca-key.pem client-cert.pem eladmin ibdata1 ib_logfile1 mysql.tgz private_key.pem server-cert.pem sys
[root@docker01 /data/k8s/yuchao-auto-pvc-mysql-pvc-ae643077-64ca-49d3-85a4-68750cb4cb4b]#
修改deployment改为用NFS类型、以及去掉你mysql的nodeSelector、因为不再是hostPath、而是分布式的NFS文件系统。
75 terminationMessagePath: /dev/termination-log
76 terminationMessagePolicy: File
77 volumeMounts:
78 - mountPath: /var/lib/mysql
79 name: mysql-nfs # 容器挂载PVC
80 dnsPolicy: ClusterFirst
81 nodeSelector: # 删掉
82 mysql: "true"
83 restartPolicy: Always
84 schedulerName: default-scheduler
85 securityContext: {}
86 terminationGracePeriodSeconds: 30
87 volumes:
88 - name: mysql-nfs
89 persistentVolumeClaim: #改为你刚才创建的PVC
90 claimName: auto-pvc-mysql
91 status:
调整副本为1,启动新数据库
[root@k8s-master /k8s-mysql]#kubectl -n yuchao get po -owide -l app=mysql
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
mysql-559d5fcc8b-zfss9 1/1 Running 0 12s 10.244.0.90 k8s-master <none> <none>
[root@k8s-master /k8s-mysql]#
[root@k8s-master /k8s-mysql]#kubectl -n yuchao exec -it mysql-559d5fcc8b-zfss9 -- bash
root@mysql-559d5fcc8b-zfss9:/#
root@mysql-559d5fcc8b-zfss9:/# mysql -uroot -pwww.yuchaoit.cn
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.7.36 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| eladmin |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.01 sec)
mysql>
# 因此数据库迁移到NFS成功

再次图解
