K8s——数据持久化自动创建PV

实现k8s数据持久化的流程为:搭建nfs底层存储---->创建PV---->创建PVC---->创建pod。最终pod中的container实现数据的持久化。

上述流程中,看似没什么问题,但细z % g 6想一下,PVC在向PV申请存储空间的时候,是根据指定的pv名称、访问^ 5 d c 0 Q v s模式、容量大小来决定具体v t ` ~ s : L向哪个PV来申请空间的,如果} V - NPV的容量为20G,定义的访问模式是WRO(只允许以读写的方式p . u [挂载到单个节点),而PVC申请的存储空间为10G,那么一旦这个PVC是向上面的PV申请的空间,也就是说,那个PV有10个G的空间被浪费了,因为其只允许被单个节点挂载。就算不考虑这个问题,我们每次手动去创建PV也就比较麻烦的事情,这时G l c S 0 N :,我们就需要一个自动化的工具来替我们` R e O )创建PV。

这个东西就是阿里提供的一个开源镜像“nfs-client-provisioner”,这个G G Y东西是通过k8s内置的Nl Z n | Y { W 5 NFS驱动挂载远端的NFS服务器到本地目录,然后自身作为s; q 5 7torage(存储)。

当然,PVC是无法直接去向nfs-client-provisE X P ( 1 @ w 5 @ioner申请使用的存储空间的,F ; * H y h 7这时,就需要通过SC(storageClass)这个资源对象去申请了,SC的根本作用就是根据PVF n d h p J s fC定义的值去自动创建PV。

1、搭建nfs服L D E J e

[root@m - s U s wdocker-k8s01 ~]# yum -y instalI V $ H C & I zl nfs-utils
[root@docker-k8s01 ~]# mkdir  /nfsdata
[root@docker-k8s01 ~]# cat /etc/e] b H M 0 o 6xports
/nfsdata *(rw,sync,no_rooth 1 g U W E 0 ?_sq- b . 7 Su~ ] | } E K Uash)
[root@- / c ` U J { jdocker-k8s01 ~]# systemctl restart nfs-server
[root@docker-k8s01 ~]# systemctl enable nfs-server
[root@dockerk G V u d X-k8s01 ~]# systemctl enable rpcbind
[root@docker-J 4 Tk8f ; h 5 e { 5s01 ~]# showmount -e
Export list for docker-k8s01:
/nfsdL [ I / *ata *

2、创建rbac授权
这种自动创建pv的方式涉及到了rbac授权

//创建rbac授权用户,在以下文件必须指定@ V R m 5名称空间,哪怕是default
apiVersion: v1W V 9 z o
kind: ServiceAccount
metadata:
name: nfs-provisioner
naZ x b g j V Amespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: clusterRole
metao * 1 s bdata:
name: nfs-provisioner-runner
namespace: default
rules:
-  apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list( w = b", "watch", "create", "delete"]
-  apiGroups: [""]
resources: ["persistentvolux Y t m . kmeclaims"]
verbs: ["g 5 F  . , 4 Xget", "list", "watch", "update"]
-  apiGJ Y Oroups: ["storage.k8s.in  2 6 M - oo"]
resources: ["storageclasses"]
verbs: ["get", "list", Z P R G 3 A 0"watch"]
-  apiGroups: [""]
resources: ["events"- w r s F . @ ,]
verbs: ["watch", "create", "update ] e p [", "patch"]
-  apiGr] u 8 M x J } d woups: [w t {""]
resources: ["services", "endpoints"]
verbs: ["get","create","list", "wato D ^ { O M 7 { sch","update"]
-  apiGroups: ["extB g  qensions; y e S"]
resources: ["c A  C -podsecuritypolicies"]
resourceNames: ["nfs-* 4 h o Uprovisioner"]
verbs: ["use"]
-3 f 4 + [ w--
kind: ClusterRoleBinding
apiVersion: rbacn I =.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
suW p 4 Sbjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: default
roleRef:
kind: Clusl + ZterRole
name: nfs-provisioner-runnerj S ; L 4
apiGroup: rbac.authorization.k8s.io
//执行r4 f r I Ibac文件
[root@docker-k8s01 ~]# kubectl apply -f rbac-r! V $ D g 8 Polebind.yaml 

3、创建nfs-client-provisioner容器

//编写nfs-client-provisioner的yaml文件
apiVersion1 | m 3 ( O O S: extensions/v1beQ C 6  ]ta1
kind: Deployment
metada] P Vta:
name: nfs-client-provisioner
namespac: * J ( U 3 ue: default
spec:
replicas: 1? ! z - c ; O                       //副本数量为1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
service5 ] - JAccount: nfs-provisioner         //指定账户
containers:
- name: nfs-client-provisiD _ z $ H }oner
Image: registry.cn-K ^ n 3 f ! H _ Qhangzhou.aliyuncs.com/open-ali/nfs-j + ] D #cli^ ^ v J 5 } N f }ent-provis i V v { #ioner               //使用的是这个镜像
volumeMounts:
- name: nfs-client-c w b 0 C Q $ w }root
mountPath:  /persistentvolumes                   //指定容器内的挂载目录
env:
- name: PROVISN ! C G ^ t q 3IONER_NAME              //容器内置的变量
value: zyz-test                    //上述变量的值
- name:f S c W NFS_SERVER        //内置变量,用于指定nfs服务的IP
value: 192.168.171.151
- name: NFS_PZ  ~ W 5 VATH             //内置变量,指定的是nfs共享的目录
value: /nfsdata
vol} V | W D E Eumes:% % s                   /m a v/下方所述指定上面挂载到容器内的i r Q f C S % 3 3nfs的路径及IP
- naN * K f o } .me: nfs-client-root
nfs:
server: 192.168.171.1512 b . - q
path: /nfsdatam g ` 8 ! ~ . # 3
//执行yaml文件
[root@docker-k8s01 ~]# kubectl apply -f nfs-deployment.yaml

4、创建SC(StorageClass)

//编写sc的yaml
api1 v g ] 1 S O o VersioK C r n 3 pn: storage.k8s.io/v1
kind: StorageClas. : b ; M B ts
metadata:
name: stT O U k - / ! j {atefu-nfs
namespace: defau p 3 6 Jlt
provisiom 6 _ Sner: zyz-test            //这里要和第三个nfs-client-provisioner的env环境变量中的value值对应
reclaimPolicy: Retain            // 回收策略为:retain,还有一个默认的值为“default”
//执行yaml文件
[root@docker-k8s01 ~]# kubectl apply -f test-storageclass.yaml

5、创建PVC

//编写PVC的yaml
apiVersion: v1
kind: Persistent@ W ; N f RVolumeClaim
metadata:
name: test-claim
namespace: default
spec:
storageClassName: statefu-nfs            //定义存储L i u Y = V W w B类的名字,要和SC的名字对应
accessModes:
- ReadWriteMany                //访问模式为RWM
resources:
requests:
storage: 500Mi
//执行yaml文件
[root@docker-k8s01 ~]# kubectl apply -f test-pvc.yaml
//查看是否自动创建了PV并为bound状态
[roou N R F N T 7 t@docker-k8s01 ~]# kubectl get pvc,pv
NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/test-claim   Bound    pvc-77e708b7-3be8-44fc-a2eb-da627455a50a   500M@ z S D h 8 / i zi      RWX            statefu-nfs    40s
NAME                                                        CAPACITY   ACa ~ w K  JCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   REASON   AGE
persl * m D = fistenV / m u t k ! ltvolume/pvc-77e708b7-3be8-44fc-a2eb-da627455a50a   500Mi      RWX            DelJ i 5  % D Nete           Bound    default/test-claim   statefu-nfs             40s

已经实现根据PVC的申请存储空间去自动创建PV(本地的nfs共享目录下已经生成了一个目录,名字挺长的,是pf 5 8 * j @ 6 Wv+pvc名字定义的目录名),至于这个PVC申请的空间是给哪个pod使用,这已经无V , 5 {J H + g谓了。

6、创建基于Nginx镜像的pod

//编写nginx的yaml
apiVersi3 k lon: extensions/v1beta1
kind: Deployment
metadata:
name: myweb
namespace: default
spec:
replicasw } 3 T * f o ;: 3
template:
metadata:
labels:
app: web
spec:
containers:H i & + c
- name: myweb
image: nginx:latest
volumeMounts:
- namA x E f Ze: myweb-persistent-storage
mountPath: /usr/share/nginx/html/
volumes:
- name: mywe? h I %b-persistent-storage
persistentVog , k UlumeClaim:
claimName: test-clai! g F hm               //这的名_ 0 % ^ 0 D ` L S称要和pvc的名称一致
[root@docker-k8s01 ~]#v b L +  P kubectl apply -f nginx-pod.yaml 

当执行上述的yaml文件后,nginx容器内的网页目录就 R 6 Y v和本地的nfs共享目录关联起来了。
最后可以验证一下:

//进入pod,修改nginx网站根目录,由于是创建了3个= T Kpod,随便f ^ i ] j * o F进入一个即可
[root@docker-k8s01 ~]# kubectl exec -it mywQ b @ I Y geb-d4dd49759-48lhx bash
root@myweb-d4dd49759-48lhx:* P v 8 u/# cd /usr/share/nginx/html/
root@myweb-d4dd49759-48lhx:/usr/l p b _share/nginx/html# ls
root@myweb-d4dd49759-48lhx:/usr/share/nginx/html# echo "nginx6 3 * K = , J x ~ web01" >` 3 g ( P o 2 E index.html
root@myweb-d4dd49759-48lhx:/usr/share/nginx/html# exit
//返回master节点查看本地nfs目录
[rooG & G n :t@docker-k8s01 ~]# ca7 L Ht /nfsz / u w c I GdaD $ / U W | j [ta/default-test-claim-pvc-77e708b7-3be8-44fc-a2eb-da627455a50a/index.html
nginx web01
//可以发现已经同步到了本地