kubernetes持久化存储PV和PVC

kubernetes持久化存储PV和PVC

1.PV和PVC的引入

Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。
拿前面 AWS EBS 的例子来说,要使用 Volume,Pod 必须事先知道如下信息:
当前 Volume 来自 AWS EBS。
EBS Volume 已经提前创建,并且知道确切的 volume-id。
Pod 通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息:
要么询问管理员。
要么自己就是管理员。
这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境这样的情况还可以接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。

Kubernetes 给出的解决方案是 PersistentVolume 和 PersistentVolumeClaim。
PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。
PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时,用户可以创建一个 PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的 PV。
有了 PersistentVolumeClaim,用户只需要告诉 Kubernetes 需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心创建 PersistentVolume 的细节信息。

2.通过NFS实现持久化存储

2.1配置nfs

所有节点安装nfs

[root@k8s-master]# yum install -y nfs-common nfs-utils

在master节点创建共享目录

[root@k8s-master]# mkdir /nfsdata

授权共享目录

[root@k8s-master]# chmod 666 /nfsdata

编辑exports文件

[root@k8s-master]# vim /etc/exports
/nfsdata *(rw,no_root_squash,no_all_squash,sync)

配置生效

启动rpc和nfs(注意顺序)

[root@k8s-master]# systemctl start rpcbind
[root@k8s-master]# systemctl start nfs
# 使配置生效
[root@k8s-master]# exportfs -r
#检查配置是否生效
[root@k8s-master]# exportfs
/nfsdata      	<world>

作为准备工作,我们已经在 k8s-master 节点上搭建了一个 NFS 服务器,目录为 /nfsdata

2.2创建PV

下面创建一个 PV mypv1,配置文件 nfs-pv1.yml 如下:

[root@k8s-master ~]# vim nfs-pv1.yml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mypv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata
    server: 192.168.119.163  #指定nfs目录所在的机器的地址
  1. capacity 指定 PV 的容量为 1G。

  2. accessModes 指定访问模式为 ReadWriteOnce,支持的访问模式有:
    ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
    ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
    ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点。

  3. persistentVolumeReclaimPolicy 指定当 PV 的回收策略为 Recycle,支持的策略有:
    Retain – 需要管理员手工回收。
    Recycle – 清除 PV 中的数据,效果相当于执行 rm -rf /thevolume/*
    Delete – 删除 Storage Provider 上的对应存储资源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

  4. storageClassName 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。

  5. 指定 PV 在 NFS 服务器上对应的目录。

创建 mypv1

[root@k8s-master ~]# kubectl apply -f nfs-pv1.yml

在这里插入图片描述

STATUSAvailable,表示 mypv1 就绪,可以被 PVC 申请。

2.3创建PVC

接下来创建 PVC mypvc1,配置文件 nfs-pvc1.yml 如下:

[root@k8s-master ~]# vim nfs-pvc1.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs

PVC 就很简单了,只需要指定 PV 的容量,访问模式和 class。

执行命令创建 mypvc1

[root@k8s-master ~]# kubectl apply -f nfs-pvc1.yml

在这里插入图片描述

kubectl get pvckubectl get pv 的输出可以看到 mypvc1 已经 Bound 到 mypv1,申请成功。

2.4创建pod

上面已经创建好了pv和pvc,pod中直接使用这个pvc即可

[root@k8s-master ~]# vim pod1.yml 
apiVersion: v1
kind: Pod
metadata:
  name: mypod1
spec:
  containers:
    - name: mypod1
      image: busybox
      args:
      - /bin/sh
      - -c
      - sleep 30000
      volumeMounts:
      - mountPath: "/mydata"
        name: mydata
  volumes:
    - name: mydata
      persistentVolumeClaim:
        claimName: mypvc1

与使用普通 Volume 的格式类似,在 volumes 中通过 persistentVolumeClaim 指定使用 mypvc1 申请的 Volume。

通过命令创建mypod1

[root@k8s-master ~]# kubectl apply -f pod1.yml

在这里插入图片描述

2.5验证

[root@k8s-master ~]# docker exec -it mypod1 /bin/sh
/ # ls mydata/
/ # echo "你看我像会的人吗" > mydata/hello.txt
/ # ls mydata/
hello.txt
/ # exit
[root@k8s-master ~]# ls /nfsdata/    #也可在nfs的共享目录中查看到,说明卷共享成功
hello.txt
[root@k8s-master ~]# cat /nfsdata/hello.txt 
hello
可见,在 Pod 中创建的文件 /mydata/hello.txt 确实已经保存到了 NFS 服务器目录 /nfsdata中。
如果不再需要使用 PV,可用删除 PVC 回收 PV。

在这里,可以尝试在任何一方删除文件,文件在两端都会消失;

在这里插入图片描述

3.PV的回收

当 PV 不再需要时,可通过删除 PVC 回收。未删除pvc之前 pv的状态是Bound

在这里插入图片描述

删除pod

[root@k8s-master yaml]# kubectl delete pod mypod1

删除pvc

[root@k8s-master yaml]# kubectl delete pvc mypvc1

再次查看pv的状态

[root@k8s-master yaml]# kubectl get pv

删除pvc之后pv的状态变为Available,,此时解除绑定后则可以被新的 PVC 申请。

/nfsdata文件中的文件被删除了

在这里插入图片描述

因为 PV 的回收策略设置为 Recycle,所以数据会被清除,

但这可能不是我们想要的结果。如果我们希望保留数据,可以将策略设置为 Retain

[root@k8s-master yaml]# vim nfs-pv1.yml

在这里插入图片描述

[root@k8s-master yaml]# kubectl apply -f nfs-pv1.yml

在这里插入图片描述

回收策略已经变为 Retain,通过下面步骤验证其效果:

# 重新创建mypvc1
[root@k8s-master yaml]# kubectl apply -f nfs-pvc1.yml
# 重新创建pod,引用mypvc1
[root@k8s-master yaml]# kubectl apply -f pod1.yml
# 进入pod中,创建文件
[root@k8s-master yaml]# kubectl get pod -o wide
NAME                       READY     STATUS    RESTARTS   AGE       IP            NODE
mypod1                     1/1       Running   0          1m        172.17.44.2   192.168.119.164
# 来到164
[root@k8s-node01]# docker exec -it mypod1 /bin/sh
/ # echo '你看我会不会' > mydata/hello.txt
/ # ls mydata/
hello.txt
/ # exit

# 在nfs目录下检验
[root@k8s-master yaml]# ls /nfsdata/
hello.txt
[root@k8s-master yaml]# cat /nfsdata/hello.txt 
你看我会不会

# 删除pod
[root@k8s-master yaml]# kubectl delete -f pod1.yml 
pod "mypod1" deleted
[root@k8s-master yaml]# ls /nfsdata/
hello.txt
# 删除pvc(mypvc1)
[root@k8s-master yaml]# kubectl delete pvc mypvc1
persistentvolumeclaim "mypvc1" deleted
[root@k8s-master yaml]# ls /nfsdata/
hello.txt
[root@k8s-master yaml]# cat /nfsdata/hello.txt 
你看我会不会

# 发现数据仍然保留

在这里插入图片描述

在这里插入图片描述

虽然 mypv1 中的数据得到了保留,但其 PV 状态会一直处于 Released,不能被其他 PVC 申请。为了重新使用存储资源,可以删除并重新创建 mypv1。删除操作只是删除了 PV 对象,存储空间中的数据并不会被删除。

[root@k8s-master yaml]# ls /nfsdata/
hello.txt
[root@k8s-master yaml]# kubectl delete pv mypv1
persistentvolume "mypv1" deleted
[root@k8s-master yaml]# ls /nfsdata/
hello.txt
[root@k8s-master yaml]# kubectl apply -f nfs-pv1.yml 
persistentvolume/mypv1 created
[root@k8s-master yaml]# kubectl get pod
No resources found in default namespace.
[root@k8s-master yaml]# kubectl get pv

在这里插入图片描述

新建的 mypv1 状态为 Available,已经可以被 PVC 申请。

PV 还支持 Delete 的回收策略,会删除 PV 在 Storage Provider 上对应存储空间。NFS 的 PV 不支持 Delete,支持 Delete 的 Provider 有 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

4.PV/PVC的静态供给

所有节点下载nfs
yum install -y nfs-common nfs-utils 

master节点作为nfs服务端
[root@k8s-master]# cat /etc/exports
/data/opv *(rw,no_root_squash,no_all_squash,sync)
[root@k8s-master]# chmod 777 -R /data/opv
# 使配置生效
[root@k8s-master]# exportfs -r
#检查配置是否生效
[root@k8s-master]# exportfs

master节点操作
#1.定义pv
[root@k8s-master yaml]# vim pv-pod.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /data/opv  #nfs服务端共享的目录
    server: 192.168.119.163   #nfs服务器的地址
[root@k8s-master yaml]# kubectl apply -f pv-pod.yaml

#2.定义pvc和deployment
[root@k8s-master yaml]# vim pvc-pod.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        #启用数据卷的名字为wwwroot,并挂载到nginx的html目录下
        volumeMounts:
        - name: wwwroot
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
    #定义数据卷名字为wwwroot,类型为pvc
      volumes:
      - name: wwwroot
        persistentVolumeClaim:
          claimName: my-pvc


---
# 定义pvc的数据来源,根据容量大小来匹配pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  #对应上面的名字
  name: my-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5G
[root@k8s-master yaml]# kubectl apply -f pvc-pod.yaml

#3,暴露一下端口
[root@k8s-master yaml]# vim pv-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: pv-svc
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30001
      targetPort: 80
  selector:   #选择器
    app: nginx

# 4.启动
[root@k8s-master yaml]# kubectl apply -f pv-service.yaml
#5.nfs服务器操作
[root@k8s-master yaml]# echo hello >> /data/opv/index.html 
#6.访问,看效果

在这里插入图片描述

在这里插入图片描述

5.PV的动态供给

前面的例子中,我们提前创建了 PV,然后通过 PVC 申请 PV 并在 Pod 中使用,这种方式叫做静态供给(Static Provision)。

与之对应的是动态供给(Dynamical Provision),即如果没有满足 PVC 条件的 PV,会动态创建 PV。相比静态供给,动态供给有明显的优势:不需要提前创建 PV,减少了管理员的工作量,效率高。

动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV,下面是两个例子。

StorageClass standard

在这里插入图片描述

StorageClass slow

在这里插入图片描述

这两个 StorageClass 都会动态创建 AWS EBS,不同在于 standard 创建的是 gp2 类型的 EBS,而 slow 创建的是 io1 类型的 EBS。不同类型的 EBS 支持的参数可参考 AWS 官方文档。

StorageClass 支持 DeleteRetain 两种 reclaimPolicy,默认是 Delete

与之前一样,PVC 在申请 PV 时,只需要指定 StorageClass 和容量以及访问模式,比如:

在这里插入图片描述

除了 AWS EBS,Kubernetes 支持其他多种动态供给 PV 的 Provisioner,完整列表请参考 https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner

6.PV、PVC在应用中的持久化存储

[root@k8s-master yaml]# kubectl delete -f pod1.yml
[root@k8s-master yaml]# vim pod1.yml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mydep
spec:
  selector:
    matchLabels:
      app: busy
  replicas: 1
  template:
    metadata:
      labels:
        app: busy
    spec:
      containers:
        - name: mypod1
          image: busybox
          args:
          - /bin/sh
          - -c
          - sleep 30000
          volumeMounts:
          - mountPath: "/mydata"
            name: mydata
      volumes:
        - name: mydata
          persistentVolumeClaim:
            claimName: mypvc1
            
[root@k8s-master pv]# kubectl apply -f pod1.yml 
[root@k8s-master yaml]# kubectl get pod -o wide
[root@k8s-master yaml]# docker exec -it dc31ac288bfa /bin/sh
/ # echo "我不会了" > mydata/hello.txt
/ # exit

查看pod运行在了哪个节点,将节点关闭。发现另外一个节点,会接手,而且数据仍然存在

在这里插入图片描述

7.PV、PVC在应用在mysql的持久化存储实战项目

下面演示如何为 MySQL 数据库提供持久化存储,步骤为:

  1. 创建 PV 和 PVC。
  2. 部署 MySQL。
  3. 向 MySQL 添加数据。
  4. 模拟节点宕机故障,Kubernetes 将 MySQL 自动迁移到其他节点。
  5. 验证数据一致性。

首先创建 PV 和 PVC,配置如下:

mysql-pv.yml

# 创建持久化目录
[root@k8s-master yaml]# mkdir /nfsdata/mysql-pv
[root@k8s-master yaml]# vim mysql-pv.yml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /nfsdata/mysql-pv
    server: 192.168.119.163
[root@k8s-master yaml]# kubectl apply -f mysql-pv.yml

mysql-pvc.yml

[root@k8s-master yaml]# vim mysql-pvc.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs
  
[root@k8s-master yaml]# kubectl apply -f mysql-pvc.yml

在这里插入图片描述

接下来部署 MySQL,配置文件如下:

[root@k8s-master yaml]# vim mysqlpod.yml 
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: mysql:5.7.5 #这里的镜像一定要选对,能确保拉取到,而且能使用变量
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: password
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pvc
          
[root@k8s-master yaml]# kubectl apply -f mysqlpod.yml

PVC mysql-pvc Bound 的 PV mysql-pv 将被 mount 到 MySQL 的数据目录 var/lib/mysql

MySQL 被部署到 163

在这里插入图片描述

在这里插入图片描述

因为分配到了主节点,不能关机,所以删除它,让它重新分配节点

在这里插入图片描述

等待拉取镜像,启动pod

1、切换到数据库 mysql。

在这里插入图片描述

2、创建数据库company及表t1。

[root@k8s-node01 ~]# docker exec -it e0effdbcddb4 bash
root@mysql-7f65bf577-b2ssv:/# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.7.5-m15 MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database company;
create database  company;
Query OK, 1 row affected (0.03 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| company            |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.02 sec)
mysql> use company;
Database changed
mysql> create table t1(Sno char(9) primary key,Sname char(20) not null,Ssex char(2),Sage smallint,Sdept char(20));
Query OK, 0 rows affected (0.07 sec)

3、插入数据。

添加表数据
mysql> insert into t1(Sno,Sname,Ssex,Sage,Sdept)values('202112081','李四','男','20','CS');
Query OK, 1 row affected (0.02 sec)

mysql> insert into t1(Sno,Sname,Ssex,Sage,Sdept)values('202112082','张三','女','19','CS');
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1(Sno,Sname,Ssex,Sage,Sdept)values('202112083','王五','女','18','MA');
Query OK, 1 row affected (0.00 sec)

mysql> insert into t1(Sno,Sname,Ssex,Sage,Sdept)values('202112085','麻子','男','19','IS');
Query OK, 1 row affected (0.01 sec)

4、 确认数据已经写入。

mysql> show tables;
+-------------------+
| Tables_in_company |
+-------------------+
| t1                |
+-------------------+
1 row in set (0.01 sec)

mysql> select * from t1;
+-----------+-------+------+------+-------+
| Sno       | Sname | Ssex | Sage | Sdept |
+-----------+-------+------+------+-------+
| 202112081 |       |      |   20 | CS    |
| 202112082 |       |      |   19 | CS    |
| 202112083 |       |      |   18 | MA    |
| 202112085 |       |      |   19 | IS    |
+-----------+-------+------+------+-------+
4 rows in set (0.00 sec)

可以看到数据已经被写入,由于编码问题,汉字未被识别,有问题吗?没有问题!

有问题就自己去修改编码。

关闭 k8s-node01,模拟节点宕机故障。

# 关机node01
[root@k8s-node01 ~]# poweroff
# master查看mysql,需要等待一段时间
[root@k8s-master yaml]# kubectl get pod -o wide
NAME                       READY     STATUS    RESTARTS   AGE       IP            NODE
mysql-7f65bf577-b2ssv      1/1       Unknown   0          2h        172.17.44.2   192.168.119.164
mysql-7f65bf577-hkvld      1/1       Running   0          9s        172.17.78.2   192.168.119.163

# 验证数据的一致性:
# 由于node1节点已经宕机,master节点接管了这个任务,pod转移,需要等待一段时间,大约五分钟左右

在这里插入图片描述

[root@k8s-master yaml]# docker exec -it 7f001e01d786 bash
root@mysql-7f65bf577-hkvld:/# mysql -uroot -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1
Server version: 5.7.5-m15 MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| company            |
| mysql              |
| performance_schema |
+--------------------+
4 rows in set (0.01 sec)

mysql> use company;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+-------------------+
| Tables_in_company |
+-------------------+
| t1                |
+-------------------+
1 row in set (0.00 sec)

mysql> select * from t1;
+-----------+-------+------+------+-------+
| Sno       | Sname | Ssex | Sage | Sdept |
+-----------+-------+------+------+-------+
| 202112081 |       |      |   20 | CS    |
| 202112082 |       |      |   19 | CS    |
| 202112083 |       |      |   18 | MA    |
| 202112085 |       |      |   19 | IS    |
+-----------+-------+------+------+-------+
4 rows in set (0.00 sec)

在这里插入图片描述

在这里插入图片描述

进入新的pod中,数据仍然存在,持久化成功。很安全。

MySQL 服务恢复,数据也完好无损。

猜你喜欢

转载自blog.csdn.net/YourMr/article/details/121945077