目录
1 存储类 Storageclass 介绍
1.1 StorageClass 说明
1.2 StorageClass 的属性
2 存储分配器 NFS Client Provisioner
2.1 官网存储分配器的部署介绍
2.2 实现动态创建 PV 模版清单文件的介绍
2.2.1 Storageclass 存储类的模版
2.2.2 创建 Provisioner 制备器的模版
2.2.3 rbac 的模版
2.2.4 PVC 的模版
2.2.5 使用 pod 测试使用的模版
3 PV 动态供给的实践操作
3.1 修改完的声明步骤顺序:
3.2 rbac 创建sa权限
3.3 class 创建存储类
3.4 deployment(控制制备器)
3.5 PVC 创建卷申领
3.6 test-nginx (测试)
1 存储类 Storageclass 介绍
官网: https://github.com/kubernetes-sigs/nfs-subdir-external-provisionerhttps://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
1.1 StorageClass 说明
-
StorageClass提供了一种描述存储类(class)的方法,不同的class可能会映射到不同的服务质量等级和备份策略或其他策略等。
-
每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在StorageClass需要动态分配 PersistentVolume 时会使用到
StorageClass存储类 和 Provisioner制备器 的关联以及NFS服务器与StorageClass存储类的关联
整个步骤如下图也说得很明白,无非就是StorageClass需要使用到provisioner制备器去选择到底使用的是那一块存储,而 provisioner 有一个镜像nfs-subdir-external-provisioner此镜像就是专门来进行选择存储的类型,在使用这个镜像可以使用多种资源类型来创建,如deployment,pod 等等,这次使用的为deployment控制器 在创建完资源类型之后需要手动去指定存储服务器的地址,如这次使用的就为NFS服务器,得在deployment清单文件的volumes.nfs.server 指定NFS的服务器地址与在containers.env 中以键值对的方式去指定NFS的地址为变量。
StorageClass 存储类 和 PVC 的关联
StorageClass 存储类 定义了自己的名字,在PVC中为了使用存储类,得指定存储类的名称spec.storageClassName
1.2 StorageClass 的属性
属性说明:存储类 | Kubernetes本文描述了 Kubernetes 中 StorageClass 的概念。 建议先熟悉卷和持久卷的概念。StorageClass 为管理员提供了描述存储类的方法。 不同的类型可能会映射到不同的服务质量等级或备份策略,或是由集群管理员制定的任意策略。 Kubernetes 本身并不清楚各种类代表的什么。Kubernetes 存储类的概念类似于一些其他存储系统设计中的"配置文件"。StorageClass 对象 每个 StorageClass 都包含 provisioner、parameters 和 reclaimPolicy 字段, 这些字段会在 StorageClass 需要动态制备 PersistentVolume 以满足 PersistentVolumeClaim (PVC) 时使用到。StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数。作为管理员,你可以为没有申请绑定到特定 StorageClass 的 PVC 指定一个默认的存储类: 更多详情请参阅 PersistentVolumeClaim 概念。storage/storageclass-low-latency.yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: low-latency annotations: storageclass.kubernetes.io/is-default-class: "false" provisioner: csi-driver.example-vendor.example reclaimPolicy: Retain # 默认值是 Delete allowVolumeExpansion: true mountOptions: - discard # 这可能会在块存储层启用 UNMAP/TRIM volumeBindingMode: WaitForFirstConsumer parameters: guaranteedReadWriteLatency: "true" # 这是服务提供商特定的 默认 StorageClass 你可以将某个 StorageClass 标记为集群的默认存储类。 关于如何设置默认的 StorageClass, 请参见更改默认 StorageClass。https://kubernetes.io/zh/docs/concepts/storage/storage-classes/
Provisioner(存储分配器):用来决定使用哪个卷插件分配 PV,该字段必须指定。可以指定内部分配器,也可以指定外部分配器。外部分配器的代码地址为: kubernetes-incubator/external-storage,其中包括NFS和Ceph等。
Reclaim Policy(回收策略):通过reclaimPolicy字段指定创建的Persistent Volume的回收策略,回收策略包括:Delete 或者 Retain,没有指定默认为Delete。
2 存储分配器 NFS Client Provisioner
2.1 官网存储分配器的部署介绍
访问 kubernetes 官网
源码地址:https://github.com/kubernetes-sigs/nfs-subdir-external-provisionerhttps://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
-
NFS Client Provisioner是一个automatic provisioner,使用NFS作为存储,自动创建PV和对应的PVC,本身不提供NFS存储,需要外部先有一套NFS存储服务。
-
PV以 ${namespace}-${pvcName}-${pvName}的命名格式提供(在NFS服务器上)
-
PV回收的时候以 archieved-${namespace}-${pvcName}-${pvName} 的命名格式(在NFS服务器上)
点击项目中的 deploy(部署)
2.2 实现动态创建 PV 模版清单文件的介绍
模版文件内容如下
这些只是模版,之后还需修改
2.2.1 Storageclass 存储类的模版
2.2.2 创建 Provisioner 制备器的模版
2.2.3 rbac 的模版
此次只需要在里面修改命名空间就可以了
2.2.4 PVC 的模版
2.2.5 使用 pod 测试使用的模版
3 PV 动态供给的实践操作
3.1 修改完的声明步骤顺序:
rbac(创建权限) --> class(创建存储类) --> deployment(使用制备器) --> pvc(pvc 关联存储类调用制备器) --> test-nginx(测试)
# 将 github 上的项目烤下来
[root@k8s-master storageClass-dynamic]# ls
class.yaml deployment.yaml pvc.yaml rbac.yaml test-nginx.yml
3.2 rbac 创建sa权限
# 创建命名空间
[root@k8s-master storageClass-dynamic]# kubectl create namespace nfs-pvc-dynamic
# 修改模版参数
[root@k8s-master storageClass-dynamic]# vim rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs-pvc-dynamic # 指定命名空间
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- 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
# replace with namespace where provisioner is deployed
namespace: nfs-pvc-dynamic # 指定命名空间
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
# replace with namespace where provisioner is deployed
namespace: nfs-pvc-dynamic
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
# replace with namespace where provisioner is deployed
namespace: nfs-pvc-dynamic # 指定命名空间
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: nfs-pvc-dynamic # 指定命名空间
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
# 声明 rbac 清单文件
[root@k8s-master storageClass-dynamic]# kubectl apply -f 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 storageClass-dynamic]# kubectl get namespaces nfs-pvc-dynamic
NAME STATUS AGE
nfs-pvc-dynamic Active 118m
[root@k8s-master storageClass-dynamic]# kubectl -n nfs-pvc-dynamic get sa
NAME SECRETS AGE
default 0 123m
nfs-client-provisioner 0 90m
3.3 class 创建存储类
[root@k8s-master storageClass-dynamic]# vim class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client # 指定存储类名
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 制备器的名称
parameters:
archiveOnDelete: "false"
# 声明存储类
[root@k8s-master storageClass-dynamic]# kubectl apply -f class.yaml
# 查看存储类
[root@k8s-master storageClass-dynamic]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-client k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 88m
3.4 deployment(控制制备器)
[root@k8s-master storageClass-dynamic]# vim deployment.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-pvc-dynamic
spec:
replicas: 1
# 更新策略,此处设置为Recreate,表示更新时会先停止旧的Pod,然后再启动新的Pod
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
# 指定Pod使用的Service Account名称。Service Account用于Pod与API Server之间的认证,
# 以便Pod能够调用API Server进行存储类型的选取等操作。
# 注意:ServiceAccountName 需要与RBAC中定义的服务账户名称一致,
# 以确保有足够的权限来执行存储相关的操作
serviceAccountName: nfs-client-provisioner # 要与rbac中的sa名称相同,因为需要调用apiserver去选择使用哪一类型的存储,所以在这上面需要使用到创建的rbac的权限
# 定义了一个存储卷
volumes:
- name: nfs-client-root
nfs:
server: 192.168.239.50
path: /nfsdata
containers:
- name: nfs-client-provisioner # 使用的是制备器的镜像,并且此名称需要与storaClass中的存储类名一致
image: sig-storage/nfs-subdir-external-provisioner:v4.0.2 # 需要用到的镜像,使用docker拉取
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes # 将卷挂载到在容器内的这一个目录
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.239.50
- name: NFS_PATH
value: /nfsdata
# 声明制备器
[root@k8s-master storageClass-dynamic]# kubectl apply -f deployment.yaml
# 查看制备器是否正常运行
[root@k8s-master storageClass-dynamic]# kubectl -n nfs-pvc-dynamic get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-client-provisioner 1/1 1 1 121m
3.5 PVC 创建卷申领
[root@k8s-master storageClass-dynamic]# vim pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
namespace: nfs-pvc-dynamic
spec:
storageClassName: nfs-client # 与类名需要一致
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
# 声明 PVC
[root@k8s-master storageClass-dynamic]# kubectl apply -f pvc.yaml
# NFS 服务端查看是否正常创建 PV 存储卷
# 可以发现在NFS服务器上是以 ${namespace}-${pvcName}-${pvName} 的命名格式提供
[root@harbor nfsdata]# ls /nfsdata/
nfs-pvc-dynamic-test-claim-pvc-29a134a4-a4dc-40f6-a378-820de948d34a
3.6 test-nginx (测试)
[root@k8s-master storageClass-dynamic]# vim test-nginx.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-test
namespace: nfs-pvc-dynamic # 指定命名空间
spec:
volumes:
- name: nfs-pvc
persistentVolumeClaim: # 指定 PVC 的名称
claimName: test-claim
containers:
- image: nginx
name: nginx-test-01
volumeMounts:
- mountPath: /usr/share/nginx/html # 容器挂载点
name: nfs-pvc
[root@k8s-master storageClass-dynamic]# kubectl apply -f test-nginx.yml
# 这个时候由于是新的卷,不能直接去访问因为直接访问是没有默认发布文件,需要手动创建测试
[root@k8s-master storageClass-dynamic]# kubectl -n nfs-pvc-dynamic get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-client-provisioner-8c78dc5f9-5hrpb 1/1 Running 0 5m57s 10.244.1.40 k8s-node1 <none> <none>
nginx-test 1/1 Running 0 76s 10.244.2.67 k8s-node2 <none> <none>
# 在 NFS 服务器中创建index.html默认发布文件,这个卷会挂载到容器中的
# /usr/share/nginx/html/ 的目录中
[root@harbor nfsdata]# echo this is nfs-dynamic nginx > /nfsdata/nfs-pvc-dynamic-test-claim-pvc-29a134a4-a4dc-40f6-a378-820de948d34a/index.html
[root@k8s-master storageClass-dynamic]# kubectl -n nfs-pvc-dynamic get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-client-provisioner-8c78dc5f9-5hrpb 1/1 Running 0 5m57s 10.244.1.40 k8s-node1 <none> <none>
nginx-test 1/1 Running 0 76s 10.244.2.67 k8s-node2 <none> <none>
[root@k8s-master storageClass-dynamic]# curl 10.244.2.67
this is nfs-dynamic nginx