k8s存储

存储

  • pod运行存储,删除pod的时候,pod里面写入的数据就没有了

一、本地存储

1、emptydir类型

  • 在pod所在的物理主机上生成的一个随机目录,也就是临时目录

  • pod容器删除后,临时目录也会被删除

bash 复制代码
[root@k-master volume]# cat pod1.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1
  name: pod1
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod1
    resources: {}
    volumeMounts:
    - name: v1  # 挂载v1的目录
      mountPath: /data1 # 挂载到容器里面的/data1目录,不存在,会自动创建
  volumes:
  - name: v1 # 临时目录的名字为v1
    emptyDir: {} # 创建一个临时目录
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

# 创建pod之后,查看pod调度在哪一个节点上面了
[root@k-master volume]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE     IP              NODE      NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          4m50s   10.244.82.181   k-node1   <none>           <none>


# 然后在node1上面查看pod1容器的详细信息
[root@k-node1 v1]# crictl inspect 1a04aed59dd91 |grep -i mount -C3
      "io.kubernetes.container.terminationMessagePolicy": "File",
      "io.kubernetes.pod.terminationGracePeriod": "30"
    },
    "mounts": [
      {
        "containerPath": "/data1",
        "hostPath": "/var/lib/kubelet/pods/99036af5-21a9-4af9-ac1c-f04e9c23dbed/volumes/kubernetes.io~empty-dir/v1",  # node1上面创建的临时目录
--
          "value": "443"
        }
      ],
      "mounts": [
        {
          "container_path": "/data1",
          "host_path": "/var/lib/kubelet/pods/99036af5-21a9-4af9-ac1c-f04e9c23dbed/volumes/kubernetes.io~empty-dir/v1"
--
      "root": {
        "path": "rootfs"
      },
      "mounts": [
        {
          "destination": "/proc",
          "type": "proc",
--
            "path": "/proc/13150/ns/uts"
          },
          {
            "type": "mount"
          },
          {
            "type": "network",

# 进入这个临时目录即可
[root@k-node1 v1]# pwd
/var/lib/kubelet/pods/99036af5-21a9-4af9-ac1c-f04e9c23dbed/volumes/kubernetes.io~empty-dir/v1
[root@k-node1 v1]# ls
test


# pod删除后,临时目录也就被删除了

2、hostPath

  • 有一个缺点,当删除了node1上面的pod后,node1上面有一个挂载目录,当再次创建pod后,调度在node2上面,因此就不行了,不能实现挂载,因为挂载目录在node1上面

  • 就是不能在各个节点上面进行同步

bash 复制代码
[root@k-master volume]# cat pod1.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1
  name: pod1
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod1
    resources: {}
    volumeMounts:
    - name: v1
      mountPath: /data1
  volumes:
  - name: v1
    hostPath:
       path: /d1  # 宿主机上不存在的话,会自动创建
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

[root@k-master volume]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE    IP              NODE      NOMINATED NODE   READINESS GATES
pod1   1/1     Running   0          4m2s   10.244.82.182   k-node1   <none>           <none>

# 这个宿主机目录是在节点上面创建,删除了pod这个目录依然存在

[root@k-node1 /]# ls -d d1
d1

二、网络存储

1、NFS

  • 就是不管我的pod在哪一个节点上面运行,都能存储数据,因此NFS服务就可以实现了

1、搭建一个nfs服务器

  • 我是在master机器上面搭建的
bash 复制代码
[root@k-master nfsdata]# systemctl enable nfs-server --now
Created symlink /etc/systemd/system/multi-user.target.wants/nfs-server.service → /usr/lib/systemd/system/nfs-server.service.

[root@k-master ~]# mkdir /nfsdata

mkdir /test
chmod o+w /test # 需要加上权限,才能写入进去

# 编写一个配置文件
[root@k-master nfsdata]# cat /etc/exports
/nfsdata *(rw)

# 重启服务

2、客户端挂载nfs

bash 复制代码
# 测试NFS服务器是否正常了

[root@k-master ~]# mount 192.168.50.100:/nfsdata /test
[root@k-master ~]# df -hT /test
Filesystem              Type  Size  Used Avail Use% Mounted on
192.168.50.100:/nfsdata nfs4   50G  5.7G   44G  12% /test

3、编写一个pod

bash 复制代码
[root@k-master volume]# cat pod1.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1
  name: pod1
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod1
    resources: {}
    volumeMounts:
    - name: v1
      mountPath: /data1
  volumes:
  - name: v1
    nfs:
      path: /nfsdata  # nfs服务器挂载的目录,将这个目录挂载到容器里面了,
      server: 192.168.50.100  # nfs服务器地址
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

4、查看nfs挂载目录

bash 复制代码
[root@k-master ~]# ls /nfsdata/
1.txt  2.txt  4.txt

2、isccsi存储

  • 分一个区20G

  • 防火墙要关闭

bash 复制代码
[root@k-master ~]# lsblk 
NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sr0                 11:0    1 12.8G  0 rom  
nvme0n1            259:0    0   50G  0 disk 
├─nvme0n1p1        259:1    0  500M  0 part /boot
└─nvme0n1p2        259:2    0 49.5G  0 part 
  └─cs_docker-root 253:0    0 49.5G  0 lvm  /
nvme0n2            259:3    0   20G  0 disk 
└─nvme0n2p1        259:4    0   20G  0 part 

2、安装target包

bash 复制代码
[root@k-master ~]# yum -y install target*

[root@k-master ~]# systemctl enable target --now
Created symlink /etc/systemd/system/multi-user.target.wants/target.service → /usr/lib/systemd/system/target.service.

3、配置iscsi

bash 复制代码
# 刚分区的盘不需要做格式化

[root@k-master ~]# targetcli
Warning: Could not load preferences file /root/.targetcli/prefs.bin.
targetcli shell version 2.1.53
Copyright 2011-2013 by Datera, Inc and others.
For help on commands, type 'help'.

/> ls /
o- / ......................................................... [...]
  o- backstores .............................................. [...]
  | o- block .................................. [Storage Objects: 0]
  | o- fileio ................................. [Storage Objects: 0]
  | o- pscsi .................................. [Storage Objects: 0]
  | o- ramdisk ................................ [Storage Objects: 0]
  o- iscsi ............................................ [Targets: 0]
  o- loopback ......................................... [Targets: 0]

# 创建一个block1
/> /backstores/block  create block1 /dev/nvme0n2p1 
Created block storage object block1 using /dev/nvme0n2p1.

/> ls /
o- / ......................................................... [...]
  o- backstores .............................................. [...]
  | o- block .................................. [Storage Objects: 1]
  | | o- block1 .. [/dev/nvme0n2p1 (20.0GiB) write-thru deactivated]
  | |   o- alua ................................... [ALUA Groups: 1]
  | |     o- default_tg_pt_gp ....... [ALUA state: Active/optimized]
  | o- fileio ................................. [Storage Objects: 0]
  | o- pscsi .................................. [Storage Objects: 0]
  | o- ramdisk ................................ [Storage Objects: 0]
  o- iscsi ............................................ [Targets: 0]
  o- loopback ......................................... [Targets: 0]
/> 

# 添加一个iscsi驱动器,有严格的格式要求
/> /iscsi  create iqn.2023-03.com.memeda:memeda
Created target iqn.2023-03.com.memeda:memeda.
Created TPG 1.
Global pref auto_add_default_portal=true
Created default portal listening on all IPs (0.0.0.0), port 3260.
/> 

/> cd iscsi/iqn.2023-03.com.memeda:memeda/tpg1/
/iscsi/iqn.20...a:memeda/tpg1> ls
o- tpg1 ..................................... [no-gen-acls, no-auth]
  o- acls ................................................ [ACLs: 0]
  o- luns ................................................ [LUNs: 0]
  o- portals .......................................... [Portals: 1]
    o- 0.0.0.0:3260 ........................................... [OK]
/iscsi/iqn.20...a:memeda/tpg1> 

/iscsi/iqn.20...a:memeda/tpg1> luns/ create /backstores/block/block1 
Created LUN 0.
/iscsi/iqn.20...a:memeda/tpg1> ls
o- tpg1 ..................................... [no-gen-acls, no-auth]
  o- acls ................................................ [ACLs: 0]
  o- luns ................................................ [LUNs: 1]
  | o- lun0 ..... [block/block1 (/dev/nvme0n2p1) (default_tg_pt_gp)]
  o- portals .......................................... [Portals: 1]
    o- 0.0.0.0:3260 ........................................... [OK]
/iscsi/iqn.20...a:memeda/tpg1> 

/iscsi/iqn.20...a:memeda/tpg1> acls/ create iqn.2023-03.com.memeda:acl
Created Node ACL for iqn.2023-03.com.memeda:acl
Created mapped LUN 0.
/iscsi/iqn.20...a:memeda/tpg1> ls
o- tpg1 ..................................... [no-gen-acls, no-auth]
  o- acls ................................................ [ACLs: 1]
  | o- iqn.2023-03.com.memeda:acl ................. [Mapped LUNs: 1]
  |   o- mapped_lun0 ...................... [lun0 block/block1 (rw)]
  o- luns ................................................ [LUNs: 1]
  | o- lun0 ..... [block/block1 (/dev/nvme0n2p1) (default_tg_pt_gp)]
  o- portals .......................................... [Portals: 1]
    o- 0.0.0.0:3260 ........................................... [OK]
/iscsi/iqn.20...a:memeda/tpg1> 

/iscsi/iqn.20...a:memeda/tpg1> exit
Global pref auto_save_on_exit=true
Configuration saved to /etc/target/saveconfig.json

4、客户端安装iscsi客户端

bash 复制代码
[root@k-node1 ~]# yum -y install iscsi*

[root@k-node1 ~]# cat /etc/iscsi/initiatorname.iscsi 
InitiatorName=iqn.1994-05.com.redhat:56a1ef745c4e

# 修改这个iscsi号
[root@k-node2 ~]# cat /etc/iscsi/initiatorname.iscsi 
InitiatorName=iqn.2023-03.com.memeda:acl

# 重启iscsid服务

5、编写pod配置文件

bash 复制代码
[root@k-master volume]# cat pod1.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pod1
  name: pod1
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod1
    resources: {}
    volumeMounts:
    - name: v1
      mountPath: /data
  volumes:
  - name: v1
    iscsi:
      lun: 0
      targetPortal: 192.168.50.100:3260
      iqn: iqn.2023-03.com.memeda:memeda
      readOnly: false
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

# lun映射到node1上面的sad,然后映射到容器里面

[root@k-node1 ~]# lsblk 
NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda           8:0    0   20G  0 disk /var/lib/kubelet/pods/0a64972c-
sr0          11:0    1 12.8G  0 rom  
nvme0n1     259:0    0   50G  0 disk 
├─nvme0n1p1 259:1    0  500M  0 part /boot
└─nvme0n1p2 259:2    0 49.5G  0 part 
  └─cs_docker-root
            253:0    0 49.5G  0 lvm  /

三、持久化存储

  • pv和pvc

  • 底层用的还是传统存储

  • pv就是一个一个块,pvc就是使用这个块的

  • pvc与pv进行绑定

1、pv和pvc

  • pv底层还是使用的存储,nfs或者iscsi存储,或者其他的,把他做成了一个pv

  • pv做成了之后,是公共的,所有名称空间下都能看到,全局可见的

  • 在一个名称空间下面创建一个pvc绑定pv

  • 在一个名称空间下面创建一个pod绑定pvc就能使用了

2、pv和pvc实验(静态创建)

  • nfs充当底层存储

  • 首先搭建一个nfs服务

1、创建pv

bash 复制代码
[root@k-master volume]# cat pv1.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv01
spec:
  capacity: # 指定这个pv的大小
    storage: 5Gi
  accessModes: # 模式
  - ReadWriteOnce
  nfs:
    server: 192.168.50.100 # 这个pv使用的就是nfs的存储
    path: /nfsdata


[root@k-master volume]# kubectl get pv 
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv01   5Gi        RWO            Retain           Available                                   2m19s


# Retain 是回收的策略

# Available 可用的

# RWO 权限

# claim为空的,表示pvc还没有绑定

1、pv的策略

  • persistentVolumeReclaimPolicy 字段控制

  • retain策略,保留策略

  • 删除pod,pvc,里面的数据是保留的,pv也是保留的

  • 静态的创建pv和pvc的话,策略默认是reatin

bash 复制代码
# 首先删除pod,然后删除pvc,pv状态就变成了released状态了

# 如果在创建一个pvc的话,就不能绑定了,因为状态必须是available

# 如果还要再次使用这个pv的话,就删除这个pv,在创建一个pv,绑定底层的nfs数据
  • delete策略

    • 删除了pod,pvc的话,pv也会被删除掉

    • 里面的数据也会被删除掉

    • delete策略,只能用动态配置,静态配置不能

  • recycle策略被弃用了

2、pv的状态

状态名 含义 常见触发场景
Available 尚未被任何 PVC 绑定,可被申领 刚创建出来,或回收策略为 Retain 且已被解除绑定
Bound 已与某条 PVC 成功绑定 kubectl get pv 最常见的状态
Released 绑定的 PVC 已被删除,但 PV 尚未被回收 ReclaimPolicy=Retain 时,PVC 删除后 PV 进入此状态
Failed 自动回收(Recycle/Delete)操作失败 例如底层存储删除卷时返回错误

3、pv的访问模式

  • ReadWriteOnce RWO 单节点读写

  • ReadOnlyMany ROX 多节点只读

  • ReadWriteMany RWX 多节点读写

  • ReadWriteOncePod 单节点pod读写

访问模式 全称 含义 典型场景
ReadWriteOnce RWO 单节点读写 大多数块存储(EBS、Ceph RBD、iSCSI);一个节点挂载,可读写。
ReadOnlyMany ROX 多节点只读 共享文件存储(NFS、CephFS、GlusterFS);多个节点可同时挂载读取。
ReadWriteMany RWX 多节点读写 分布式文件系统(NFS、CephFS、Portworx);多个节点同时挂载读写。
ReadWriteOncePod RWOP 单节点单 Pod 读写 1.22+ 引入,针对 CSI 卷;同一节点上只允许一个 Pod 挂载读写,适合 StatefulSet 精细化调度。

2、创建pvc

  • 一个pv只能与一个pvc进行绑定
bash 复制代码
[root@k-master volume]# cat pvc1.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-1
spec:
  accessModes:
  - ReadWriteOnce # 权限
  resources:
    requests:  # 需要的大小
      storage: 5Gi

# 通过权限和大小进行匹配pv

# 多个相同的pvc的话,就是随机匹配pvc

# 一个pv只能被一个pvc进行绑定

# pvc的容量小于等于pv的容量才能匹配到

# 如果有多个pvc的话,那就需要看谁创建的快,就先匹配

[root@k-master volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-1   Bound    pv01     5Gi        RWO                           52s
[root@k-master volume]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM           STORAGECLASS   REASON   AGE
pv01   5Gi        RWO            Retain           Bound    default/pvc-1                           7m14s

1、pvc的状态

状态名 含义 常见触发场景
Pending 尚未找到/绑定到合适的 PV 集群里没有匹配容量、AccessMode、StorageClass 的 PV;或动态供给未就绪
Bound 已成功绑定到一个 PV 正常使用的常态
Lost 所绑定的 PV 意外消失(对象被删除或后端存储不可用) 手动删除 PV 或底层存储故障
Terminating PVC 正在删除中(对象处于 metadata.deletionTimestamp 非空) 执行 kubectl delete pvc 后,等待回收或 finalizer 完成

3、pv和pvc绑定

  • 受到权限和大小和storagename(存储类名称,标识)这个三个参数的影响

  • storagename是优先级最高的,即使满足权限和大小,pvc没有这个storageClassName的话,就不能绑定,只有pvc有这个storageClassName的才能绑定

bash 复制代码
[root@k-master volume]# cat pv2.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv02
spec:
  storageClassName: abc  # 存储卷的名称为abc
  capacity:
    storage: 5Gi
  accessModes:
  - ReadWriteOnce
  nfs:
    server: 192.168.50.100
    path: /nfsdata

[root@k-master volume]# cat pvc2.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-2
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

[root@k-master volume]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv02   5Gi        RWO            Retain           Available           abc                     49s

[root@k-master volume]# kubectl get pvc
NAME    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc-2   Pending                                                     25s

# 只有这个pvc有storageClassName才能匹配到

4、pod使用pvc

bash 复制代码
[root@k-master volume]# cat pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod2
  name: pod2
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod2
    resources: {}
    volumeMounts:
    - name: mypv
      mountPath: /var/www/html  # 挂载到容器里面的/var/www/html目录下
  restartPolicy: Always
  volumes:
  - name: mypv  # 卷的名字
    persistentVolumeClaim:  # 用pvc来做这个卷
      claimName: pvc-1  # pvc的名字
status: {}


[root@k-master volume]# kubectl get pod 
NAME   READY   STATUS    RESTARTS   AGE
pod2   1/1     Running   0          2m22s

[root@k-master ~]# kubectl exec -ti pod2 -- /bin/bash

# 查看挂载点
root@pod2:/var/www/html# df -hT /var/www/html/
Filesystem              Type  Size  Used Avail Use% Mounted on
192.168.50.100:/nfsdata nfs4   50G  5.7G   44G  12% /var/www/html

# 写入数据
root@pod2:/var/www/html# echo 1 > 1.txt

# 发现,最底层的作为pv的nfs存储里面也有数据
[root@k-master volume]# ls /nfsdata/
1.txt



# 这个pod调度在node1节点上,也可以查看到挂载的情况
# 这个pod的挂载目录也会创建出来的
[root@k-node1 pv01]# df -hT  | grep -i nfs
192.168.50.100:/nfsdata    nfs4       50G  5.7G   44G  12% /var/lib/kubelet/pods/2ce30dc7-4076-482f-9d78-d5af92d03967/volumes/kubernetes.io~nfs/pv01

[root@k-node1 pv01]# cd /var/lib/kubelet/pods/2ce30dc7-4076-482f-9d78-d5af92d03967/volumes/kubernetes.io~nfs/pv01
[root@k-node1 pv01]# ls
1.txt  2.txt

5、删除pod,pv的状态

  • 怎么处理
bash 复制代码
[root@k-master volume]# kubectl delete -f pod2.yaml 
pod "pod2" deleted

[root@k-master volume]# kubectl delete -f pvc1.yaml 
persistentvolumeclaim "pvc-1" deleted
# pv的状态为released
[root@k-master volume]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM           STORAGECLASS   REASON   AGE
pv01   5Gi        RWO            Retain           Released   default/pvc-1                           81s

# 删除relf下面的字段,就能重新变成available了
[root@k-master volume]# kubectl edit pv pv01
persistentvolume/pv01 edited
[root@k-master volume]# kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv01   5Gi        RWO            Retain           Available                                   2m26s

# 或者删除pv,然后重新创建即可

3、pv和pvc和pod

  • 首先pv是一个块,底层使用的是一个存储,用来做成pv,使用nfs也可以,或者其他的

  • pvc用来绑定一个pv,一个pv只能绑定一个pvc

  • pod的持久化存储的话,就是使用的pvc来实现的,pvc挂载到容器的目录下

  • 在这个目录下面写入数据的话,就写入到了最底层的存储里面了

  • 其实pv和pvc都是虚拟出来的,最底层的还是一个存储

  • pv和pvc方便集中管理

  • 最底层的nfs或者其他的也可以管理,也就是分权管理

  • 也就是多级映射关系,抽象出来的

  • 最底层的nfs,映射到pv,pv映射到pvc,最后以卷的形式挂载到pod里面即可

3、nfs配置动态卷的供应流程

  • 就是在定义pvc的时候,自动的创建出pv

  • 依靠的就是nfs驱动器

  • 默认的pv策略是delete,可以修改的为retain

  • 创建一个存储类,映射到nfs存储,然后创建一个pvc就会自动的创建一个pv

1、配置nfs服务器

bash 复制代码
[root@k-master ~]# cat /etc/exports
/nfsdata *(rw)

2、配置nfs驱动

bash 复制代码
# 先git clone 一些这个文件
[root@k-master nfs-deploy]# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git

# 进入到deploy目录下
[root@k-master deploy]# pwd
/root/volume/nfs-deploy/nfs-subdir-external-provisioner/deploy

# 如果名称空间不是默认的default的话,需要修改名称空间,如果是默认的则无需操作

[root@k-master deploy]# ls
class.yaml       kustomization.yaml  rbac.yaml        test-pod.yaml
deployment.yaml  objects             test-claim.yaml
[root@k-master deploy]# 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


# 修改了deployment.yaml
        - name: nfs-client-provisioner
          image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2

# 如果可以拉取到这个镜像,就无需修改,不行的话,就需要更换镜像


registry.cn-hangzhou.aliyuncs.com/cloudcs/nfs-subdir-external-provisioner:v4.0.2
# 这个是别人的网络仓库

# 修改驱动文件中的nfs的一些配置,修改deployment.yaml
            - name: NFS_SERVER
              value: 192.168.50.100
            - name: NFS_PATH
              value: /nfsdata
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.50.100
            path: /nfsdata

[root@k-master deploy]# kubectl apply -f deployment.yaml 
deployment.apps/nfs-client-provisioner created

[root@k-master deploy]# kubectl get pod 
NAME                                    READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-9f74c968-2lm9k   1/1     Running   0          15s


# 这个pod就跟nfs存储做了一个映射,当创建一个pvc(使用的存储类是nfs-client)的时候,就会自动的创建一个pv

3、创建一个存储类

bash 复制代码
[root@k-master ~]# cat class.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiverOnDelete: "false"

[root@k-master ~]# kubectl get sc
NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
nfs-client   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  37s
[root@k-master ~]# 

4、创建一个pvc

  • 创建一个pvc就会自动的创建一个pv
bash 复制代码
[root@k-master volume]# cat pvc3.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc3
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: nfs-client  # 使用的存储类是nfs-client,就会自动的创建pv
  resources:
    requests:
       storage: 5Gi
    
[root@k-master volume]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS   REASON   AGE
pvc-37889731-cc0f-4485-8647-0bc46a435faf   5Gi        RWO            Delete           Bound    default/pvc3   nfs-client              9s
[root@k-master volume]# kubectl get pvc
NAME   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pvc3   Bound    pvc-37889731-cc0f-4485-8647-0bc46a435faf   5Gi        RWO            nfs-client     13s

5、创建一个pod

bash 复制代码
[root@k-master volume]# cat pod2.yaml 
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: pod2
  name: pod2
spec:
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: pod2
    resources: {}
    volumeMounts:
    - name: mypv
      mountPath: /var/www/html
  restartPolicy: Always
  volumes:
  - name: mypv
    persistentVolumeClaim:
      claimName: pvc3
status: {}


[root@k-master volume]# kubectl get pod 
NAME                                    READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-9f74c968-2lm9k   1/1     Running   0          20m
pod2                                    1/1     Running   0          70s
# 就会在nfsdata这个目录创建一个目录用来存储数据
[root@k-master volume]# ls /nfsdata/
1.txt  2.txt  default-pvc3-pvc-37889731-cc0f-4485-8647-0bc46a435faf

# 写入一些数据
[root@k-master volume]# ls /nfsdata/default-pvc3-pvc-37889731-cc0f-4485-8647-0bc46a435faf/
11  22

# 删除pod和pvc
[root@k-master volume]# kubectl delete -f pod2.yaml 
pod "pod2" deleted
[root@k-master volume]# kubectl delete -f pvc3.yaml 
persistentvolumeclaim "pvc3" deleted

# 这个nfs的目录的名字就会修改
[root@k-master volume]# ls /nfsdata/
archived-default-pvc3-pvc-3cd12cad-47a5-43f3-93a0-8e9a9d4a490c

# 因为这个是delete策略导致的,防止数据立即丢失

四、总结

  • 本地存储的话,比较笨重

  • 静态逻辑

    • 先有一个最底层的nfs服务器,可以让别人挂载这个目录

    • 然后创建一个pv,pvc之间进行绑定

    • 创建一个pod绑定pvc,从而写数据,写的数据存储在nfs这个目录下

  • 动态的逻辑

    • 创建一个nfs服务器

    • 创建一个nfs的驱动器,映射到nfs存储,使用的还是nfs存储

    • 然后创建一个存储类,驱动器使用的是上面创建的

    • 创建一个pvc,存储类使用的nfs-client,这个驱动器就会自动的创建一个pv,也就是在nfs存储目录里面划分一个目录用于存储

    • 创建一个pod进行绑定pvc即可