持久化存储

关于k8s中的存储字段信息介绍可以通过该命令进行查看:kubectl explain pods.spec.volumes 如下图(只截图了部分内容)

k8s存储类型:emptyDir、hostPath、nfs、pvc及存储类storageclass的静态/动态创建pv_K8s

在k8s中使用存储卷通常需要经历如下两个步骤:

1、创建pod时定义volume,并指定这个volume关联到哪个存储上

2、在容器中使用volumemounts挂载对应需要被关联的存储

一、存储类型 emptyDir

该字段属于是存储方案中的临时目录,常用于测试时使用,存放的数据可有可无,pod删除后该存放的数据也会一起删除,生产中不建议使用该字段进行存储数据。

定义的存储卷会在创建pod时在pod所在的节点上创建一个临时目录,它的数据与容器内指定挂载存储的路径中的数据是同步的。

缺点:数据会随着pod删除一起消失,无法有效保存

1.1 创建pod

#创建pod并挂载存储,且将存储挂载到pod中容器内的/test路径下
[root@k8s-master ~]# vim emptydir.yaml

apiVersion: v1
kind: Pod
metadata:
  name: emptydir
spec:
  containers:
  - name: mynginx
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:             #定义挂载存储
    - name: mynginx-volums    #定义被关联存储卷的名称(需要写关联的存储卷的名称)
      mountPath: /test        #定义将存储卷挂载到运行的容器内的/test路径下
  volumes:                    #定义存储类型(emptydir 表示临时目录)
  - name: mynginx-volums      #定义存储卷的名称  (需要与volumeMounts字段的name定义的名称一致,要被关联到)
    emptyDir: {}              #"{}"表示将这个临时目录做成卷


#创建
[root@k8s-master ~]# kubectl get pods -owide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE          NOMINATED NODE   READINESS GATES
emptydir   1/1     Running   0          20s   10.244.126.1   k8s-worker2   <none>           <none>

#查看pod详细信息,查看容器内存储挂载路径
[root@k8s-master ~]# kubectl describe pods emptydir | grep -i -A2 mounts
    Mounts:
      /test from mynginx-volums (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vmfvq (ro)

#查看存储的字段类型及其它信息
[root@k8s-master ~]# kubectl describe pods emptydir | grep -i -A4 Volumes
Volumes:
  mynginx-volums:
    Type:       EmptyDir (a temporary directory that shares a pod's lifetime)
    Medium:     
    SizeLimit:  <unset>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.

1.2 查看node节点存储挂载路径

通过创建pod的yaml文件查找pod所在节点生成的临时目录路径

#查找使用yaml文件创建pod时的完成yaml文件,并过滤pod的uid
[root@k8s-master ~]# kubectl get pods emptydir -o yaml | grep uid
  uid: b2d938cf-5263-4f03-9d47-31fcc66f5faa

#然后在pod所在节点通过tree查看/var/lib/kubelet/pods/ 路径下pod的uid 得到该路径下的所有路径信息
[root@k8s-master ~]# ssh k8s-worker2
[root@k8s-worker2 ~]# yum -y install tree
[root@k8s-worker2 ~]# tree /var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa
/var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa
├── containers
│   └── mynginx
│       └── 6c89e1c6
├── etc-hosts
├── plugins
│   └── kubernetes.io~empty-dir
│       ├── mynginx-volums
│       │   └── ready
│       └── wrapped_kube-api-access-vmfvq
│           └── ready
└── volumes
    ├── kubernetes.io~empty-dir
    │   └── mynginx-volums
    └── kubernetes.io~projected
        └── kube-api-access-vmfvq
            ├── ca.crt -> ..data/ca.crt
            ├── namespace -> ..data/namespace
            └── token -> ..data/token

#进入该uid路径下可查看
[root@k8s-worker2 ~]# ls /var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa/  //查看到容器的路径信息
containers  etc-hosts  plugins  volumes
[root@k8s-worker2 ~]# cd /var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa/  //进入挂载的该容器路径内
[root@k8s-worker2 b2d938cf-5263-4f03-9d47-31fcc66f5faa]# ls
containers  etc-hosts  plugins  volumes
[root@k8s-worker2 b2d938cf-5263-4f03-9d47-31fcc66f5faa]# ls volumes/
kubernetes.io~empty-dir  kubernetes.io~projected
[root@k8s-worker2 b2d938cf-5263-4f03-9d47-31fcc66f5faa]# ls volumes/kubernetes.io~empty-dir/  //如下路径即是与容器内的数据同步
mynginx-volums
[root@k8s-worker2 b2d938cf-5263-4f03-9d47-31fcc66f5faa]# ls volumes/kubernetes.io~empty-dir/mynginx-volums/  //查看为空
[root@k8s-worker2 b2d938cf-5263-4f03-9d47-31fcc66f5faa]# 

#这个就是完整存储路径/var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa/volumes/kubernetes.io~empty-dir/mynginx-volums/
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.

1.3 验证数据同步

在pod所在node节点上的临时目录中创建/删除数据验证容器内的数据是否同步

#在node节点存储路径中创建 test001
[root@k8s-worker2 ~]# mkdir /var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa/volumes/kubernetes.io~empty-dir/mynginx-volums/test001
[root@k8s-worker2 ~]# ls /var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa/volumes/kubernetes.io~empty-dir/mynginx-volums/
test001

#进入容器中验证数据是否同步
[root@k8s-master ~]# kubectl exec -it emptydir -- /bin/bash
root@emptydir:/# ls /test/
test001             //已同步创建

#测试删除pod 查看node节点中的临时目录是否会自动删除
[root@k8s-master ~]# kubectl delete -f emptydir.yaml 
pod "emptydir" deleted

#节点中验证该路径已删除
[root@k8s-worker2 ~]# ls /var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa
ls: 无法访问/var/lib/kubelet/pods/b2d938cf-5263-4f03-9d47-31fcc66f5faa: 没有那个文件或目录
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

二、存储类型 hostPath

该字段类型是指pod挂载宿主机的目录或文件,当pod调度到节点1上时,指定该节点上的一个目录或文件给这个pod使用,与emptyDir不同的是,pod删除后节点1上挂载的存储卷不会被删除依然存在。

如果再次创建一个pod时还想使用节点1上的这个存储卷,那么就需要将pod调度到这个存储卷所在的节点1上,即使调度到k8s集群内的其它节点上且其他节点上也有相同路径,但是数据也不会同步,只有将pod调度到相同的节点上才可以。


缺点:单节点,想要数据一直与某pod同步,就需要pod更新或创建时必须要在volumes所在的node节点上。


总而言之,如果删除pod之后,再次创建pod想要数据不丢失,就需要将pod还重建在之前所删除时所在的节点上。

hostPath 字段下的type类型具有如下类型 (默认为空)

官方文档地址: https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

取值

行为


空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。

DirectoryOrCreate

如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 kubelet 相同的组和属主信息。

Directory

在给定路径上必须存在的目录。

FileOrCreate

如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 kubelet 相同的组和所有权。

File

在给定路径上必须存在的文件。

Socket

在给定路径上必须存在的 UNIX 套接字。

CharDevice

在给定路径上必须存在的字符设备。

BlockDevice

在给定路径上必须存在的块设备。

2.1 创建pod

需求,pod中创建两个容器,使它们的存储数据同步

将pod所在节点宿主机的/test001 目录做成存储卷,将/test001挂载到pod中第一个容器的/nginx-test路径下和第二个容器的/httpd-test路径下,并使它们之间的数据同步。

[root@k8s-master ~]# vim hostpath.yaml

apiVersion: v1
kind: Pod
metadata:
  name: hostpath
spec:
  containers:
  - name: mynginx
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts: 
    - name: myvolumes
      mountPath: /nginx-test
  - name: mytomcat               #创建pod中的第二个容器
    image: tomcat
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: myvolumes
      mountPath: /tomcat-test
  volumes:
  - name: myvolumes
    hostPath: 
      path: /test001             #指定pod所在节点宿主机的某个目录为volumes
      type: DirectoryOrCreate    #表示如果pod所在节点没有/test001目录,那么将创建,并赋予0755权限


#创建
[root@k8s-master ~]# kubectl apply -f hostpath.yaml 
pod/hostpath created

[root@k8s-master ~]# kubectl get pods -owide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE          NOMINATED NODE   READINESS GATES
hostpath   2/2     Running   0          5s    10.244.126.3   k8s-worker2   <none>           <none>

#如果两个容器需要挂载不同的volumes,只需要在yaml文件中再次添加编写创建一个volumes并在容器的 volumeMounts字段下关联即可。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

2.2 验证同步数据

创建删除数据验证pod所在宿主机及pod中容器内的数据是否同步

#查看node节点是否创建了volumes
[root@k8s-master ~]# ssh k8s-worker2
[root@k8s-worker2 ~]# ll /test001/
总用量 0

#创建文件验证容器内数据是否同步
[root@k8s-worker2 ~]# touch /test001/test002
[root@k8s-worker2 ~]# ls /test001/
test002

#进入容器1 nginx 验证
root@hostpath:/# ls /nginx-test/
test002        //验证已同步

#进入容器2验证
root@hostpath:/usr/local/tomcat# ls /tomcat-test/
test002        //验证已同步
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

2.3 测试删除/创建pod数据是否保留

测试删除pod之后创建pod在另一个节点,及恢复pod到原来的节点,测试数据同步状态。

#删除pod,验证pod所在宿主机是否也会同步删除存储数据
[root@k8s-master ~]# kubectl delete -f hostpath.yaml 
pod "hostpath" deleted
[root@k8s-master ~]# ssh k8s-worker2
[root@k8s-worker2 ~]# ls /test001/
test002              //验证pod删除后 宿主机volumes还在


#创建pod在另一个节点,在yaml文件中的spec字段下添加 nodeName并指定node节点的主机名称,如下所示
[root@k8s-master ~]# cat hostpath.yaml | grep -A 3 spec
spec:
  nodeName: k8s-worker1
  containers:
  - name: mynginx

#创建pod
[root@k8s-master ~]# kubectl apply -f hostpath.yaml 
pod/hostpath created

#已成功调度到k8s-worker1 节点
[root@k8s-master ~]# kubectl get pods -owide
NAME       READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
hostpath   2/2     Running   0          6s    10.244.194.66   k8s-worker1   <none>           <none>

#进入容器验证数据是否同步 (验证都为空 并未同步)
[root@k8s-master ~]# kubectl exec -it hostpath -c mynginx -- /bin/bash
root@hostpath:/# ls -l /nginx-test/
total 0
root@hostpath:/# exit 
exit
[root@k8s-master ~]# kubectl exec -it hostpath -c mytomcat -- /bin/bash
root@hostpath:/usr/local/tomcat# ls -l /tomcat-test/
total 0

#删除pod 重新将pod创建在之前删除的node节点上并验证
[root@k8s-master ~]# kubectl delete -f hostpath.yaml 
pod "hostpath" deleted

#修改yaml文件 将 nodeName指定的node节点修改为之前pod所在节点的主机名称,如下所示
[root@k8s-master ~]# cat hostpath.yaml | grep -A 3 spec
spec:
  nodeName: k8s-worker2
  containers:
  - name: mynginx
  
#创建
[root@k8s-master ~]# kubectl apply -f hostpath.yaml 
pod/hostpath created
[root@k8s-master ~]# kubectl get pods -owide
NAME       READY   STATUS    RESTARTS   AGE   IP             NODE          NOMINATED NODE   READINESS GATES
hostpath   2/2     Running   0          8s    10.244.126.4   k8s-worker2   <none>           <none>

#进入容器内查看(验证 数据已重新同步)
[root@k8s-master ~]# kubectl exec -it hostpath -c mynginx -- /bin/bash
root@hostpath:/# ls /nginx-test/
test002
root@hostpath:/# exit 
exit
[root@k8s-master ~]# kubectl exec -it hostpath -c mytomcat -- /bin/bash
root@hostpath:/usr/local/tomcat# ls /tomcat-test/
test002
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.

三、存储类型 NFS

使用nfs类型的方式进行存储数据,可以避开hostPath方式不能随机在node节点上创建pod的缺点,

但是nfs的缺点是,如果做nfs共享存储的节点挂掉,那么数据一样也会丢失。

需要在k8s集群中的控制节点和工作节点都安装nfs-utils 

3.1 安装配置 nfs

#安装 nfs-utils 并启动服务
[root@k8s-master ~]# yum -y install nfs-utils
[root@k8s-master ~]# systemctl enable nfs --now

#在控制节点上创建NFS共享存储目录(下方内容只在控制节点配置)
[root@k8s-master ~]# mkdir -p /nfs/volumes

#配置访问权限  (*表示所有地址,如果限制只可某一个ip访问的话,例:192.168.xx.0/24)
[root@k8s-master ~]# vim /etc/exports  //加入如下内容
/nfs/volumes *(rw,no_root_squash)

#使配置生效
[root@k8s-master ~]# exportfs -arv
exporting *:/nfs/volumes

#
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

3.2 创建pod

使用deployment控制器来创建pod

#创建控制器yaml文件
[root@k8s-master ~]# vim deploy-nfs.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy001             #定义控制器名称
spec:
  replicas: 3                 #定义pod副本数
  selector:                   #定义标签选择器
    matchLabels:              #定义匹配pod的标签
      myname: pod-001
  template:                   #定义pod模板
    metadata:
      labels:                 #定义模板标签,与上方一致要被匹配到
        myname: pod-001
    spec:                     #开始定义模板中的pod资源
      containers:
      - name: mynginx-test-nfs
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          protocol: TCP
        volumeMounts:         #定义存储挂载类型
        - name: nginx-nfs-volumes  #定义挂载存储卷的名称,要与下方volumes字段下的name一致,要匹配它
          mountPath: /usr/share/nginx/html  #定义pod中容器内的共享路径(我这里挂载到了nginx的首页)
      volumes:                     #定义volumes
      - name: nginx-nfs-volumes    #定义名称 要与上方volumeMounts字段下的name一致,要被匹配到
        nfs:
          path: /nfs/volumes       #定义nfs共享路径
          server: 192.168.57.131   #定义配置nfs共享的节点IP
          
#创建
[root@k8s-master ~]# kubectl apply -f nfs.yaml 
deployment.apps/deploy001 created

[root@k8s-master ~]# kubectl get pods -owide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy001-57f85f4c7d-hjzqn   1/1     Running   0          6s    10.244.126.2    k8s-worker2   <none>           <none>
deploy001-57f85f4c7d-jmgqr   1/1     Running   0          6s    10.244.126.1    k8s-worker2   <none>           <none>
deploy001-57f85f4c7d-wmxzk   1/1     Running   0          6s    10.244.194.66   k8s-worker1   <none>           <none>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.

3.3 验证数据同步

在配置了nfs共享的控制节点中创建\删除来验证nginx容器内的挂载路径是否达到数据同步

#在nfs共享路径中创建index.html并写入如下内容
[root@k8s-master ~]# touch /nfs/volumes/index.html
[root@k8s-master ~]# echo How are you ? >> /nfs/volumes/index.html

#访问三个pod中的nginx容器进行测试
[root@k8s-master ~]# curl 10.244.126.2:80
How are you ?
[root@k8s-master ~]# curl 10.244.126.1:80
How are you ?
[root@k8s-master ~]# curl 10.244.194.66:80
How are you ?

#进入其中一个pod的容器中查看yaml文件中定义的共享路径
[root@k8s-master ~]# kubectl exec -it deploy001-57f85f4c7d-hjzqn -- /bin/bash
root@deploy001-57f85f4c7d-hjzqn:/# ls /usr/share/nginx/html/
index.html
root@deploy001-57f85f4c7d-hjzqn:/# cat /usr/share/nginx/html/index.html 
How are you ?
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

3.4 删除pod创建新pod测试数据同步

由于是使用的deployment控制器来管理的pod,删除一个会自动创建一个新的pod出来,测试删除一个pod,重新创建pod之后,验证数据是否同步。

#删除其中一个pod
[root@k8s-master ~]# kubectl delete pods deploy001-57f85f4c7d-hjzqn
pod "deploy001-57f85f4c7d-hjzqn" deleted

#查看自动创建之后查看新创建的pod信息
[root@k8s-master ~]# kubectl get pods -owide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy001-57f85f4c7d-chxh2   1/1     Running   0          5s    10.244.126.3    k8s-worker2   <none>           <none>
deploy001-57f85f4c7d-jmgqr   1/1     Running   0          19m   10.244.126.1    k8s-worker2   <none>           <none>
deploy001-57f85f4c7d-wmxzk   1/1     Running   0          19m   10.244.194.66   k8s-worker1   <none>           <none>

#验证测试请求新创建pod的nginx服务
[root@k8s-master ~]# curl 10.244.126.3:80
How are you ?
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

四、存储类型 PVC/storageclass

PVC简介:

PersistentVolume(PV)

它是k8s集群中的一块存储,由管理员配置的或者使用存储类动态配置。

它是集群中的资源,就像pod是k8s集群资源一样。

PV是容量插件,如Volumes,其生命周期独立于使用PV的任何单个pod,也就是说想要在k8s集群中使用PV的话,就需要宿主机的存储目录,或者是nfs共享的目录。

PersistentVolumeClaim(PVC)

它是一个持久化存储卷,创建pod的时候可以将pvc做成存储卷,pvc使用的是pv的资源,

使用pvc时需要有一个符合条件的pv来让pvc申请使用,这样pvc才能做成卷挂到pod中给容器使用,就像创建pod时需要找node节点去调度一样。


PVC和PV的工作原理

PV是集群中的资源。 PVC是对这些资源的请求。


PV和PVC之间的相互作用遵循以下生命周期:

1、pv的供应方式:

     可以通过两种方式配置PV:静态或动态。

     静态:需要手动创建很多pv,它们包含可供群集用户使用的实际存储的详细信息。它们存在于Kubernetes API中,在创建pvc的时候才能找到事先创建好的pv来使用。

     动态:不用事先创建pv,在创建pvc的时候指定一个存储类,需要多大的pv就申请多大的,存储类会自动划分出来以供pvc使用。

2、绑定:

     pvc使用pv的时候,pvc必须要找到符合条件的pv才可使用,否则会显示保持未绑定状态。

3、使用方式:

     a. 需要有一个存储服务器,把它划分多个存储空间并做成pv

     b. 在创建pod定义使用存储卷的时候,可以先创建pvc,让pvc与事先准备好的pv做一个绑定,然后在定义pod的时候把pvc做成卷挂到pod容器里就可以了。

     c. pvc与pv关系一一对应,如果创建的pv被其中一个pvc绑定使用了,那么其他的pvc就不能再使用这个pv

     d. 如果创建pvc的绑定pv的时候没有任何一个pv满足条件,那么这个pvc就会处于Pending状态。

4、回收策略:

     创建pod时使用pvc,pvc与pv进行绑定,删除pod时,绑定的pvc与pv就会解除,

解除之后的pv有常用的两种处理方式:

     a. Retain     //保留:(默认配置)当解除pvc的时候,pv依然存在,处于released状态,但是它不能被其他pvc绑定使用,里面数据依然存在。

     b. Delete     //删除:解除删除pvc的时候,pv也会一并被删除,数据也会消失。

 

pv和pvc字段信息可通过如下命令进行查看:

kubectl explain pv

kubectl explain pvc

4.1静态创建pv

静态创建pv需要手动的指定创建pv,然后在创建pvc时进行绑定,下面演示步骤及效果。

4.1.1创建pv

使用nfs共享目录做存储pv(上方标题三已配置nfs,在增加些路径即可)

(可以先删除上方NFS测试时配置的pod及nfs文件路径)

#创建共享目录 (在控制节点创建)
[root@k8s-master ~]# for i in {01..10};do mkdir -p /nfs/volumes001/pv$i ;done
[root@k8s-master ~]# ls /nfs/volumes001/
pv01  pv02  pv03  pv04  pv05  pv06  pv07  pv08  pv09  pv10

#配置nfs(将这十个目录做成pv)
[root@k8s-master ~]#  for i in `ls /nfs/volumes001/` ; do echo /nfs/volumes001/$i *\(rw,no_root_squash\) >> /etc/exports; done
[root@k8s-master ~]# cat /etc/exports        //将十个目录加入到配置文件中
/nfs/volumes001/pv01 *(rw,no_root_squash)
/nfs/volumes001/pv02 *(rw,no_root_squash)
/nfs/volumes001/pv03 *(rw,no_root_squash)
/nfs/volumes001/pv04 *(rw,no_root_squash)
/nfs/volumes001/pv05 *(rw,no_root_squash)
/nfs/volumes001/pv06 *(rw,no_root_squash)
/nfs/volumes001/pv07 *(rw,no_root_squash)
/nfs/volumes001/pv08 *(rw,no_root_squash)
/nfs/volumes001/pv09 *(rw,no_root_squash)
/nfs/volumes001/pv10 *(rw,no_root_squash)

#重新加载使配置生效
[root@k8s-master ~]# exportfs -arv
exporting *:/nfs/volumes001/pv10
exporting *:/nfs/volumes001/pv09
exporting *:/nfs/volumes001/pv08
exporting *:/nfs/volumes001/pv07
exporting *:/nfs/volumes001/pv06
exporting *:/nfs/volumes001/pv05
exporting *:/nfs/volumes001/pv04
exporting *:/nfs/volumes001/pv03
exporting *:/nfs/volumes001/pv02
exporting *:/nfs/volumes001/pv01

#创建pv
[root@k8s-master ~]# vim pod-pv.yaml 

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv01     #定义pv的名称
  labels:
    path: pv01     #定义标签,供pvc绑定pv时使用
spec:
  nfs:             #因为使用的是nfs共享目录做pv,这里定义nfs
    path: /nfs/volumes001/pv01
    server: 192.168.57.131
  accessModes:     #定义访问模式
  - ReadWriteOnce  #表示pvc绑定pv之后,只给同一个节点上的pod使用
  capacity:        #定义pv的大小
    storage: 1G

---                #分割 下面进行创建第二个pv
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv02     #定义第二pv的名称
  labels:
    path: pv02
spec:
  nfs:
    path: /nfs/volumes001/pv02  #修改共享路径
    server: 192.168.57.131
  accessModes:
  - ReadOnlyMany  #第二个pv设置可以被多个节点的pod以只读的方式挂载
  capacity:
    storage: 2G

---                #分割 下面进行创建第三个pv  名称和共享路径名称需要修改 其他根据需求修改 依此类推
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv03
  labels:
    path: pv03
spec:
  nfs:
    path: /nfs/volumes001/pv03
    server: 192.168.57.131
  accessModes:
  - ReadWriteMany  #第三个pv可以被多个节点的pod以读写的方式挂载
  capacity:
    storage: 3G

 
#创建
[root@k8s-master ~]# kubectl apply -f pod-pv.yaml 
persistentvolume/mypv01 created
persistentvolume/mypv02 created
persistentvolume/mypv03 created

[root@k8s-master ~]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv01   1G         RWO            Retain           Available                                   7s
mypv02   2G         ROX            Retain           Available                                   7s
mypv03   3G         RWX            Retain           Available                                   7s

#其中 ACCESS列的类型模式表示如下:
#也就是 yaml文件中定义的 accessModes 字段访问模式中的三种模式
RWO:readwariteonce: 单路读写,允许同一个node节点上的pod访问
ROX:readonlymany:    多路只读,允许不同node节点的pod以只读方式访问
RWX:readwritemany:  多路读写,允许不同的node节点的pod以读写方式访问

PS:虽然字段官方解释是单路/多路读写,但是效果并没有达到,即使指定了readwariteonce、readonlymany之后,
    在不同的node节点上,依然可以不同的路径中进行文件或目录的创建。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
4.1.2 创建pvc

pv创建好之后,创建pvc进行与pv的绑定

#创建pvc.yaml
[root@k8s-master ~]# vim pod-pvc.yaml 

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc01
spec:
  accessModes:          #定义访问模式
  - ReadWriteOnce       #与哪个pv绑定,就要与那个pv定义的访问模式一致
  selector:
    matchLabels:
      path: pv01        #要与被绑定目标pv定义的标签一致,要匹配到
  resources:
    requests:
      storage: 1G       #表示要请求pv的大小
---                     #分割 定义第二个pvc与pv的绑定
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc02
spec:
  accessModes:
  - ReadOnlyMany
  selector:
    matchLabels:
      path: pv02
  resources:
    requests:
      storage: 2G

---                     #分割 定义第三个pvc与pv的绑定
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc03
spec:
  accessModes:
  - ReadWriteMany
  selector:
    matchLabels:
      path: pv03
  resources:
    requests:
      storage: 3G

#创建
[root@k8s-master ~]# kubectl apply -f pod-pvc.yaml 
persistentvolumeclaim/mypvc01 created
persistentvolumeclaim/mypvc02 created
persistentvolumeclaim/mypvc03 created

[root@k8s-master ~]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc01   Bound    mypv01   1G         RWO                           6s
mypvc02   Bound    mypv02   2G         ROX                           6s
mypvc03   Bound    mypv03   3G         RWX                           6s

#信息显示:name列表示自己pvc的名称,status状态列中,显示bound就是绑定成功, volume列表示绑定的pv名称,capacity表示绑定的大小
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
4.1.3 创建pod

pvc创建并绑定好创建的pv之后,创建pod将pvc挂载到pod中

#创建pod.yaml文件
[root@k8s-master ~]# vim pod-001.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      myname: pod-pvc-01
  template:
    metadata:
      labels:
        myname: pod-pvc-01
    spec:
      containers:
      - name: mynginx-pvc
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          protocol: TCP
        volumeMounts:
        - name: nginx-pvc   #指定关联要挂载的卷的名称
          mountPath: /usr/share/nginx/html  #指定pod容器内的挂载路径
      volumes:              #定义挂载
      - name: nginx-pvc     #定义卷名称
        persistentVolumeClaim:  #表示将要使用pvc的卷
          claimName: mypvc01    #指定要挂载创建好的pvc的名称


#创建
[root@k8s-master ~]# kubectl apply -f pod-001.yaml 
deployment.apps/deploy created

[root@k8s-master ~]# kubectl get pods -owide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy-747cdffc6b-5pb9m   1/1     Running   0          8s    10.244.126.7    k8s-worker2   <none>           <none>
deploy-747cdffc6b-5qdnd   1/1     Running   0          8s    10.244.126.6    k8s-worker2   <none>           <none>
deploy-747cdffc6b-cp92q   1/1     Running   0          8s    10.244.194.68   k8s-worker1   <none>           <none>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
4.1.4 验证pvc数据同步

如上方创建pv -->创建pvc绑定pv --> 创建pod挂载pvc得知,pod中指定的挂载路径是/usr/share/nginx/html,共享的是做了nfs共享的控制节点下的/nfs/volumes001/pv01 (其他的pv0210还未挂载,0310还未创建pvc并绑定),如下在nfs主机上的pv01路径下测试创建/删除数据是否会与容器内同步。

#在pv01下写入数据并请求容器访问测试
[root@k8s-master ~]# echo What a beautiful day!>> /nfs/volumes001/pv01/index.html
[root@k8s-master ~]# curl 10.244.126.7:80
What a beautiful day!        //共享ok

#进入容器内验证路径内容
[root@k8s-master ~]# kubectl exec -it deploy-747cdffc6b-5pb9m -- /bin/bash
root@deploy-747cdffc6b-5pb9m:/# cat /usr/share/nginx/html/index.html 
What a beautiful day!        //容器内验证ok
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
4.1.5 测试pvc是否支持新创建pod使用

再次创建一个pod仍然挂载mypvc01,测试是否可以使用并数据同步

#仍然使用上方创建pod的yaml文件,修改控制器名称即可
[root@k8s-master ~]# head -4 pod-001.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-02       //修改名称

#创建
[root@k8s-master ~]# kubectl apply -f pod-001.yaml 
deployment.apps/deploy-02 created

[root@k8s-master ~]# kubectl get pods -owide
NAME                         READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy-02-747cdffc6b-ct255   1/1     Running   0          5s    10.244.194.70   k8s-worker1   <none>           <none>
deploy-02-747cdffc6b-pwjzx   1/1     Running   0          5s    10.244.126.8    k8s-worker2   <none>           <none>
deploy-02-747cdffc6b-r6p86   1/1     Running   0          5s    10.244.194.69   k8s-worker1   <none>           <none>
deploy-747cdffc6b-5pb9m      1/1     Running   0          12m   10.244.126.7    k8s-worker2   <none>           <none>
deploy-747cdffc6b-5qdnd      1/1     Running   0          12m   10.244.126.6    k8s-worker2   <none>           <none>
deploy-747cdffc6b-cp92q      1/1     Running   0          12m   10.244.194.68   k8s-worker1   <none>           <none>

#验证访问数据是不是同步到新创建的pod容器内
[root@k8s-master ~]# curl 10.244.194.70:80 
What a beautiful day!

#进入容器内查看也已同步
[root@k8s-master ~]# kubectl exec -it deploy-02-747cdffc6b-ct255 -- /bin/bash
root@deploy-02-747cdffc6b-ct255:/# cat /usr/share/nginx/html/index.html 
What a beautiful day!
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
4.1.6 pv、pvc的删除回收

如果想要删除pv 或者 pvc,需要先删除pod,否则由于pod在使用pvc和pv,pv和pvc将无法删除。

4.1.6.1 pv、pvc删除重建步骤 
#删除pvc
[root@k8s-master ~]# kubectl delete -f pod-pvc.yaml 
persistentvolumeclaim "mypvc01" deleted
persistentvolumeclaim "mypvc02" deleted
persistentvolumeclaim "mypvc03" deleted

#因为mypvc02~03 没有pod使用,所以成功删除,mypvc01 pod正在使用,所以处于Terminating状态,无法删除
[root@k8s-master ~]# kubectl get pvc
NAME      STATUS        VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc01   Terminating   mypv01   1G         RWO                           71m

#删除pod 在删除pvc
[root@k8s-master ~]# kubectl delete -f pod-001.yaml 
deployment.apps "deploy" deleted

[root@k8s-master ~]# kubectl get pods 
No resources found in default namespace.

[root@k8s-master ~]# kubectl delete -f pod-pvc.yaml 
persistentvolumeclaim "mypvc01" deleted

[root@k8s-master ~]# kubectl get pvc
No resources found in default namespace.

#删除pvc之后查看pv状态  (status列 状态已经从bound绑定状态到released)
[root@k8s-master ~]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM             STORAGECLASS   REASON   AGE
mypv01   1G         RWO            Retain           Released   default/mypvc01                           103m
mypv02   2G         ROX            Retain           Released   default/mypvc02                           103m
mypv03   3G         RWX            Retain           Released   default/mypvc03                           103m

#此时重新创建pvc进行pv的绑定将会失败需要删除pv并重新创建pv才可以与pvc进行绑定
#创建pvc
[root@k8s-master ~]# kubectl apply -f pod-pvc.yaml 
persistentvolumeclaim/mypvc01 created
persistentvolumeclaim/mypvc02 created
persistentvolumeclaim/mypvc03 created

#查看信息为空
[root@k8s-master ~]# kubectl get pvc    
NAME      STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc01   Pending                                                     4s
mypvc02   Pending                                                     4s
mypvc03   Pending                                                     4s

#删除pv并重新创建
[root@k8s-master ~]# kubectl delete -f pod-pv.yaml 
persistentvolume "mypv01" deleted
persistentvolume "mypv02" deleted
persistentvolume "mypv03" deleted

#删除之后 共享路径下的数据也不会丢失
[root@k8s-master ~]# cat  /nfs/volumes001/pv01/index.html 
What a beautiful day!

#重新创建pv
[root@k8s-master ~]# kubectl apply -f pod-pv.yaml 
persistentvolume/mypv01 created
persistentvolume/mypv02 created
persistentvolume/mypv03 created

#查看pv的status状态已经从released 转换成bound
[root@k8s-master ~]# kubectl get pv    
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
mypv01   1G         RWO            Retain           Bound    default/mypvc01                           5s
mypv02   2G         ROX            Retain           Bound    default/mypvc02                           5s
mypv03   3G         RWX            Retain           Bound    default/mypvc03                           5s

#查看pvc状态 已经完成绑定
[root@k8s-master ~]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc01   Bound    mypv01   1G         RWO                           42s
mypvc02   Bound    mypv02   2G         ROX                           42s
mypvc03   Bound    mypv03   3G         RWX                           42s

#重新创建pod 并进入容器内验证数据同步
[root@k8s-master ~]# kubectl apply -f pod-001.yaml 
deployment.apps/deploy created

[root@k8s-master ~]# kubectl get pods 
NAME                      READY   STATUS    RESTARTS   AGE
deploy-747cdffc6b-88w2b   1/1     Running   0          6s
deploy-747cdffc6b-j2gkm   1/1     Running   0          6s
deploy-747cdffc6b-kdxbc   1/1     Running   0          6s

[root@k8s-master ~]# kubectl exec -it deploy-747cdffc6b-88w2b -- /bin/bash  
root@deploy-747cdffc6b-88w2b:/# cat /usr/share/nginx/html/index.html 
What a beautiful day!    //数据依然存在
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
4.1.6.2 pv、pvc的回收

(下面只是测试回收策略是否生效,其实在当前k8s集群的版本中(1.26)不管有没有设置回收策略,在删除pod、pvc及pv之后宿主机上共享的数据都不会被删除,感兴趣的可以看下或者自己测试下。)


创建pv时如果不定义回收策略,默认的策略是Retain(保留),下面测试回收策略delete

回收策略字段定义:persistentVolumeReclaimPolicy

kubectl explain pv.spec.persistentVolumeReclaimPolicy  可通过该命令查看字段详细介绍


ps:为保持测试方便,可将创建的pod及pvc、pv全部删除 

#创建pv 使用nfs共享的第四个目录(/nfs/volumes001/pv04)
[root@k8s-master ~]# vim pod-pv-02.yaml 

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv04
  labels:
    path: pv04
spec:
  nfs:
    path: /nfs/volumes001/pv04
    server: 192.168.57.131
  accessModes:
  - ReadWriteOnce
  capacity: 
    storage: 1G
  persistentVolumeReclaimPolicy: Delete #定义pv的回收策略,删除pv时宿主机同步的数据也一并删除

#创建
[root@k8s-master ~]# kubectl apply -f pod-pv-02.yaml 
persistentvolume/mypv04 created

[root@k8s-master ~]# kubectl get pv 
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv04   1G         RWO            Delete           Available                                   4s

#创建pvc绑定pv
[root@k8s-master ~]# vim pod-pvc-02.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc04
spec:
  accessModes:
  - ReadWriteOnce
  selector:
    matchLabels: 
      path: pv04
  resources:
    requests:
      storage: 1G

#创建
[root@k8s-master ~]# kubectl apply -f pod-pvc-02.yaml 
persistentvolumeclaim/mypvc04 created

#如下pvc和pv已经是绑定的状态
[root@k8s-master ~]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc04   Bound    mypv04   1G         RWO                           5s

[root@k8s-master ~]# kubectl get pv 
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
mypv04   1G         RWO            Delete           Bound    default/mypvc04                           3m19s

#创建pod将pvc进行挂载
[root@k8s-master ~]# vim pod-002.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy
spec:
  replicas: 3 
  selector: 
    matchLabels:
      myname: pod-pvc-02
  template:
    metadata:
      labels:
        myname: pod-pvc-02
    spec:
      containers:
      - name: mynginx-pvc
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          protocol: TCP
        volumeMounts:
        - name: nginx-pvc-02
          mountPath: /usr/share/nginx/html
      volumes:
      - name: nginx-pvc-02
        persistentVolumeClaim: 
          claimName: mypvc04    #指定要挂载创建好的pvc的名称
          
#创建
[root@k8s-master ~]# kubectl apply -f pod-002.yaml 
deployment.apps/deploy created

[root@k8s-master ~]# kubectl get pods -owide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy-586cf867cb-6hgz8   1/1     Running   0          8s    10.244.194.73   k8s-worker1   <none>           <none>
deploy-586cf867cb-r2xlt   1/1     Running   0          8s    10.244.126.13   k8s-worker2   <none>           <none>
deploy-586cf867cb-s7xfv   1/1     Running   0          8s    10.244.126.14   k8s-worker2   <none>           <none>

#宿主机下创建文件验证数据同步
[root@k8s-master ~]# echo "This is easy." >> /nfs/volumes001/pv04/index.html
[root@k8s-master ~]# curl 10.244.194.73:80
This is easy.        //验证ok

#进入容器内验证
[root@k8s-master ~]# kubectl exec -it deploy-586cf867cb-6hgz8 -- /bin/bash
root@deploy-586cf867cb-6hgz8:/# cat /usr/share/nginx/html/index.html 
This is easy.        //容器内验证ok

#删除pod及pvc、pv之后验证宿主机共享的路径数据是否已删除
[root@k8s-master ~]# kubectl delete -f pod-002.yaml 
deployment.apps "deploy" deleted

[root@k8s-master ~]# kubectl get pods 
No resources found in default namespace.

#删除pvc
[root@k8s-master ~]# kubectl delete -f pod-pvc-02.yaml 
persistentvolumeclaim "mypvc04" deleted

[root@k8s-master ~]# kubectl get  pvc 
No resources found in default namespace.

#pvc删除之后pv状态变成了 Failed
[root@k8s-master ~]# kubectl get  pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
mypv04   1G         RWO            Delete           Failed   default/mypvc04                           10m

#删除pv
[root@k8s-master ~]# kubectl delete -f pod-pv-02.yaml 
persistentvolume "mypv04" deleted
[root@k8s-master ~]# kubectl get pv 
No resources found

#验证宿主机共享路径中数据依然存在
[root@k8s-master ~]# ls /nfs/volumes001/pv04
index.html
[root@k8s-master ~]# cat /nfs/volumes001/pv04/index.html 
This is easy.

#重新创建pv、pvc及pod 验证容器内数据是否依然被共享且数据存在
[root@k8s-master ~]# kubectl apply -f pod-pv-02.yaml 
persistentvolume/mypv04 created

[root@k8s-master ~]# kubectl apply -f pod-pvc-02.yaml 
persistentvolumeclaim/mypvc04 created

[root@k8s-master ~]# kubectl apply -f pod-002.yaml 
deployment.apps/deploy created

[root@k8s-master ~]# kubectl get pods -owide
NAME                      READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
deploy-586cf867cb-7s794   1/1     Running   0          9s    10.244.194.74   k8s-worker1   <none>           <none>
deploy-586cf867cb-92plc   1/1     Running   0          9s    10.244.126.15   k8s-worker2   <none>           <none>
deploy-586cf867cb-r64hm   1/1     Running   0          9s    10.244.126.16   k8s-worker2   <none>           <none>

#验证容器内的挂载的共享路径中数据依然存在
[root@k8s-master ~]# curl 10.244.194.74:80
This is easy.

[root@k8s-master ~]# kubectl exec -it deploy-586cf867cb-7s794 -- /bin/bash
root@deploy-586cf867cb-7s794:/# cat /usr/share/nginx/html/index.html 
This is easy.

#经测试,不管有没有设置回收的策略,使用pvc为pod进行挂载的存储卷模式,在pod删除之后都不会将宿主机上共享的数据进行删除。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150.
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.

4.2 动态创建pv

存储类(storageclass),使用类型可以动态的自动创建pv,k8s管理员通过创建storageclass可以动态生成一个存储卷pv供pvc使用。

 

kubectl explain storageclass 使用该命令可以查看该字段信息。


其中比较重要的字段解释如下

provisioner

可理解为提供商,使用storageclass时需要有一个供应者用来动态的生成符合条件的pv,然后由该字段指定供应者来创建pv


reclaimPolicy

定义回收策略,默认的是delete

4.2.1 创建nfs 提供商

以nfs共享存储为例进行创建,将nfs作为提供商,从nfs共享目录中划分存储。

nfs属于是k8s外部供应商,要想使用nfs需要安装一个自动装载程序--nfs-client,称之为provisioner,这个程序会使用已经配置好的nfs服务在配置nfs共享目录的服务器上自动创建持久卷,也就是自动创建pv。

 

创建nfs提供商需要使用到这个镜像,可在docker上拉取下载

4.2.2 创建运行nfs-provisioner需要的sa账号

因为nfs 提供商是以pod中的容器形式在k8s中运行的,所以需要创建一个sa账号并赋权,让他能有权限操作k8s并与k8s api通信

才能从k8s中创建存储出来。


sa的全称是serviceaccount。

serviceaccount是为了方便Pod里面的进程调用Kubernetes API或其他外部服务而设计的。

 

指定了serviceaccount之后,我们把pod创建出来了,我们在使用这个pod时,这个pod就有了我们指定的账户的权限了。

#创建sa.yaml
[root@k8s-master ~]# vim sa.yaml 

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-provisioner

#创建
[root@k8s-master ~]# kubectl apply -f sa.yaml 
serviceaccount/nfs-provisioner created

[root@k8s-master ~]# kubectl get sa | grep nfs
nfs-provisioner   0         11s

#对sa授权
[root@k8s-master ~]# kubectl create clusterrolebinding nfs-provisioner-clusterrolebinding --clusterrole=cluster-admin --serviceaccount=default:nfs-provisioner
clusterrolebinding.rbac.authorization.k8s.io/nfs-provisioner-clusterrolebinding created    //授权成功
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
4.2.3 创建nfs提供商

创建nfs提供商之前,先找一个集群内的机器做服务端,我这里仍然使用控制节点,配置方法如上方3.1标题中的步骤一致

#配置nfs共享
[root@k8s-master ~]# yum -y install nfs-utils
[root@k8s-master ~]# systemctl enable nfs --now
[root@k8s-master ~]# mkdir -p /nfs/test001
[root@k8s-master ~]# vim /etc/exports   //加入如下内容
/nfs/test001 *(rw,no_root_squash)

#重新加载生效
[root@k8s-master ~]# exportfs -arv
exporting *:/nfs/test001

#创建nfs提供商,使用deploymen控制器管理pod以容器方式运行
[root@k8s-master ~]# vim nfs-deployment.yaml 


kind: Deployment
apiVersion: apps/v1
metadata:
  name: mynfs-provisioner
spec:
  selector:
    matchLabels:
       name: nfs-01
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        name: nfs-01
    spec:
      serviceAccount: nfs-provisioner  #这里指定的就是上方创建的sa的名称,通过kubectl get sa查看
      containers:
        - name: nfs-02
          image: registry.cn-beijing.aliyuncs.com/mydlq/nfs-subdir-external-provisioner:v4.0.0
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: nfs-client
              mountPath: /persistentvolumes   #这里定义容器内的挂载路径
          env:
            - name: PROVISIONER_NAME #这里定义nfs提供商的名称
              value: nfs-test
            - name: NFS_SERVER       #这里写nfs共享的宿主机IP
              value: 192.168.57.131
            - name: NFS_PATH         #这里定义nfs共享宿主机上的路径
              value: /nfs/test001
      volumes:
        - name: nfs-client
          nfs:
            server: 192.168.57.131   #这里要与配置nfs共享的宿主机的ip一致
            path: /nfs/test001       #这里是nfs共享的路径

#创建
[root@k8s-master ~]# kubectl apply -f nfs-deployment.yaml 
deployment.apps/mynfs-provisioner created

[root@k8s-master ~]# kubectl get pods 
NAME                                 READY   STATUS    RESTARTS   AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   0          31s
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
4.2.4 创建存储类 pvc 

创建pvc之前,需要先创建一个存储类(storageclass ),通过它动态生成pv

4.2.5 创建存储类(torageclass)

创建storageclass,动态供给pv,(可以理解为创建了动态的pv)

#创建存储类的yaml文件
[root@k8s-master ~]# vim nfs-storageclass.yaml 

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs             #定义存储类的名称
provisioner: nfs-test   #这里要与创建nfs提供商时env里面时定义提供商的名称一致

#创建
[root@k8s-master ~]# kubectl apply -f nfs-storageclass.yaml 
storageclass.storage.k8s.io/nfs created

[root@k8s-master ~]# kubectl get storageclass
NAME   PROVISIONER   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs    nfs-test      Delete          Immediate           false                  8s
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
4.2.6 创建pvc

创建pvc 与 存储类绑定

[root@k8s-master ~]# vim nfs-pvc.yaml 

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-pvc
spec:
  accessModes:
  - ReadWriteMany        #定义访问一个ReadWriteMany该类型的pv
  resources:
    requests:
      storage: 1G
  storageClassName: nfs  #这里要写存储类的名称 
  
  
#创建
[root@k8s-master ~]# kubectl apply -f nfs-pvc.yaml 
persistentvolumeclaim/test-pvc created

[root@k8s-master ~]# kubectl get pvc
NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff   1G         RWX            nfs            3s

#查看动态生成的pv
[root@k8s-master ~]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff   1G         RWX            Delete           Bound    default/test-pvc   nfs                     6s

#查看自动生成的pv目录
#相当于是在指定的路径下(/nfs/test001/)自动创建一个目录,然后将这个目录自动做成pv并绑定pvc最终挂载到容器内进行使用。
[root@k8s-master ~]# ls /nfs/test001/
default-test-pvc-pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff

#命名规范分为三段:命名空间+pvc的名称+pv的名称

#整个创建步骤分为如下三步:
1.创建一个提供商 如nfs;
2.创建storageclass指定创建好的提供商;
3.创建pvc指定创建好的storageclass。
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
4.2.7 创建pod

创建一个pod,挂载上面创建好的pvc,{也就是存储类(storageclass),动态生成的pvc(test-pvc)}

#创建绑定pvc卷的pod
[root@k8s-master ~]# vim pod-nginx.yaml

kind: Pod
apiVersion: v1
metadata:
  name: pod-01
spec:
  containers:
  - name: mynginx
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
      - name: nfs-pvc             #这里写下面定义的卷的名称 要匹配到(表示将下方的pvc卷与下面定义的容器内的路径进行绑定)
        mountPath: /usr/share/nginx/html
  restartPolicy: "Never"
  volumes:
    - name: nfs-pvc               #定义卷的名称
      persistentVolumeClaim:
        claimName: test-pvc       #这里写创建好的pvc的名称

#创建
[root@k8s-master ~]# kubectl apply -f pod-nginx.yaml 
pod/pod-01 created

[root@k8s-master ~]# kubectl get pods
NAME                                 READY   STATUS    RESTARTS   AGE
mynfs-provisioner-7bbf59f87d-m2vtz   1/1     Running   0          23m
pod-01                               1/1     Running   0          3s
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
4.2.8 测试共享

测试绑定的pvc是否生效

经上方步骤:

创建的pod 中nginx容器的/usr/share/nginx/html 绑定了test-pvc

test-pvc绑定了存储类(storageclass),

存储类指定了宿主机上的/nfs/test001/并在其下自动生成了一个目录,而这个目录就是pv

而这个/nfs/test001/下生成的随机目录(pv)就是与nginx容器中绑定的路径做了共享存储。

#在pv下创建测试文件
[root@k8s-master ~]# ls /nfs/test001/default-test-pvc-pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff/
test.txt
[root@k8s-master ~]# cat /nfs/test001/default-test-pvc-pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff/test.txt 
[root@k8s-master ~]#

#进入容器验证
[root@k8s-master ~]# kubectl exec -it pod-01 -- /bin/bash
root@pod-01:/# ls /usr/share/nginx/html/
test.txt
root@pod-01:/# echo test123 >> /usr/share/nginx/html/test.txt    //写入内容

#退出容器再次验证
[root@k8s-master ~]# cat /nfs/test001/default-test-pvc-pvc-e6f251e2-c8d5-4f7e-ba20-951ba0eaa1ff/test.txt 
test123
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.