Provisioning: PV的预制创建有两种模式:静态和动态供给模式:
静态供给模式: 需要先手动创建PV, 然后通过 PVC 申请 PV 并在 Pod 中使用,这种方式叫做静态供给(Static Provision)。
动态供给模式: 只需要创建PVC,系统根据PVC创建PV, 如果没有满足 PVC 条件的 PV,会动态创建 PV。相比静态供给,动态供给(Dynamical Provision)有明显的优势:不需要提前创建 PV,减少了管理员的工作量,效率高.
动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV。
部署NFS 服务( 10.68.56.11 主机上 )
# 创建 NFS 存储目录
mkdir -p /home/cicd
# 安装nfs服务
yum -y install nfs-utils rpcbind
# 修改配置文件
echo "/home/cicd *(rw,sync,no_root_squash,no_subtree_check)" >> /etc/exports
# 启动服务
systemctl start nfs && systemctl start rpcbind
# 设置开机启动
systemctl enable nfs-server && systemctl enable rpcbind
下面就分别实践这两种模式的创建跟使用:
NFS作为静态供给模式持久化存储卷
1
手动创建PV—>手动创建PVC—>POD挂载使用
- 创建PV
cat >> nfs-test-pv.yaml << EOF
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-test-pv
namespace: default
labels:
app: nfs-test-pv
spec:
capacity:
storage: 5Gi # 指定PV容量为5G
accessModes:
- ReadWriteOnce # 指定访问模式为 ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle # 指定当 PV 的回收策略为 Recycle
storageClassName: nfs # 定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。
nfs:
path: /nfs_data # 指定 PV 在 NFS 服务器上对应的目录
server: 10.68.56.11 # NFS Server地址
EOF
create_pv
STATUS 为 Available,表示 nfs-test-pv 就绪,可以被 PVC 申请。
接下来创建 PVC nfs-test-pv-claim:
- 创建PVC
cat >> nfs-test-pv-claim.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-test-pv-claim
namespace: default
spec:
accessModes: # 存储访问模式,此能力依赖存储厂商能力
- ReadWriteOnce
resources:
requests:
storage: 2Gi # 请求获得的pvc存储大小
storageClassName: nfs
EOF
create_pvc
从 kubectl get pvc 和 kubectl get pv 的输出可以看到 nfs-test-pv-claim 已经 Bound 到 nfs-test-pv,申请成功。
接下来就可以在 Pod 中使用存储了:
- 创建Pod
cat >> nfs-test-pod.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: nfs-test-pod
spec:
containers:
- name: nfs-test-pod
image: busybox
args:
- /bin/sh
- -c
- sleep 30000
volumeMounts:
- mountPath: "/nfs-data"
name: nfs-data
volumes:
- name: nfs-data
persistentVolumeClaim:
claimName: nfs-test-pv-claim
EOF
与使用普通 Volume 的格式类似,在 volumes 中通过 persistentVolumeClaim 指定使用 nfs-test-pv-claim 申请的 Volume。
create_pod
验证 PV 是否可用:
1
kubectl exec nfs-test-pod touch /nfs-data/SUCCESS
create_result
可见,在 Pod 中创建的文件 /nfs-data/SUCCESS 确实已经保存到了 NFS 服务器目录 /nfs_data/中。
如果不再需要使用 PV,可用删除 PVC 回收 PV:
- 回收PVC
持久化卷声明的保护
PVC 保护的目的是确保由 pod 正在使用的 PVC 不会从系统中移除,因为如果被移除的话可能会导致数据丢失。
注意:当 pod 状态为 Pending 并且 pod 已经分配给节点或 pod 为 Running 状态时,PVC 处于活动状态。
当启用PVC保护功能时,如果用户删除了一个 pod 正在使用的 PVC,则该 PVC 不会被立即删除。PVC 的删除将被推迟,直到 PVC 不再被任何 pod 使用。
您可以看到,当我直接删除上面POD正在使用的PVC时命令直接hang住了,此时虽然为 Teminatiing,但PVC 受到保护,Finalizers 列表中包含 kubernetes.io/pvc-protection:
1
kubectl delete pvc nfs-test-pv-claim
pvc_delete_status
等待 pod 状态变为 Terminated(删除 pod 或者等到它结束),然后检查,确认 PVC 被移除。
反之,如果一个PVC没有被pod使用则可以直接删除。
用户用完 volume 后,可以从允许回收资源的 API 中删除 PVC 对象。PersistentVolume 的回收策略告诉集群在存储卷声明释放后应如何处理该卷。目前,volume 的处理策略有:
Retain,不清理, 保留 Volume(需要手动清理)
Recycle,删除数据,即 rm -rf /thevolume/*(只有 NFS 和 HostPath 支持)
Delete,删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)
OK 以上是NFS创建静态模式创建PVC,以及PVC跟POD生命周期的一些实践,
NFS作为动态持久化存储卷
利用NFS client provisioner动态提供Kubernetes后端存储卷
想要动态生成PV,需要运行一个NFS-Provisioner服务,将已配置好的NFS系统相关参数录入,并向用户提供创建PV的服务。官方推荐使用Deployment运行一个replica来实现,当然也可以使用Daemonset等其他方式,这些都在官方文档中提供了。
前提条件是有已经安装好的NFS服务器,并且NFS服务器与Kubernetes的Slave节点都能网络连通。 所有下文用到的文件来自于git clone https://github.com/kubernetes-incubator/external-storage.git 的nfs-client目录
nfs-client-provisioner 是一个Kubernetes的简易NFS的外部provisioner,本身不提供NFS,需要现有的NFS服务器提供存储
PV以 n a m e s p a c e − {namespace}- namespace−{pvcName}- p v N a m e 的命名格式提供(在 N F S 服务器上) P V 回收的时候以 a r c h i e v e d − {pvName}的命名格式提供(在NFS服务器上) PV回收的时候以 archieved- pvName的命名格式提供(在NFS服务器上)PV回收的时候以archieved−{namespace}- p v c N a m e − {pvcName}- pvcName−{pvName} 的命名格式(在NFS服务器上)
- 获取nfs-client-provisioner配置文件
1
git clone https://github.com/kubernetes-incubator/external-storage.git
- 安装部署:
- 修改deployment文件并部署 deploy/deployment.yaml
需要修改的地方只有NFS服务器所在的IP地址(10.68.56.11),以及NFS服务器共享的路径(/nfs_data_2),两处都需要修改为你实际的NFS服务器和共享目录
cat deploy/deployment.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 10.68.56.11
- name: NFS_PATH
value: /nfs_data_2
volumes:
- name: nfs-client-root
nfs:
server: 10.68.56.11
path: /nfs_data_2
$ kubectl apply -f deploy/deployment.yaml # 执行部署
serviceaccount/nfs-client-provisioner created
deployment.extensions/nfs-client-provisioner created
- 修改StorageClass文件并部署 deploy/class.yaml
此处可以不修改,或者修改provisioner的名字,需要与上面的deployment的PROVISIONER_NAME名字一致。
cat deploy/class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
archiveOnDelete: "false"
# 执行部署
kubectl apply -f deploy/class.yaml
storageclass.storage.k8s.io/managed-nfs-storage created
# 查看StorageClass
kubectl get sc
NAME PROVISIONER AGE
managed-nfs-storage fuseim.pri/ifs 16m
# 设置这个managed-nfs-storage名字的SC为Kubernetes的默认存储后端
kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
$ kubectl get sc
NAME PROVISIONER AGE
managed-nfs-storage (default) fuseim.pri/ifs 19m
- 授权
如果您的集群启用了RBAC,或者您正在运行OpenShift,则必须授权provisioner。 如果你在非默认的“default”名称空间/项目之外部署,可以编辑deploy/rbac.yaml或编辑`oadm policy“指令。
如果启用了RBAC
需要执行如下的命令来授权。
cat deploy/rbac.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
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
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
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
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
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
kubectl create -f deploy/rbac.yaml
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
- 执行部署:
测试创建PVC
cat deploy/test-claim.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
$ kubectl create -f deploy/test-claim.yaml
persistentvolumeclaim/test-claim created
$ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-dsfasdf-0048-11e11-af7a-sadfadswerer 1Mi RWX Delete Bound default/test-claim managed-nfs-storage 9m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/test-claim Bound pvc-dsfasdf-0048-11e11-af7a-sadfadswerer 1Mi RWX managed-nfs-storage 9m
以上可以看到我们的pvc已经申请成功,等待POD挂载使用
测试创建POD
POD文件如下,作用就是在test-claim的PV里touch一个SUCCESS文件。
cat deploy/test-pod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: gcr.io/google_containers/busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
kubectl create -f deploy/test-pod.yaml
pod/test-pod created
# 启动POD,一会儿POD就是completed状态,说明执行完毕。
kubectl get pod | grep test-pod
NAME READY STATUS RESTARTS AGE
test-pod 0/1 Completed 0 18s
在NFS服务器上的共享目录下的卷子目录中检查创建的NFS PV卷下是否有”SUCCESS” 文件。
以上,说明我们部署正常,并且可以通过动态分配NFS的持久共享卷
参考文档:
https://kubernetes.io/docs/concepts/storage/storage-classes/