目录

为什么要做持久化存储

都有哪些持久化存储

emptyDir

什么是emptyDir

emptyDir作用

emptyDir的应用场景

emptyDir优缺点

emptyDir的使用方式

hostPath

什么是hostPath

hostPath应用场景

hostPath优缺点

hostPath的使用方式

PV以及PVC

什么是PV

什么是PVC

PV的供应方式

绑定

使用流程

回收策略

访问模式

示例

资源列表

部署NFS

PV、PVC应用示例


为什么要做持久化存储

        在k8s中部署的应用都是以pod容器的形式运行的,假如我们部署MySQL、Redis等数据库,需要对这些数据库产生的数据做备份。因为Pod是有生命周期的,如果pod不挂载数据卷,那pod被删除或重启后这些数据会随之消失,如果想要长久的保留这些数据就要用到pod数据持久化存储。

都有哪些持久化存储

emptyDir

什么是emptyDir

        是一个临时存储卷,与Pod的生命周期绑定到一起,如果Pod被删除了,这意味着数据也被随之删除。

emptyDir作用

  • 可以实现持久化;
  • 同一个Pod的多个容器可以实现数据共享,多个不同的Pod之间不能进行数据通信;
  • 随着Pod的生命周期而存在,当我们删除Pod时,其数据也会被随之删除;

emptyDir的应用场景

  • 临时缓存空间,比如基于磁盘的归并排序;
  • 为较耗时计算任务提供检查点,以便任务能方便的从崩溃前状态恢复执行;
  • 存储Web访问日志及错误日志等信息;

emptyDir优缺点

优点

        (1)可以实现同一个Pod内多个容器之间数据共享;

        (2)当Pod内的某个容器被强制删除时,数据并不会丢失,因为Pod没有删除;

缺点:

        (1)当Pod被删除时,数据也会被随之删除;

        (2)不同的Pod之间无法实现数据共享;

emptyDir的使用方式

[root@master ~]# cat emptyDir.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test-pod
    image: busybox:1.28
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: data
      mountPath: /opt
    command: ["sh","-c","sleep 1000"]
  volumes:
  - name: data
    emptyDir: {}

[root@master ~]# kubectl apply -f emptyDir.yaml 
pod/test created

查看临时目录存在的位置,可用如下方法

[root@master ~]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
test   1/1     Running   0          67s   10.244.1.2   node1   <none>           <none>
[root@master ~]# kubectl get pod test -oyaml | grep uid
  uid: 1da23c7c-eab0-42c4-b1d6-77d4e066968a

# 登录node1机器
[root@node1 ~]# tree /var/lib/kubelet/pods/1da23c7c-eab0-42c4-b1d6-77d4e066968a/
/var/lib/kubelet/pods/1da23c7c-eab0-42c4-b1d6-77d4e066968a/
├── containers
│   └── test-pod
│       └── d8847ba8
├── etc-hosts
├── plugins
│   └── kubernetes.io~empty-dir
│       ├── data
│       │   └── ready
│       └── wrapped_kube-api-access-gcs8w
│           └── ready
└── volumes
    ├── kubernetes.io~empty-dir
    │   └── data
    └── kubernetes.io~projected
        └── kube-api-access-gcs8w
            ├── ca.crt -> ..data/ca.crt
            ├── namespace -> ..data/namespace
            └── token -> ..data/token

11 directories, 7 files

# 在容器里面写个文件,对应的emptyDir目录会有相应的文件
[root@master ~]# kubectl exec -it test -- sh -c 'date > /opt/time.txt'
[root@master ~]# kubectl exec -it test -- ls /opt/
time.txt
[root@master ~]# kubectl exec -it test -- cat /opt/time.txt 
Fri Dec  8 03:10:40 UTC 2023

# 登录node1机器查看
[root@node1 ~]# cat /var/lib/kubelet/pods/1da23c7c-eab0-42c4-b1d6-77d4e066968a/volumes/kubernetes.io~empty-dir/data/time.txt 
Fri Dec  8 03:10:40 UTC 2023

hostPath

什么是hostPath

        hostPath Volume是指Pod挂载宿主机上的目录或文件。 hostPath Volume使得容器可以使用宿主机的文件系统进行存储,hostpath(宿主机路径):节点级别的存储卷,在pod被删除,这个存储卷还是存在的,不会被删除,所以只要同一个pod被调度到同一个节点上来,在pod被删除重新被调度到这个节点之后,对应的数据依然是存在的

hostPath应用场景

Pod中容器需要访问宿主机文件。

hostPath优缺点

优点:

        (1)可以实现同一个Pod不同容器之间的数据共享;

        (2)可以实现同一个Node节点不同Pod之间的数据共享;

缺点:

        无法满足跨节点Pod之间的数据共享。

hostPath的使用方式

[root@master ~]# cat hostPath.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test-pod
    image: busybox:1.28
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: data
      mountPath: /opt
    command: ["sh","-c","sleep 1000"]
  volumes:
  - name: data
    hostPath: 
      path: "/data"
      type: DirectoryOrCreate

[root@master ~]# kubectl apply -f hostPath.yaml 
pod/test created
[root@master ~]# kubectl exec -it test -- sh -c 'date > /opt/time.txt'
[root@master ~]# kubectl exec -it test -- cat /opt/time.txt 
Fri Dec  8 03:15:34 UTC 2023
[root@master ~]# kubectl get pod -o wide
NAME   READY   STATUS    RESTARTS   AGE   IP           NODE    NOMINATED NODE   READINESS GATES
test   1/1     Running   0          50s   10.244.2.2   node2   <none>           <none>

# 登录node2机器查看
[root@node2 ~]# ls /data/
time.txt
[root@node2 ~]# cat /data/time.txt 
Fri Dec  8 03:15:34 UTC 2023

PV以及PVC

        前面我们和大家一起学习了一些基本的资源对象的使用方法,前面我们也和大家讲到了有状态的应用和对数据有持久化的应用,我们有通过 hostPath 或者 emptyDir 的方式来持久化我们的数据,但是显然我们还需要更加可靠的存储来保存应用的持久化数据,这样容器在重建后,依然可以使用之前的数据。但是显然存储资源和 CPU 资源以及内存资源有很大不同,为了屏蔽底层的技术实现细节,让用户更加方便的使用,Kubernetes 便引入了 PV 和 PVC 两个重要的资源对象来实现对存储的管理。这也是我们这节课需要和大家讲解的核心:PV 和 PVC。

什么是PV

        PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。

        PersistentVolume(PV)是群集中的一块存储,由管理员配置或使用存储类动态配置。 它是集群中的资源,就像pod是k8s集群资源一样。 PV是容量插件,如Volumes,其生命周期独立于使用PV的任何单个pod。

什么是PVC

        PersistentVolumeClaim(PVC)是一个持久化存储卷,我们在创建pod时可以定义这个类型的存储卷。 它类似于一个pod。 Pod消耗节点资源,PVC消耗PV资源。 Pod可以请求特定级别的资源(CPU和内存)。 pvc在申请pv的时候也可以请求特定的大小和访问模式(例如,可以一次读写或多次只读)。

PV的供应方式

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

静态的

集群管理员创建了许多PV。它们包含可供群集用户使用的实际存储的详细信息。它们存在于Kubernetes API中,可供使用。

动态的

当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,群集可能会尝试为PVC专门动态配置卷。此配置基于StorageClasses,PVC必须请求存储类,管理员必须创建并配置该类,以便进行动态配置。

绑定

        用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态。

每个持久卷会处于以下阶段(Phase)之一:

Available

卷是一个空闲资源,尚未绑定到任何申领

Bound

该卷已经绑定到某申领

Released

所绑定的申领已被删除,但是关联存储资源尚未被集群回收

Failed

卷的自动回收操作失败

使用流程

  • 需要找一个存储服务器,把它划分成多个存储空间;
  • k8s管理员可以把这些存储空间定义成多个pv;
  • 在pod中使用pvc类型的存储卷之前需要先创建pvc,通过定义需要使用的pv的大小和对应的访问模式,找到合适的pv;
  • pvc被创建之后,就可以当成存储卷来使用了,我们在定义pod时就可以使用这个pvc的存储卷
  • pvc和pv它们是一一对应的关系,pv如果被pvc绑定了,就不能被其他pvc使用了;
  • 我们在创建pvc的时候,应该确保和底下的pv能绑定,如果没有合适的pv,那么pvc就会处于pending状态。

回收策略

        当我们创建pod时如果使用pvc做为存储卷,那么它会和pv绑定,当删除pod,pvc和pv绑定就会解除,解除之后和pvc绑定的pv卷里的数据需要怎么处理,目前,卷可以保留,回收或删除:

Retain

        当删除pvc的时候,pv仍然存在,处于released状态,但是它不能被其他pvc绑定使用,里面的数据还是存在的,当我们下次再使用的时候,数据还是存在的,这个是默认的回收策略。

Recycle

        简单擦除 (rm -rf /thevolume/*)

Delete

        删除pvc时即会从Kubernetes中移除PV,也会从相关的外部设施中删除存储资产。

对于 Kubernetes 1.28 来说,只有 nfs 和 hostPath 卷类型支持回收(Recycle)。

访问模式

        PersistentVolume 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。 如下表所示,提供者(驱动)的能力不同,每个 PV 卷的访问模式都会设置为对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器上以只读的方式导出。 每个 PV 卷都会获得自身的访问模式集合,描述的是特定 PV 卷的能力。

访问模式有:

ReadWriteOnce

        卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式也允许运行在同一节点上的多个 Pod 访问卷。

ReadOnlyMany

        卷可以被多个节点以只读方式挂载。

ReadWriteMany

        卷可以被多个节点以读写方式挂载。

ReadWriteOncePod

        特性状态: Kubernetes v1.27 [beta]

        卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。

在命令行接口(CLI)中,访问模式也使用以下缩写形式:

  • RWO - ReadWriteOnce
  • ROX - ReadOnlyMany
  • RWX - ReadWriteMany
  • RWOP - ReadWriteOncePod

示例

这里面为了方便演示,决定使用相对简单的 NFS 这种存储资源。

资源列表

        这里面Kubernetets集群由master、node1、node2节点组成,本文不在演示Kubernetes的部署了,只解释NFS的部署,以及配置PV、PVC相关内容。

操作系统

主机名

配置

IP

CentOS7.9.2009

master

2C4G

192.168.207.131

CentOS7.9.2009

node1

2C4G

192.168.207.165

CentOS7.9.2009

node2

2C4G

192.168.207.166

CentOS7.9.2009

nfs

2C4G

192.168.207.167

部署NFS

nfs节点操作

# 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld

# 关闭selinux
setenforce 0
sed -i "s/.*SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config

# 安装
yum -y install nfs-utils rpcbind
mkdir -p /data/volumes
cat > /etc/exports << EOF
/data/volumes 192.168.207.0/24(rw,no_root_squash)
EOF
systemctl enable nfs --now

# 所有kubernetes集群中的节点需要安装以下软件包用以支持nfs
yum -y install nfs-utils rpcbind
PV、PVC应用示例

该yaml文件一共创建了3个资源,分别是PV、PVC、Pod。

其中PV的名字叫test-pv,指定的存储大小是1G(从NFS的/data/volumes分配的空间),回收策略是Delete,访问模式的ReadWriteMany。

PVC叫test-pvc,请求的存储是1G,访问模式是ReadWriteMany。

Pod挂载test-pvc这个PVC到/opt目录。

[root@master ~]# cat pv-pvc-test.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-pv
spec:
  capacity:
    storage: 1G
  persistentVolumeReclaimPolicy: Delete
  accessModes: ["ReadWriteMany"]
  nfs:
    path: /data/volumes
    server: 192.168.207.167
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec: 
  accessModes: ["ReadWriteMany"]
  resources:
    requests: 
      storage: 1G
    limits:
      storage: 1G
---
apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test-pod
    image: busybox:1.28
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: data
      mountPath: /opt
    command: ["sh","-c","sleep 1000"]
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: test-pvc
[root@master ~]# kubectl apply -f pv-pvc-test.yaml 
persistentvolume/test-pv created
persistentvolumeclaim/test-pvc created
pod/test created

[root@master ~]# kubectl get pod
NAME   READY   STATUS    RESTARTS   AGE
test   1/1     Running   0          16s
[root@master ~]# kubectl get pvc
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
test-pvc   Bound    test-pv   1G         RWX                           19s
[root@master ~]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
test-pv   1G         RWX            Delete           Bound    default/test-pvc                           20s

# 查看PVC相关信息
[root@master ~]# kubectl describe pvc test-pvc
Name:          test-pvc
Namespace:     default
StorageClass:  
Status:        Bound
Volume:        test-pv
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      1G
Access Modes:  RWX
VolumeMode:    Filesystem
Used By:       test
Events:        <none>

# 查看PV相关信息
[root@master ~]# kubectl describe pv test-pv
Name:            test-pv
Labels:          <none>
Annotations:     pv.kubernetes.io/bound-by-controller: yes
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    
Status:          Bound
Claim:           default/test-pvc
Reclaim Policy:  Delete
Access Modes:    RWX
VolumeMode:      Filesystem
Capacity:        1G
Node Affinity:   <none>
Message:         
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    192.168.207.167
    Path:      /data/volumes
    ReadOnly:  false
Events:        <none>

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐