当前位置: 首页 > news >正文

k8s mysql volume_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.6

V1.14.2

2C2G

node节点

centos7

Centos 7.3.1611

172.27.9.181

×

×

1C1G

nfs服务器

一、Volume

1. 概念

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

2. 为什么需要Volume

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

3. Volume类型

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

4ada5e38ff20158e1d26348cb8cba3eb.png

本文将对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中两个容器之间的文件共享

b201cedf2b08519f279ba9a00bfcbf2c.png

2. 创建pod emptyDir-fortune

[root@master ~]# more emptyDir-pod.yaml

apiVersion: v1

kind: Pod

metadata:

labels:

app: prod #pod标签

name: emptydir-fortune

spec:

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 GATES

emptydir-fortune 2/2 Running 0 9s 10.244.2.140 node02

2fb24cdd6e52d586e6d3d7d97ef6405a.png

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

2.1 loong576/fortune镜像

root@master ~]# more Dockerfile

[root@master ~]# more fortune/Dockerfile

FROM ubuntu:latest

RUN apt-get update ; apt-get -y install fortune

ADD fortuneloop.sh /bin/fortuneloop.sh

E*TRYPOINT /bin/fortuneloop.sh

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

fortuneloop.sh脚本:

[root@master ~]# more fortuneloop.sh

#!/bin/bash

trap "exit" SIGINT

mkdir /var/htdocs

while :

do

echo $(date) Writing fortune to /var/htdocs/index.html

/usr/games/fortune > /var/htdocs/index.html

sleep 10

done

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

3. 访问nginx

3.1 创建service

[root@master ~]# more service-fortune.yaml

apiVersion: v1

kind: Service

metadata:

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) AGE

kubernetes ClusterIP 10.96.0.1 443/TCP 3d17h

my-service NodePort 10.102.191.57 8881:30002/TCP 9s

3.2 nginx访问

[root@master ~]# curl 10.102.191.57:8881

Writing is easy; all you do is sit staring at the blank sheet of paper until

drops of blood form on your forehead.

-- Gene Fowler

[root@master ~]# curl 172.27.9.135:30002

Don't Worry, Be Happy.

-- Meher Baba

ad7d385adbe1747f8b989d75984419a5.png

结论:

容器nginx成功的读取到了容器fortune写入存储的内容,emptyDir卷可以实现容器间的文件共享。

emptyDir卷的生存周期与pod的生存周期相关联,所以当删除pod时,卷的内容就会丢失

三、hostPath

1. 概念

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

dd1bc5c49920f99ca9144839315fd506.png

2. 创建pod hostpath-nginx

2.1 创建挂载目录

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

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

2.2 创建pod

[root@master ~]# more hostPath-pod.yaml

apiVersion: v1

kind: Pod

metadata:

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 wide

NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES

emptydir-fortune 2/2 Running 0 40m 10.244.2.140 node02

hostpath-nginx 1/1 Running 0 16s 10.244.1.140 node01

3. 访问pod hostpath-nginx

[root@master ~]# curl 10.244.1.140

node01

328045d2c23ba35fac91132311577c65.png

结论:

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服务器搭建和客户端nfs软件安装安装后,可在master和各node节点检查nfs服务是否正常

[root@master ~]# showmount -e 172.27.9.181

Export list for 172.27.9.181:

/backup 172.27.9.0/24

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

ff142955e6e1ddc80931521412884d32.png

本文测试的NFS内容:

151377c7a61c9acf8b439f2d5fd84a96.png

3. 新建pod mongodb-nfs

[root@master ~]# more mongodb-pod-nfs.yaml

apiVersion: v1

kind: Pod

metadata:

name: mongodb-nfs

spec:

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 GATES

mongodb-nfs 1/1 Running 0 23s 10.244.2.142 node02

注意此时pod的ip为10.244.2.142

fd4e0cd209e68af451a16a54ac6c1a68.png

4. nfs共享存储测试

4.1 向MongoDB写入数据

[root@master ~]# kubectl exec -it mongodb-nfs mongo

> use loong

switched to db loong

> db.foo.insert({name:'loong576'})

WriteResult({ "nInserted" : 1 })

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

4.2 查看写入的数据

> db.foo.find()

{ "_id" : ObjectId("5d6e17b018651a21e0063641"), "name" : "loong576" }

34ed1de4bcaaa6136396ed5db859ff7b.png

4.3 删除pod并重建

[root@master ~]# kubectl delete pod mongodb-nfs

pod "mongodb-nfs" deleted

[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 GATES

mongodb-nfs 1/1 Running 0 22s 10.244.2.143 node02

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

4.4 新pod读取共享存储数据

[root@master ~]# kubectl exec -it mongodb-nfs mongo

> use loong

switched to db loong

> db.foo.find()

{ "_id" : ObjectId("5d6e17b018651a21e0063641"), "name" : "loong576" }

94d2c7f34c44dc77f93600e237be8aa6.png

即使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绑定来释放。

2766dbeb28dfbbdf15ff5280063d98df.png

2. 创建PV

2.1 nfs配置

nfs服务器共享目录配置:

[root@centos7 ~]# exportfs

/backup/v1 172.27.9.0/24

/backup/v2 172.27.9.0/24

/backup/v3 172.27.9.0/24

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

[root@master ~]# showmount -e 172.27.9.181

Export 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

2.2 PV创建

[root@master ~]# more pv-nfs.yaml

apiVersion: v1

kind: PersistentVolume

metadata:

name: pv001

spec:

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: v1

kind: PersistentVolume

metadata:

name: pv002

spec:

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: v1

kind: PersistentVolume

metadata:

name: pv003

spec:

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 created

persistentvolume/pv002 created

persistentvolume/pv003 created

[root@master ~]# kubectl get pv

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLA*S REASON AGE

pv001 2Gi RWO Retain Available nfs 26s

pv002 2Gi ROX Retain Available nfs 26s

pv003 1Gi RWO Retain Available nfs 26s

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

c16fa58fdc734bb6b147b4e696c72208.png

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

Available(可用),一块空闲资源还没有被任何声明绑定

Bound(已绑定),卷已经被声明绑定

Released(已释放),声明被删除,但是资源还未被集群重新声明

Failed(失败),该卷的自动回收失败

PV的访问模式有三种:

第一种,ReadWriteOnce:是最基本的方式,可读可写,但只支持被单个Pod挂载。

第二种,ReadOnlyMany:可以以只读的方式被多个Pod挂载。

第三种,ReadWriteMany:这种存储可以以读写的方式被多个Pod共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是NFS。

3b0ec7ee0efaa48829f8675726c15337.png

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

3. 创建PVC

3.1 PVC创建

[root@master ~]# more pvc-nfs.yaml

kind: PersistentVolumeClaim

apiVersion: v1

metadata:

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 pvc

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE

mypvc Bound pv001 2Gi RWO nfs 22s

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

0f92f4d973341ed0e82412242dcc832a.png

3.2 查看选中的PV

PVC筛选条件:

PV

accessModes

storage

pv001

pv002

×

pv003

×

PV查看:

[root@master ~]# kubectl get pv

NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLA*S REASON AGE

pv001 2Gi RWO Retain Bound default/mypvc nfs 12m

pv002 2Gi ROX Retain Available nfs 12m

pv003 1Gi RWO Retain Available nfs 12m

5f40002d8af9cbaca2771686708635c1.png

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

4. pod中使用PVC

[root@master ~]# more mongodb-pod-pvc.yaml

apiVersion: v1

kind: Pod

metadata:

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 GATES

mongodb-pvc 1/1 Running 0 16s 10.244.2.144 node02

30a41bd4b0d0275b6be7ae6b019136e7.png

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

1c77c40ab380cd025c935ccbc6bbb808.png

相关文章:

  • java 能够完成多个http请求并回应_Java Web请求与响应实例详解
  • mysql 交叉查询_MySQL连接查询,内连接,外连接,全连接,交叉连接
  • java中 springurl_基于SpringMVC中的路径参数和URL参数实例
  • java句子倒序_Java实现英文句子中的单词顺序逆序输出的方法
  • JAVA边学边练答案_Struts2边学边练(1)-HelloWorld
  • php gzip css 乱码,php使用gzip压缩传输js和css文件的方法
  • php静态检测工具,PHP静态代码分析工具,可以检测未捕获的异常?
  • php 挂起一个请求一直执行,在后台运行进程挂起PHP pag
  • php设置cookie路径,php 设置cookie路径例子总结
  • 服务器被上传文件php,求助,哪位大神遇到过这种情况,linux服务器总是被上传这些文件...
  • php m grep gd,ubuntu – php5-gd显示在“php -i | grep -i gd“但不是在phpinfo();
  • php my global.h,11月13日任务 - 志明咖的个人空间 - OSCHINA - 中文开源技术交流社区...
  • php限制输入数字,如何使用javascript和php禁用数字输入类型
  • php7 curl 慢,PHP7无法加载curl模块
  • 二叉树建树java,二叉树的建树、遍历(先序、中序、后序、层次)(递归和非递归)--Java实现...
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • Brief introduction of how to 'Call, Apply and Bind'
  • css布局,左右固定中间自适应实现
  • OSS Web直传 (文件图片)
  • puppeteer stop redirect 的正确姿势及 net::ERR_FAILED 的解决
  • Python - 闭包Closure
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • windows下使用nginx调试简介
  • Yii源码解读-服务定位器(Service Locator)
  • 可能是历史上最全的CC0版权可以免费商用的图片网站
  • 前端技术周刊 2019-01-14:客户端存储
  • 如何实现 font-size 的响应式
  • 原生JS动态加载JS、CSS文件及代码脚本
  • Python 之网络式编程
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #《AI中文版》V3 第 1 章 概述
  • #微信小程序:微信小程序常见的配置传值
  • (1)(1.13) SiK无线电高级配置(六)
  • (2)MFC+openGL单文档框架glFrame
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • .dwp和.webpart的区别
  • .net core Swagger 过滤部分Api
  • .NET 动态调用WebService + WSE + UsernameToken
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • @angular/cli项目构建--http(2)
  • [28期] lamp兄弟连28期学员手册,请大家务必看一下
  • [android] 请求码和结果码的作用
  • [Angular] 笔记 7:模块
  • [BROADCASTING]tensor的扩散机制
  • [bug总结]: Feign调用GET请求找不到请求体实体类
  • [ffmpeg] aac 音频编码