千家信息网

k8s之volumes持久化存储

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,k8s之数据持久化kubernetes存储卷:我们知道默认情况下容器的数据都是非持久化的,在容器销毁以后数据也跟着丢失,所以docker提供了volume机制以便将数据持久化存储。类似的,k8s提供了
千家信息网最后更新 2026年10月31日k8s之volumes持久化存储

k8s之数据持久化

kubernetes存储卷:
我们知道默认情况下容器的数据都是非持久化的,在容器销毁以后数据也跟着丢失,所以docker提供了volume机制以便将数据持久化存储。类似的,k8s提供了更强大的volume机制和丰富的插件,解决了容器数据持久化和容器间共享数据的问题。

volume:
我们经常会说:容器和 Pod 是短暂的。
其含义是它们的生命周期可能很短,会被频繁地销毁和创建。容器销毁时,保存在容器内部文件系统中的数据都会被清除。为了持久化保存容器的数据,可以使用k8s volume。
Volume 的生命周期独立于容器,Pod 中的容器可能被销毁和重建,但 Volume 会被保留。

k8s支持的volume类型有emptydir,hostpath,persistentVolumeClaim,gcePersistentDisk,awsElasticBlockStore,nfs,iscsi,gitRepo,secret等等,完整列表及详细文档可参考 http://docs.kubernetes.org.cn/429.html。

在本文中主要实践以下几种volume类型:

1,EmptyDir(临时存储):
emptyDir 是最基础的 Volume 类型。正如其名字所示,一个 emptyDir Volume 是 Host 上的一个空目录。也就是宿主机上没有指定的目录或文件,直接由pod内部映射到宿主机上。(类似于docker中的docker manager volume 挂载方式)

我们通过下面的例子来实践emptydir:

[root@master yaml]# vim emptydir.yamlapiVersion: v1kind: Podmetadata:  name: read-writespec:  containers:  - name: write    image: busybox    volumeMounts:     #定义数据持久化    - mountPath: /write     #定义挂载目录,该目录是pod内部的目录      name: share-volume    args:    - /bin/sh    - -c    - echo "hello volumes" > /write/hello; sleep 3000;      - name: read     #在该pod内定义第二个容器    image: busybox    volumeMounts:    - mountPath: /read      name: share-volume    args:    - /bin/sh    - -c    - cat /read/hello; sleep 30000;  volumes:  - name: share-volume    emptyDir: {}       #定义一个数据持久化的类型empytdir

我们模拟一个pod里运行了两个容器,两个容器共享一个volume,一个负责写入数据,一个负责读取数据。

//运行该pod, 并进行查看:[root@master yaml]# kubectl  apply -f  emptydir.yaml pod/read-write created
[root@master yaml]# kubectl  get pod -o wideNAME         READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATESread-write   2/2     Running   0          14s   10.244.2.2   node02              
//我们分别查看两个容器中的挂载内容:[root@master yaml]# kubectl  exec  -it read-write -c read cat /read/hellohello volumes[root@master yaml]# kubectl  exec  -it read-write -c write cat /write/hellohello volumes

参数解释:
-c :为指定某个容器,是--container= 的缩写,可以通过--help进行查看。

因为 emptyDir 是 Docker Host 文件系统里的目录,其效果相当于执行了 docker run -v /write 和 docker run -v /read。我们在node02
上通过 docker inspect 分别查看容器的详细配置信息,我们发现两个容器都 mount 了同一个目录:

    "Mounts": [        {            "Type": "bind",            "Source": "/var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume",            "Destination": "/read",            "Mode": "",            "RW": true,            "Propagation": "rprivate"        },        {            "Type": "bind",            "Source": "/var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume",            "Destination": "/write",            "Mode": "",            "RW": true,            "Propagation": "rprivate"        },

这里的"/var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume"就是emptydir 挂载到dockerhost上的真正路径。
所以我们可以进入到该路径下进行查看:

[root@node02 ~]# cd /var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume/[root@node02 share-volume]# cat hello hello volumes

总结emptydir:
同个pod里边的不同容器,共享同一个持久化目录。当pod节点删除时,volume的内容也会被删除,但如果仅是容器被销毁,pod还在,则volume不受影响。也就是说emptydir的数据持久化的生命周期和使用的pod一致。一般作为临时存储使用,以及长时间任务的中间过程checkpoint的临时保存目录,及多容器共享目录。

2,hostPath:

  • 1)将宿主机上已经存在的目录或文件挂载到容器内部。
  • 2)这种持久化方式,运用场景不多,因为我们使用虚拟化技术的核心就是为了于宿主机进行隔离,但这种方式它增加了pod于节点之间的耦合。
  • 3)一般对于k8s集群本身的数据持久化,和docker本身的数据持久化会使用这种方式。

比如 kube-apiserver 和 kube-controller-manager 就是这样的应用。
我们通过"kubectl edit -n kube-system pod kube-apiserver-master"命令来查看 kube-apiserver Pod 的配置,下面是 Volume 的相关部分:

volumeMounts:- mountPath: /etc/ssl/certs  name: ca-certs  readOnly: true- mountPath: /etc/pki  name: etc-pki  readOnly: true- mountPath: /etc/kubernetes/pki  name: k8s-certs  readOnly: true
  volumes:  - hostPath:      path: /etc/ssl/certs      type: DirectoryOrCreate    name: ca-certs  - hostPath:      path: /etc/pki      type: DirectoryOrCreate    name: etc-pki  - hostPath:      path: /etc/kubernetes/pki      type: DirectoryOrCreate    name: k8s-certs

这里定义了三个 hostPath volume 分别是k8s-certs、ca-certs 和etc- pki,分别对应 Host 目录 /etc/kubernetes/pki、/etc/ssl/certs 和 /etc/pki。

如果 Pod 被销毁了,hostPath 对应的目录也还会被保留,从这点看,hostPath 的持久性比 emptyDir 强。不过一旦 Host 崩溃,hostPath 也就没法访问了。

3,pv & pvc

  • PersistentVolume(pv):统一的数据持久化目录,是指由集群管理员配置提供的某存储系统上的一段空间,它是对底层共享存储的抽象,将共享存储作为一种可由用户申请使用的资源,实现了"存储消费"机制。
  • PersistentVolumeClaim(PVC):用于pv持久化空间的一个申请(Claim),声明。指定所需要的最低容量要求和访问模式,然后用户将持久卷声明的清单提交给 kubernetes api服务器,kubernetes将找到可匹配的持久卷并将其绑定到持久卷声明。

NFS PersistentVolume
通过 NFS 实践PV和PVC。

1)我们在master节点上部署nfs服务:

[root@master ~]# yum -y install nfs-utils[root@master ~]# mkdir /nfsdata[root@master ~]# vim /etc/exports   #编写nfs配置文件/nfsdata 172.16.1.0/24(rw,sync,no_root_squash)[root@master ~]# systemctl enable rpcbind[root@master ~]# systemctl start rpcbind[root@master ~]# systemctl enable nfs-server[root@master ~]# systemctl start nfs-server
[root@master ~]# showmount -e   #查看是否挂载成功Export list for master:/nfsdata 172.16.1.0/24

2)创建pv:

[root@master yaml]# vim nfs-pv.yamlapiVersion: v1kind: PersistentVolumemetadata:  name: nfs-pvspec:  capacity:      storage: 1Gi  accessModes:    - ReadWriteOnce  persistentVolumeReclaimPolicy: Recycle  storageClassName: nfs  nfs:    path: /nfsdata     #指定nfs共享目录    server: 172.16.1.30    #指定的是nfs服务器的ip地址
//通过以下命令来运行pv:[root@master yaml]# kubectl apply -f  nfs-pv.yaml persistentvolume/nfs-pv created
字段解释:capacity:指定pv的容量大小,目前,capacity仅支持空间设定,将来应该还可以指定IOPS和throughput。accessModes:访问模式,有以下几种模式:                                              ReadWriteOnce: 以读写的方式挂载到单个节点,命令行中简写为RWO。                                              ReadOnlyMany:以只读的方式挂载到多个节点,命令行中简写为ROX。                                              ReadWriteMany: 以读写的方式挂载到多个节点,命令行中简写为RWX。 persistentVolumeReclaimPolicy:pv空间释放时的回收策略,有以下几种策略:                                          Recycle:清除pv中的数据,然后自动回收。(自动回收策略是由pvc的保护机制保护的,当pv删除后,只要pvc还在数据就还在)                                              Retain: 保持不动,由管理员手动回收。                                              Delete: 删除云存储资源,仅部分云储存系统支持,如果AWS,EBS,GCE PD,Azure Disk和Cinder。注意:这里的回收策略是指在pv被删除之后,所存储的源文件是否删除。storageClassName:pv和pvc关联的依据。
//验证pv是否可用:[root@master yaml]# kubectl  get pvNAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGEnfs-pv   1Gi (容量为1GB)       RWO (读写)          Recycle   (自动回收)       Available(可用的,确保是该状态才可被使用)           nfs(基于nfs来做的)                     18m(时间)

3)创建一个pvc:

[root@master yaml]# vim nfs-pvc.yamlapiVersion: v1kind: PersistentVolumeClaimmetadata:  name: nfs-pvcspec:  accessModes:    - ReadWriteOnce     #pv和pvc的访问模式必须一致  resources:             #在该字段下的requests子字段中定义要申请的资源    requests:      storage: 1Gi  storageClassName: nfs
运行该pvc:[root@master yaml]# kubectl apply -f  nfs-pvc.yaml persistentvolumeclaim/nfs-pvc created
//验证pvc是否可用:[root@master yaml]# kubectl  get pvcNAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGEnfs-pvc   Bound   nfs-pv   1Gi        RWO            nfs            3m53s[root@master yaml]# kubectl  get pvNAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGEnfs-pv   1Gi        RWO            Recycle          Bound    default/nfs-pvc   nfs                     29m

确保此时pv和pvc的状态都为Bound,则表示绑定成功。

pv空间的使用。

接下来我们实践mysql的pv使用:
1)创建一个mysql的pod:

[root@master yaml]# vim mysql-pod.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: mysqlspec:  template:    metadata:      labels:        app: mysql    spec:      containers:      - name: mysql        image: mysql:5.7        env:             #定义一个变量,将容器中mysqlroot密码映射到本地        - name: MYSQL_ROOT_PASSWORD          value: 123.com     #密码为123.com        ports:        - containerPort: 3306        volumeMounts:         #定义数据持久化        - name: mysql-pv-storage          mountPath: /var/lib/mysql   #该目录为默认的mysql数据持久化目录      volumes:                     #该volumes字段为上面的一个解释      - name: mysql-pv-storage        #注意名称要与上面的名称相同        persistentVolumeClaim:      #指定pvc,注意下面声明的pvc要于之前创建的pvc名称一致          claimName: nfs-pvc       ---apiVersion: v1                  #创建一个service资源对象kind: Servicemetadata:  name: mysqlspec:  type: NodePort  ports:  - port: 3306    targetPort: 3306    nodePort: 30000  selector:    app: mysql
通过以下命令来运行pod:[root@master yaml]# kubectl apply -f  mysql-pod.yaml deployment.extensions/mysql createdservice/mysql created
//查看pod是否正常运行:[root@master yaml]# kubectl  get pod -o wide mysql-68d65b9dd9-hf2bf NAME                     READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATESmysql-68d65b9dd9-hf2bf   1/1     Running   0          9m34s   10.244.1.3   node01              

2)登录mysql数据库,进行写入数据:

[root@master yaml]# kubectl  exec  -it mysql-68d65b9dd9-hf2bf  -- mysql -u root -p123.comType 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql>
mysql> create database volumes_db;   #创建库Query OK, 1 row affected (0.01 sec)mysql> use volumes_db;      #进入库中Database changedmysql> create table my_id(     #创建表    -> id int primary key,    -> name varchar(25)    -> );Query OK, 0 rows affected (0.04 sec)mysql> insert into my_id values(1,'zhangsan');   #往表中写入数据Query OK, 1 row affected (0.01 sec)mysql> select * from my_id;    #查看数据+----+----------+| id | name     |+----+----------+|  1 | zhangsan |+----+----------+1 row in set (0.00 sec)

3)进行验证:
(1)手动删除pod,验证数据库内数据是否还会存在

[root@master ~]# kubectl  delete pod mysql-68d65b9dd9-hf2bf pod "mysql-68d65b9dd9-hf2bf" deleted
[root@master ~]# kubectl  get pod -o wideNAME                     READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATESmysql-68d65b9dd9-bf9v8   1/1     Running   0          26s    10.244.1.4   node01              

删除pod后,kubernetes会生成新的pod,我们登录mysql查看
数据是否还会存在。

[root@master ~]# kubectl  exec  -it mysql-68d65b9dd9-bf9v8 -- mysql -u root -p123.comType 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> select * from volumes_db.my_id;  +----+----------+| id | name     |+----+----------+|  1 | zhangsan |+----+----------+1 row in set (0.01 sec)

可以看到数据依旧会存在。

2)模拟pod运行所在节点宕机,在新生成的pod内,数据是否恢复正常。
从上面查看pod的信息中,我们知道pod是运行在node01上,所以我们将集群中的node01主机关机。
##[root@node01 ~]# systemctl poweroff

过一段时间后,kubernetes会将pod迁移至集群中node02主机上:

[root@master ~]# kubectl  get nodes   #得知node01节点已经宕机NAME     STATUS     ROLES    AGE   VERSIONmaster   Ready      master   39d   v1.15.0node01   NotReady      39d   v1.15.0node02   Ready         39d   v1.15.0

[root@master ~]# kubectl  get pod -o wideNAME                     READY   STATUS        RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATESmysql-68d65b9dd9-bf9v8   1/1     Terminating   0          15m   10.244.1.4   node01              mysql-68d65b9dd9-mvxdg   1/1     Running       0          83s   10.244.2.3   node02              

可以看到pod已经迁移到了node02上。

最后我们登录mysql,验证数据是否恢复:

[root@master ~]# kubectl exec  -it mysql-68d65b9dd9-mvxdg  -- mysql -u root -p123.comType 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> select * from volumes_db.my_id;+----+----------+| id | name     |+----+----------+|  1 | zhangsan |+----+----------+1 row in set (0.09 sec)

可以得知在pod迁移之后,mysql服务正常运行,且数据也并没有丢失。。。

pv和pvc实现了mysql数据的持久化,分离了管理员和普通用户的职责,更适合生产环境。

数据 容器 目录 存储 运行 节点 方式 命令 文件 空间 验证 两个 字段 宿主 机制 模式 策略 类型 系统 资源 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技企业 中国互联网科技工作委员会毛军 深圳恒合互联网络科技有限公司 科技互联网龙头 奇酷互联网科技公司 互联网科技革命 镁科技互联网资讯平台 互联网巨头投资的硬核科技 太原新华互联网科技学校怎么样 互联网汽车科技小镇 深圳国际航运科技和互联网 互联网科技实习生岗位职责 科技互联网大厂 苏州铭阳互联网科技有限公司 米聚互联网科技南京有限公司排面 张召忠谈中国互联网科技 卡尔迅互联网科技有限公司 全球科技与互联网公司市值变化 万物互联网智能科技 互联网科技大佬云集 科技互联网政务服务 互联网科技汛 互联网巨头投资的硬核科技 华中科技有哪些互联网大佬 科技与互联网哪个更好 佛山市翊博互联网络科技有限公司 工业互联网展湾科技股份有限公司 深圳互联网科技的发展 互联网科技资金流入 优雇互联网科技有限公司
0