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:

[[email protected] yaml]# vim emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
  name: read-write
spec:
  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, 并进行查看:
[[email protected] yaml]# kubectl  apply -f  emptydir.yaml
pod/read-write created
[[email protected] yaml]# kubectl  get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
read-write   2/2     Running   0          14s   10.244.2.2   node02   <none>           <none>
//我们分别查看两个容器中的挂载内容:
[[email protected] yaml]# kubectl  exec  -it read-write -c read cat /read/hello
hello volumes
[[email protected] yaml]# kubectl  exec  -it read-write -c write cat /write/hello
hello 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上的真正路径。
所以我们可以进入到该路径下进行查看:

[[email protected] ~]# cd /var/lib/kubelet/pods/756b4f4a-917a-414d-a7ee-523eecf05465/volumes/kubernetes.io~empty-dir/share-volume/
[[email protected] 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服务:

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

2)创建pv:

[[email protected] yaml]# vim nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: nfs
  nfs:
    path: /nfsdata     #指定nfs共享目录
    server: 172.16.1.30    #指定的是nfs服务器的ip地址
//通过以下命令来运行pv:
[[email protected] 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是否可用:
[[email protected] yaml]# kubectl  get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv   1Gi (容量为1GB)       RWO (读写)          Recycle   (自动回收)       Available(可用的,确保是该状态才可被使用)           nfs(基于nfs来做的)                     18m(时间)

3)创建一个pvc:

[[email protected] yaml]# vim nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteOnce     #pv和pvc的访问模式必须一致
  resources:             #在该字段下的requests子字段中定义要申请的资源
    requests:
      storage: 1Gi
  storageClassName: nfs
运行该pvc:
[[email protected] yaml]# kubectl apply -f  nfs-pvc.yaml
persistentvolumeclaim/nfs-pvc created
//验证pvc是否可用:
[[email protected] yaml]# kubectl  get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound   nfs-pv   1Gi        RWO            nfs            3m53s

[[email protected] yaml]# kubectl  get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   1Gi        RWO            Recycle          Bound    default/nfs-pvc   nfs                     29m

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

pv空间的使用。

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

[[email protected] yaml]# vim mysql-pod.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: mysql
spec:
  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: Service
metadata:
  name: mysql
spec:
  type: NodePort
  ports:
  - port: 3306
    targetPort: 3306
    nodePort: 30000
  selector:
    app: mysql
通过以下命令来运行pod:
[[email protected] yaml]# kubectl apply -f  mysql-pod.yaml
deployment.extensions/mysql created
service/mysql created
//查看pod是否正常运行:
[[email protected] yaml]# kubectl  get pod -o wide mysql-68d65b9dd9-hf2bf
NAME                     READY   STATUS    RESTARTS   AGE     IP           NODE     NOMINATED NODE   READINESS GATES
mysql-68d65b9dd9-hf2bf   1/1     Running   0          9m34s   10.244.1.3   node01   <none>           <none>

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

[[email protected] yaml]# kubectl  exec  -it mysql-68d65b9dd9-hf2bf  -- mysql -u root -p123.com
Type ‘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 changed
mysql> 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,验证数据库内数据是否还会存在

[[email protected] ~]# kubectl  delete pod mysql-68d65b9dd9-hf2bf
pod "mysql-68d65b9dd9-hf2bf" deleted
[[email protected] ~]# kubectl  get pod -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP           NODE     NOMINATED NODE   READINESS GATES
mysql-68d65b9dd9-bf9v8   1/1     Running   0          26s    10.244.1.4   node01   <none>           <none>

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

[[email protected] ~]# kubectl  exec  -it mysql-68d65b9dd9-bf9v8 -- mysql -u root -p123.com
Type ‘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主机关机。
##[[email protected] ~]# systemctl poweroff

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

[[email protected] ~]# kubectl  get nodes   #得知node01节点已经宕机
NAME     STATUS     ROLES    AGE   VERSION
master   Ready      master   39d   v1.15.0
node01   NotReady   <none>   39d   v1.15.0
node02   Ready      <none>   39d   v1.15.0

[[email protected] ~]# kubectl  get pod -o wide
NAME                     READY   STATUS        RESTARTS   AGE   IP           NODE     NOMINATED NODE   READINESS GATES
mysql-68d65b9dd9-bf9v8   1/1     Terminating   0          15m   10.244.1.4   node01   <none>           <none>
mysql-68d65b9dd9-mvxdg   1/1     Running       0          83s   10.244.2.3   node02   <none>           <none>

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

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

[[email protected] ~]# kubectl exec  -it mysql-68d65b9dd9-mvxdg  -- mysql -u root -p123.com
Type ‘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数据的持久化,分离了管理员和普通用户的职责,更适合生产环境。

原文地址:https://blog.51cto.com/13972012/2458539

时间: 2024-08-29 14:25:24

k8s之volumes持久化存储的相关文章

一文读懂 K8s 持久化存储流程

作者 | 孙志恒(惠志)? 阿里巴巴开发工程师<br /> 导读:众所周知,K8s 的持久化存储(Persistent Storage)保证了应用数据独立于应用生命周期而存在,但其内部实现却少有人提及.K8s?内部的存储流程到底是怎样的?PV.PVC.StorageClass.Kubelet.CSI 插件等之间的调用关系又如何,这些谜底将在本文中一一揭晓. K8s 持久化存储基础 在进行 K8s 存储流程讲解之前,先回顾一下 K8s 中持久化存储的基础概念. 1. 名词解释 in-tree:代

k8s实践(七):存储卷和数据持久化(Volumes and Persistent Storage)

环境说明: 主机名 操作系统版本 ip docker version kubelet version 配置 备注 master Centos 7.6.1810 172.27.9.131 Docker 18.09.6 V1.14.2 2C2G master主机 node01 Centos 7.6.1810 172.27.9.135 Docker 18.09.6 V1.14.2 2C2G node节点 node02 Centos 7.6.1810 172.27.9.136 Docker 18.09.

k8s附加组件之存储-glusterfs

k8s附加组件之存储-glusterfs 2018/1/16 部署 glusterfs 集群 初始化 glusterfs 集群 创建 glusterfs 卷,用于保存数据 不做特别说明的,都在 67 上操作 集群节点 10.10.9.67 10.10.9.68 10.10.9.69 初始化 glusterfs 集群 ~]# yum install centos-release-gluster310 -y ~]# yum install glusterfs-server -y ~]# yum in

Longhorn:实现Kubernetes集群的持久化存储

Longhorn项目是Rancher Labs推出的开源的基于云和容器部署的分布式块存储新方式.Longhorn遵循微服务的原则,利用容器将小型独立组件构建为分布式块存储,并使用容器编排来协调这些组件,形成弹性分布式系统. 自2017年4月Longhorn项目发布以来,人们对在Kubernetes集群上运行Longhorn存储就产生了极大的兴趣.近日,Longhorn v0.2版本发布了,它可支持任何Kubernetes集群的持久化存储实现! Why Longhorn 如今,基于云和容器的部署规

AKS使用Azure Disk实现动态持久化存储(下)

上一篇文章我们初步体验了AKS pod挂载Azure Disk的流程,这篇文章我们来正式部署一个mysql的服务来看下. 首先准备一个PVC,命名为mysql-pvc.yaml,内容如下: apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc spec: accessModes: - ReadWriteOnce storageClassName: managed-premium resources: reques

Kubernetes 系列(六):持久化存储 PV与PVC(一)

在使用容器之后,我们需要考虑的另外一个问题就是持久化存储,怎么保证容器内的数据存储到我们的服务器硬盘上.这样容器在重建后,依然可以使用之前的数据.但是显然存储资源和 CPU 资源以及内存资源有很大不同,为了屏蔽底层的技术实现细节,让用户更加方便的使用,Kubernetes便引入了 PV 和 PVC 两个重要的资源对象来实现对存储的管理. 一.概念 PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术

kubernetes持久化存储,静态存储【pv】,动态存储【StorageClass】(5)

在开始介绍k8s持久化存储前,我们有必要了解一下k8s的emptydir和hostpath.configmap以及secret的机制和用途 1.EmptydirEmptyDir是一个空目录,他的生命周期和所属的 Pod 是完全一致的,pod删掉目录消失 2.HostpathHostpath会把宿主机上的指定卷加载到容器之中,如果 Pod 发生跨主机的重建,其内容就难保证了 3.ConfigmapConfigMap跟Secrets类似,但是ConfigMap可以更方便的处理不包含敏感信息的字符串.

storageclass和本地持久化存储

StorageClass 之前我们部署了PV 和 PVC 的使用方法,但是前面的 PV 都是静态的,什么意思?就是我要使用的一个 PVC 的话就必须手动去创建一个 PV,我们也说过这种方式在很大程度上并不能满足我们的需求,比如我们有一个应用需要对存储的并发度要求比较高,而另外一个应用对读写速度又要求比较高,特别是对于 StatefulSet 类型的应用简单的来使用静态的 PV 就很不合适了,这种情况下我们就需要用到动态 PV,也就是我们今天要讲解的 StorageClass. 创建 要使用 St

Docker持久化存储之数据共享

持久化存储 Data volume 要知道容器是有生命周期的.docker默认的存储方式:存储类型:(strage driver:overlay2.xfs) data volume有两种挂载方式: 1)bind mount(用户管理):将宿主机上的某个目录或文件(不可以是没有格式化的磁盘文件),挂载到容器中,默认在容器内对此目录是有读写权限的,如果只需要向容器内添加文件,不希望覆盖目录,需要注意源文件必须存在,否则会被当做一个目录bind mount给容器.2)docker manager vo