k8s无脑系列(七)- NFS存储(动态存储)
1. 为什么需要动态存储
大概其的说一说,不一定对。总之一开始就觉得是个好东西。用到了,自然能体会到好处。
为每一个需要存储的资源编写pv,pvc很繁琐。
相同类型的请求有很多,急需快速可控的方案来实现动态申请。pvc申请,自动绑定pv
需要可以精细控制的存储回收重利用。既要保证容量,又要保证数据安全
2. 了解StorageClass
2.1 基础术语
- pv - Persistent Volume(持久化存储卷)
- pvc - Persistent Volume Claim(持久化存储卷请求)
- pvp - Persistent Volume Provisioner(持久化存储卷供应者)
- cluster role 集群操作角色,直接翻译role为角色,引申含义是角色具备哪些权限
2.1 原理
管理员创建Provisioner(供应者),负责为外部请求提供pv(持久化存储卷)实例
StorageClass代替pvc(持久存储卷请求)向绑定的Provistioner发出pv(持久化存储卷)实例的请求
Pod绑定的pvc通过pvc获取pv实例进行存储
3. 前期准备
物料 | 内容 | 备注 |
---|---|---|
nfs服务 | 192.168.56.4 | 一台 |
存储目录 | /data/nfs/db-svc-dynamic-volume | 用于存放数据 |
k8s集群 | 无脑系列有介绍 | 版本1.16.4 |
3.1 Yaml涉及的概念
名称 | 解释 | 备注 |
---|---|---|
StorageClass | k8s API Doc | |
ServiceAccount | 服务账户 | |
Role/ClusterRole | 角色/集群角色 | |
RoleBinding/ClusterRoleBinding | 角色与账户绑定 |
3.2 先定义服务账户与权限
定义一个服务账户,该账户负责向集群申请资源。
定义“集群角色”,“角色”并与服务账户绑定。所以,yaml中才会分五部分。分别是
- service account
- cluster role
- cluster role 与 service account绑定
- role
- role 与 service account 绑定
nfs-storage-rbac.yaml
apiVersion: v1
# 定义服务账户
kind: ServiceAccount
metadata:
# 名字要知命达意,这个账户专门为数据库服务
# {用途}-svc-{卷类型}-account
name: db-svc-nfs-account
namespace: default
---
# 定义集群角色声明该角色的权限列表,可以看出全是存储相关
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
# 与 db-svc-nfs-account 相呼应
name: db-svc-nfs-cluster-role
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"]
---
# 定义完角色后,就要将ServiceAccount与ClusterRole来绑定
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: db-svc-nfs-account-cluster-role-bind
subjects: # 这里用的数组结构,那么可以认为这一个“角色”可以被多个账户绑定
- kind: ServiceAccount
# 账户名字,见ServiceAccount的name
name: db-svc-nfs-account
namespace: default
roleRef:
kind: ClusterRole
# 角色的名字,见ClusterRole的name
name: db-svc-nfs-cluster-role
apiGroup: rbac.authorization.k8s.io
---
# 专门用来操作pvc与pv绑定时,ServiceAccount可以使用的权限
kind: Role # 角色
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: db-svc-nfs-role
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
# 与角色绑定的ServiceAccount
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: db-svc-nfs-account-role-bind
subjects:
- kind: ServiceAccount
# 账户名字,见ServiceAccount的name
name: db-svc-nfs-account
namespace: default
roleRef:
kind: Role
# 角色名字,见role
name: db-svc-nfs-role
apiGroup: rbac.authorization.k8s.io
$kubectl create -f nfs-storage-rbac.yaml
serviceaccount/db-svc-nfs-account created
clusterrole.rbac.authorization.k8s.io/db-svc-nfs-cluster-role created
clusterrolebinding.rbac.authorization.k8s.io/db-svc-nfs-account-cluster-role-bind created
role.rbac.authorization.k8s.io/db-svc-nfs-role created
rolebinding.rbac.authorization.k8s.io/db-svc-nfs-account-role-bind created
3.3 创建StorageClass
nfs-storage-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: db-svc-nfs-storage-class
# 这个名字要记住
provisioner: db-svc-nfs-provistioner
parameters:
archiveOnDelete: "false"
reclaimPolicy: Retain
3.4 创建NFS Provisioner
nfs-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: db-svc-nfs-provisioner
labels:
app: db-svc-nfs-provisioner
namespace: default
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: db-svc-nfs-provisioner
template:
metadata:
labels:
app: db-svc-nfs-provisioner
spec:
# 这里说明,用上面创建的service account来创建pv
serviceAccountName: db-svc-nfs-account
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env: #------ 这里是有学问的,见3.7
- name: PROVISIONER_NAME
value: db-svc-nfs-provistioner
- name: NFS_SERVER
value: 192.168.56.4
- name: NFS_PATH
value: /data/nfs/db-svc-dynamic-volume
volumes:
- name: db-svc-dynamic-volume
nfs: #----- 这里是有学问的,见3.7
server: 192.168.56.4
path: /data/nfs/db-svc-dynamic-volume
$kubectl create -f nfs-provisioner.yaml
3.5 创建Persistent Volume Claim
nfs-dynamic-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mysql-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: db-svc-nfs-storage-class
$kubectl create -f nfs-dynamic-pvc.yaml
*注意:如果系统报告下面的错误,说明您看过了无脑系列其它部分内容
Error from server (AlreadyExists): error when creating "nfs-dynamic-pvc.yaml": persistentvolumeclaims "mysql-pvc" already exists
请调用如下命令删除
$kubectl delete pvc mysql-pvc
3.6 校验系统是否正常运行
$kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-e95e6bfb-aeba-4a96-b8eb-90c0db607ad9 1Gi RWO Retain Bound default/mysql-pvc db-svc-nfs-storage-class 17m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/mysql-pvc Bound pvc-e95e6bfb-aeba-4a96-b8eb-90c0db607ad9 1Gi RWO db-svc-nfs-storage-class 17m
出现了ersistentvolume/pvc-e95e6bfb-aeba-4a96-b8eb-90c0db607ad9 这样的PV
- mysql-pvc状态显示‘Bound’
系统正常运行!
3.7 多问一个为什么
为什么Provisioner中出现了重复设定NFS的内容呢?
说一下nfs-client-provisioner这个镜像
这个镜像的代码在Github中,查看代码得出结论
与集群ApiServer联通,并完成PV的创建过程。
-
在创建PV过程中,需要用到NFS_SERVER与NFS_PATH这两个变量,并传递给新建的PV
$kubectl describe pv pvc-e95e6bfb-aeba-4a96-b8eb-90c0db607ad9 Name: pvc-e95e6bfb-aeba-4a96-b8eb-90c0db607ad9 Labels: <none> Annotations: pv.kubernetes.io/provisioned-by: db-svc-nfs-provistioner Finalizers: [kubernetes.io/pv-protection] StorageClass: db-svc-nfs-storage-class Status: Bound Claim: default/mysql-pvc Reclaim Policy: Retain Access Modes: RWO VolumeMode: Filesystem Capacity: 1Gi Node Affinity: <none> Message: Source: Type: NFS (an NFS mount that lasts the lifetime of a pod) Server: 192.168.56.4 <--------这里 Path: /data/nfs/db-svc-dynamic-volume/default-mysql-pvc-pvc-e95e6bfb-aeba-4a96-b8eb-90c0db607ad9 ReadOnly: false Events: <none>
之所以还需要给镜像挂载一个volume,是因为需要代码来完成集群给PV下达的reclaimPolicy指令,并完成具体操作