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

一、Volume

1. 概念

  Kubernetes的卷是pod的一个组成部分,因此像容器一样在pod的规范中就定义了。它们不是独立的Kubernetes对象,也不能单独创建或删除。pod中的所有容器都可以使用卷,但必须先将它挂载在每个需要访问它的容器中。在每个容器中,都可以在其文件系统的任意位置挂载卷。

2. 为什么需要Volume

  容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在 Pod 中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的 Volume 抽象就很好的解决了这些问题。

3. Volume类型

目前,Kubernetes支持以下Volume 类型:

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

本文将对emptyDir,hostPath,共享存储NFS,PV及PVC分别进行测试实践。

二、emptyDir

1. emptyDir概念

  emptyDir是最基础的Volume类型,用于存储临时数据的简单空目录。如果Pod设置了emptyDir类型Volume,Pod被分配到Node上时候,会创建emptyDir,只要Pod运行在Node上,emptyDir都会存在(容器挂掉不会导致emptyDir丢失数据),但是如果Pod从Node上被删除(Pod被删除,或者Pod发生迁移),emptyDir也会被删除,并且永久丢失。

  下面将用emptyDir卷实现在同一pod中两个容器之间的文件共享

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

2. 创建pod emptyDir-fortune

<code>[root@master ~]# more emptyDir-pod.yaml apiVersion: v1kind: Podmetadata:  labels:    app: prod                           #pod标签   name: emptydir-fortunespec:  containers:  - image: loong576/fortune    name: html-generator    volumeMounts:                       #名为html的卷挂载至容器的/var/htdocs目录    - name: html      mountPath: /var/htdocs  - image: nginx:alpine    name: web-server    volumeMounts:                       #挂载相同的卷至容器/usr/share/nginx/html目录且设置为只读    - name: html      mountPath: /usr/share/nginx/html       readOnly: true    ports:    - containerPort: 80      protocol: TCP  volumes:  - name: html                          #卷名为html的emptyDir卷同时挂载至以上两个容器    emptyDir: {} [root@master ~]# kubectl apply -f emptyDir-pod.yaml pod/emptydir-fortune created[root@master ~]# kubectl get po -o wide             NAME               READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESemptydir-fortune   2/2     Running   0          9s    10.244.2.140   node02   <none>           <none>/<none>/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

创建pod emptydir-fortune,该pod有两个容器,同时挂载emptyDir卷,容器html-generator向卷中写入随机内容,通过访问容器web-server验证是否实现文件的共享。

2.1 loong576/fortune镜像

root@master ~]# more Dockerfile

<code>[root@master ~]# more fortune/Dockerfile FROM ubuntu:latestRUN apt-get update ; apt-get -y install fortuneADD fortuneloop.sh /bin/fortuneloop.shE*TRYPOINT /bin/fortuneloop.sh/<code>

该镜像的base镜像为ubuntu,镜像启动时会执行fortuneloop.sh脚本

fortuneloop.sh脚本:

<code>[root@master ~]# more fortuneloop.sh #!/bin/bashtrap "exit" SIGINTmkdir /var/htdocswhile :do  echo $(date) Writing fortune to /var/htdocs/index.html  /usr/games/fortune > /var/htdocs/index.html  sleep 10done/<code>

该脚本主要是每10秒钟输出随机短语至index.html文件中。

3. 访问nginx

3.1 创建service

<code>[root@master ~]# more service-fortune.yaml apiVersion: v1kind: Servicemetadata:  name: my-service           #service名spec:  type: NodePort  selector:    app: prod                #pod标签,由此定位到pod emptydir-fortune   ports:  - protocol: TCP    nodePort: 30002          #节点监听端口,暴露静态端口30002对外提供服务    port: 8881               #ClusterIP监听的端口     targetPort: 80           #容器端口   sessionAffinity: ClientIP  #是否支持Session,同一个客户端的访问请求都转发到同一个后端Pod [root@master ~]# kubectl apply -f service-fortune.yaml service/my-service created[root@master ~]# kubectl get svc NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGEkubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          3d17hmy-service   NodePort    10.102.191.57   <none>        8881:30002/TCP   9s/<none>/<none>/<code>

3.2 nginx访问

<code>[root@master ~]# curl 10.102.191.57:8881Writing is easy; all you do is sit staring at the blank sheet of paper untildrops of blood form on your forehead.                -- Gene Fowler[root@master ~]# curl 172.27.9.135:30002Don't Worry, Be Happy.                -- Meher Baba/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

结论:

  • 容器nginx成功的读取到了容器fortune写入存储的内容,emptyDir卷可以实现容器间的文件共享。
  • emptyDir卷的生存周期与pod的生存周期相关联,所以当删除pod时,卷的内容就会丢失

三、hostPath

1. 概念

  hostPath允许挂载Node上的文件系统到Pod里面去。如果Pod需要使用Node上的文件,可以使用hostPath。在同一个节点上运行并在其hostPath卷中使用相同路径的pod可以看到相同的文件。

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

2. 创建pod hostpath-nginx

2.1 创建挂载目录

在node节点上创建挂载目录,master和各node上分别执行如下操作

<code>[root@master ~]# mkdir /data && cd /data && echo `hostname` > index.html/<code>

2.2 创建pod

<code>[root@master ~]# more hostPath-pod.yaml apiVersion: v1kind: Podmetadata:  labels:    app: prod   name: hostpath-nginx spec:  containers:  - image: nginx     name: nginx     volumeMounts:    - mountPath: /usr/share/nginx/html   #容器挂载点       name: nginx-volume                 #挂载卷nginx-volume  volumes:  - name: nginx-volume                   #卷名    hostPath:      path: /data                        #准备挂载的node上的文件系统[root@master ~]# kubectl apply -f hostPath-pod.yaml pod/hostpath-nginx created[root@master ~]# kubectl get po -o wideNAME               READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESemptydir-fortune   2/2     Running   0          40m   10.244.2.140   node02   <none>           <none>hostpath-nginx     1/1     Running   0          16s   10.244.1.140   node01   <none>           <none>/<none>/<none>/<none>/<code>

3. 访问pod hostpath-nginx

<code>[root@master ~]# curl 10.244.1.140node01/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

结论:

  • pod运行在node01上,访问的内容为'node01',为挂载的文件系统/data下index.html内容,容器成功读取到挂载的节点文件系统里的内容。
  • 仅当需要在节点上读取或写入系统文件时才使用hostPath , 切勿使用它们来持久化跨pod的数据。
  • hostPath可以实现持久存储,但是在node节点故障时,也会导致数据的丢失。

四、NFS共享存储

1. 概念

  NFS是Network File System的缩写,即网络文件系统。Kubernetes中通过简单地配置就可以挂载NFS到Pod中,而NFS中的数据是可以永久保存的,同时NFS支持同时写操作。

  emptyDir可以提供不同容器间的文件共享,但不能存储;hostPath可以为不同容器提供文件的共享并可以存储,但受制于节点限制,不能跨节点共享;这时需要网络存储 (NAS),即既可以方便存储容器又可以从任何集群节点访问,本文以NFS为例做测试。

2. nfs搭建及配置

nfs搭建详见:Centos7下NFS服务器搭建及客户端连接配置

完成nfs服务器搭建和客户端nfs软件安装安装后,可在master和各node节点检查nfs服务是否正常

<code>[root@master ~]# showmount -e 172.27.9.181Export list for 172.27.9.181:/backup 172.27.9.0/24/<code>

master和node01、node02节点都执行showmount命令,用于验证nfs服务是否正常,/backup为nfs服务器对外提供的共享目录。

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

本文测试的NFS内容:

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

3. 新建pod mongodb-nfs

<code>[root@master ~]# more mongodb-pod-nfs.yaml apiVersion: v1kind: Podmetadata:  name: mongodb-nfsspec:  containers:  - image: mongo    name: mongodb    volumeMounts:    - name: nfs-data               #挂载的卷名,与上面的mongodb-data保持一致      mountPath: /data/db          #MongoDB数据存放的路径    ports:    - containerPort: 27017      protocol: TCP  volumes:  - name: nfs-data                 #卷名    nfs:      server: 172.27.9.181         #nfs服务器ip      path: /backup                #nfs服务器对外提供的共享目录[root@master ~]# kubectl apply -f mongodb-pod-nfs.yaml pod/mongodb-nfs created[root@master ~]# kubectl get po -o wide                NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESmongodb-nfs   1/1     Running   0          23s   10.244.2.142   node02   <none>           <none>/<none>/<code>

注意此时pod的ip为10.244.2.142

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

4. nfs共享存储测试

4.1 向MongoDB写入数据

<code>[root@master ~]# kubectl exec -it mongodb-nfs mongo> use loongswitched to db loong> db.foo.insert({name:'loong576'})WriteResult({ "nInserted" : 1 })/<code>

切换至db loong,插入JSON文档(name:'loong576')

4.2 查看写入的数据

<code>> db.foo.find(){ "_id" : ObjectId("5d6e17b018651a21e0063641"), "name" : "loong576" }/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

4.3 删除pod并重建

<code>[root@master ~]# kubectl delete pod mongodb-nfs pod "mongodb-nfs" deleted[root@master ~]# kubectl apply -f mongodb-pod-nfs.yamlpod/mongodb-nfs created[root@master ~]# kubectl get po -o wide               NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESmongodb-nfs   1/1     Running   0          22s   10.244.2.143   node02   <none>           <none>/<none>/<code> 

删除pod mongodb-nfs并重建,此时podip变为10.244.2.143,再次访问MongoDB验证之前写入的文档是否还存在。

4.4 新pod读取共享存储数据

<code>[root@master ~]# kubectl exec  -it mongodb-nfs  mongo> use loongswitched to db loong> db.foo.find(){ "_id" : ObjectId("5d6e17b018651a21e0063641"), "name" : "loong576" }/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

即使pod被删除重建仍然能访问共享数据。

结论:

  • NFS共享存储可持久化数据
  • NFS共享存储可跨节点提供数据共享

五、PV and PVC

1. 概念

   PersistentVolume (持久卷, 简称 PV)和Persistent VolumeClaim(持久卷声明,简称 PVC)使得K8s集群具备了存储的逻辑抽象能力,使得在配置Pod的逻辑里可以忽略对实际后台存储技术的配置,而把这项配置的工作交给PV的配置者,即集群的管理者。存储的PV和PVC的这种关系,跟计算的Node和Pod的关系是非常类似的;PV和Node是资源的提供者,根据集群的基础设施变化而变化,由K8s集群管理员配置;而PVC和Pod是资源的使用者,根据业务服务的需求变化而变化,由K8s集群的使用者即服务的管理员来配置。

  当集群用户需要在其pod中使用持久化存储时,他们首先创建PVC清单,指定所需要的最低容量要求和访问模式,然后用户将待久卷声明清单提交给Kubernetes API服务器,Kubernetes将找到可匹配的PV并将其绑定到PVC。PVC可以当作pod中的一个卷来使用,其他用户不能使用相同的PV,除非先通过删除PVC绑定来释放。

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

2. 创建PV

2.1 nfs配置

nfs服务器共享目录配置:

<code>[root@centos7 ~]# exportfs         /backup/v1      172.27.9.0/24/backup/v2      172.27.9.0/24/backup/v3      172.27.9.0/24/<code>

master和各node节点检查nfs配置:

<code>[root@master ~]# showmount -e 172.27.9.181Export list for 172.27.9.181:/backup/v3 172.27.9.0/24/backup/v2 172.27.9.0/24/backup/v1 172.27.9.0/24/<code>

2.2 PV创建

<code>[root@master ~]# more pv-nfs.yaml apiVersion: v1kind: PersistentVolumemetadata:  name: pv001spec:  capacity:    storage: 2Gi                             #指定PV容量为2G  volumeMode: Filesystem                     #卷模式,默认为Filesystem,也可设置为'Block'表示支持原始块设备  accessModes:    - ReadWriteOnce                          #访问模式,该卷可以被单个节点以读/写模式挂载  persistentVolumeReclaimPolicy: Retain      #回收策略,Retain(保留),表示手动回收  storageClassName: nfs                      #类名,PV可以具有一个类,一个特定类别的PV只能绑定到请求该类别的PVC  nfs:                                       #指定NFS共享目录和IP信息    path: /backup/v1    server: 172.27.9.181---apiVersion: v1kind: PersistentVolumemetadata:  name: pv002spec:  capacity:    storage: 2Gi                             #指定PV容量为2G  volumeMode: Filesystem                     #卷模式,默认为Filesystem,也可设置为'Block'表示支持原始块设备  accessModes:    - ReadOnlyMany                           #访问模式,该卷可以被多个节点以只读模式挂载  persistentVolumeReclaimPolicy: Retain      #回收策略,Retain(保留),表示手动回收  storageClassName: nfs                      #类名,PV可以具有一个类,一个特定类别的PV只能绑定到请求该类别的PVC  nfs:                                       #指定NFS共享目录和IP信息    path: /backup/v2    server: 172.27.9.181---apiVersion: v1kind: PersistentVolumemetadata:  name: pv003spec:  capacity:    storage: 1Gi                             #指定PV容量为1G  volumeMode: Filesystem                     #卷模式,默认为Filesystem,也可设置为'Block'表示支持原始块设备  accessModes:    - ReadWriteOnce                          #访问模式,该卷可以被单个节点以读/写模式挂载  persistentVolumeReclaimPolicy: Retain      #回收策略,Retain(保留),表示手动回收  storageClassName: nfs                      #类名,PV可以具有一个类,一个特定类别的PV只能绑定到请求该类别的PVC  nfs:                                       #指定NFS共享目录和IP信息    path: /backup/v3    server: 172.27.9.181[root@master ~]# kubectl apply -f pv-nfs.yaml persistentvolume/pv001 createdpersistentvolume/pv002 createdpersistentvolume/pv003 created[root@master ~]# kubectl get pvNAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLA*S   REASON   AGEpv001   2Gi        RWO            Retain           Available           nfs                     26spv002   2Gi        ROX            Retain           Available           nfs                     26spv003   1Gi        RWO            Retain           Available           nfs                     26s/<code> 

创建pv001、pv002、pv003,分别对应nfs的共享目录/backup/v1、/backup/v2、/backup/v2。

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

卷可以处于以下的某种状态:

  • Available(可用),一块空闲资源还没有被任何声明绑定
  • Bound(已绑定),卷已经被声明绑定
  • Released(已释放),声明被删除,但是资源还未被集群重新声明
  • Failed(失败),该卷的自动回收失败

PV的访问模式有三种:

  • 第一种,ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个Pod挂载。
  • 第二种,ReadOnlyMany:可以以只读的方式被多个Pod挂载。
  • 第三种,ReadWriteMany:这种存储可以以读写的方式被多个Pod共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

PV不属于任何命名空间, 它跟节点一样是集群层面的资源,区别于pod和PVC。

3. 创建PVC

3.1 PVC创建

<code>[root@master ~]# more pvc-nfs.yaml kind: PersistentVolumeClaimapiVersion: v1metadata:  name: mypvc                       #声明的名称,当做pod的卷使用时会用到                          spec:  accessModes:    - ReadWriteOnce                 #访问卷模式,筛选PV条件之一  volumeMode: Filesystem            #卷模式,与PV保持一致,指示将卷作为文件系统或块设备使用  resources:                        #声明可以请求特定数量的资源,筛选PV条件之一    requests:      storage: 2Gi  storageClassName: nfs             #请求特定的类,与PV保持一致,否则无法完成绑定[root@master ~]# kubectl apply -f pvc-nfs.yaml persistentvolumeclaim/mypvc created[root@master ~]# kubectl get pvcNAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGEmypvc   Bound    pv001    2Gi        RWO            nfs            22s/<code>

创建PVC mypvc,访问卷模式为ReadWriteOnce,大小为2G;WO、ROX、RWX、RWO表示可以同时使用卷的工作节点的数量而并非pod的数量。

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

3.2 查看选中的PV

PVC筛选条件:

PV

accessModes

storage

pv001

pv002

×

pv003

×

PV查看:

<code>[root@master ~]# kubectl get pvNAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLA*S   REASON   AGEpv001   2Gi        RWO            Retain           Bound       default/mypvc   nfs                     12mpv002   2Gi        ROX            Retain           Available                   nfs                     12mpv003   1Gi        RWO            Retain           Available                   nfs                     12m/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

pv001被选中,符合PVC定义,pv002访问模式不匹配,pv003大小不匹配。

4. pod中使用PVC

<code>[root@master ~]# more mongodb-pod-pvc.yaml                  apiVersion: v1kind: Podmetadata:  name: mongodb-pvc spec:  containers:  - image: mongo    name: mongodb    volumeMounts:    - name: pvc-data      mountPath: /data/db    ports:    - containerPort: 27017      protocol: TCP  volumes:  - name: pvc-data    persistentVolumeClaim:      claimName: mypvc          #与pvc中声明的name保持一致[root@master ~]# kubectl apply -f mongodb-pod-pvc.yaml pod/mongodb-pvc created[root@master ~]# kubectl get po -o wide                           NAME          READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATESmongodb-pvc   1/1     Running   0          16s   10.244.2.144   node02   <none>           <none>/<none>/<code>
k8s实践(七):存储卷数据持久化Volumes and Persistent Storage

创建pod mongodb-pvc,使用PVC mypvc,测试同四-4中的nfs共享存储测试,不再赘述。

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

本文所有脚本和配置文件已上传:https://github.com/loong576/k8s-Volumes-and-Persistent-Storage.git


分享到:


相關文章: