k8s中的Mysql数据库持久化存储

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了k8s中的Mysql数据库持久化存储相关的知识,希望对你有一定的参考价值。

参考技术A  

一、配置:

环境:

CentOS7 

VMware

笔者配置了四台虚拟机:

K8S-Master节点: 3GB内存   2核CPU   20GB硬盘空间

K8S-node1节点:  2GB内存   2核CPU   30GB硬盘空间

K8S-node2节点:  2GB内存   2核CPU   30GB硬盘空间

镜像仓库节点:      2GB内存   2核CPU   50GB硬盘空间

二、节点规划:

使用三台虚拟机搭建K8S集群,使用一台虚拟机搭建镜像仓库。

每台虚拟机配置两块网卡,其中一块为“NAT模式”,用于拉取镜像等功能。

另外一块网卡为“仅主机模式”,用于集群节点间的通信。归划如下:

K8s-master节点:

仅主机模式:10.10.10.200

NAT模式:  192.168.200.130

K8S-node1节点:

仅主机模式:10.10.10.201

NAT模式:  192.168.200.131

K8S-node2节点:

仅主机模式:10.10.10.202

NAT模式:  192.168.200.132

镜像仓库节点:

仅主机模式:10.10.10.101

NAT模式:  192.168.200.150

三、版本信息

Linux内核版本:

Linux version 3.10.0-862.el7.x86_64 (builder@kbuilder.dev.centos.org)

(gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC) )

 #1 SMP Fri Apr 20 16:44:24 UTC 2018

K8s集群版本为1.15.0版本:

四、基于StatefulSet与PV/PVC的mysql持久化存储实验

1. 在每个节点安装nfs服务

在“镜像仓库”节点,执行以下命令:

yum install -y nfs-common nfs-utils rpcbind

在k8s集群,执行以下命令:

yum install -y nfs-utils rpcbind

2. 在“镜像仓库”节点下,配置nfs服务器

mkdir /nfs_mysql

Chmod 777 /nfs_mysql/

(在测试环境中,为了不考虑用户属性,暂时赋予777权限,但在生产环境不推荐这样做)

Chown nfsnobody /nfs_mysql/

echo “/nfs_mysql *(rw,no_root_squash,no_all_squash,sync)” >> /etc/exports

cat /etc/exports

/nfs_mysql *(rw,no_root_squash,no_all_squash,sync)

systemctl start rpcbind

systemctl start nfs

3. 测试nfs服务是否可用

mkdir /test

showmount -e 10.10.10.101

可见/nfs_mysql *已暴露于共享目录,接下来测试挂载是否可用:

在master节点下执行:

mount -t nfs 10.10.10.101:/nfs_mysql /test/

echo "hello-world">>/test/1.txt

在镜像仓库节点下查看1.txt是否存在,若存在则挂载成功:

可见nfs服务可以正常使用,接下来删除test目录和1.txt

在镜像仓库下:

[root@hub nfs_mysql]# rm -f 1.txt

在Master节点下:

[root@k8s-master ~]# umount /test/

[root@k8s-master ~]# rm -rf /test/

同理,依照以上步骤同时创建:(提供多个mysql副本进行挂载)

nfs_mysql1

nfs_mysql2

完成后需要重启nfs服务

systemctl restart rpcbind

systemctl restart nfs

最终效果:

4. 将nfs封装成pv

创建mysql_test文件夹,将yaml文件统一保存在此目录下

mkdir mysql_test

cd mysql_test

vim mysql-pv.yml

mysql-pv.yml配置如下:

apiVersion: v1

kind: PersistentVolume

metadata:

  name: mysql-pv

spec:

  capacity:

    storage: 5Gi

  accessModes:

    -  ReadWriteOnce

  persistentVolumeReclaimPolicy: Retain

  storageClassName: nfs

  nfs:

    path: /nfs_mysql

    server: 10.10.10.101

---

apiVersion: v1

kind: PersistentVolume

metadata:

  name: mysql-pv1

spec:

  capacity:

    storage: 5Gi

  accessModes:

    -  ReadWriteOnce

  persistentVolumeReclaimPolicy: Retain

  storageClassName: nfs

  nfs:

    path: /nfs_mysql1

    server: 10.10.10.101

---

apiVersion: v1

kind: PersistentVolume

metadata:

  name: mysql-pv2

spec:

  capacity:

    storage: 5Gi

  accessModes:

    -  ReadWriteOnce

  persistentVolumeReclaimPolicy: Retain

  storageClassName: nfs

  nfs:

    path: /nfs_mysql2

    server: 10.10.10.101

注意:

在k8s集群15版本中recycle回收策略已被删除,只能用retain策略或者Delete策略。这里我们使用 persistentVolumeReclaimPolicy: Retain

 

执行命令:

kubectl create -f mysql-pv.yml

kubectl get pv

如图所示,即为Pv创建成功。

5. 部署MySQL,在mysql_test目录下编写mysql.yml,配置文件如下

apiVersion: v1

kind: Service

metadata:

  name: mysql

  labels:

    app: mysql

spec:

  ports:

  - port: 3306

    name: mysql

  clusterIP: None

  selector:

    app: mysql

---

apiVersion: apps/v1

kind: StatefulSet

metadata:

  name: mysql

spec:

  selector:

    matchLabels:

      app: mysql

  serviceName: "mysql"

  replicas: 3

  template:

    metadata:

      labels:

        app: mysql

    spec:

      containers:

      - name: mysql

        image: mysql:5.6

        env:

        - name: MYSQL_ROOT_PASSWORD

          value: password

        ports:

        - containerPort: 3306

          name: mysql

        volumeMounts:

        - name: mysql-persistent-storage

          mountPath: /var/lib/mysql

  volumeClaimTemplates:

  - metadata:

      name: mysql-persistent-storage

    spec:

      accessModes: ["ReadWriteOnce"]

      storageClassName: "nfs"

      resources:

        requests:

          storage: 1Gi  

执行以下命令,部署mysql服务:

kubectl create -f mysql.yml

如图可知,mysql按StatefulSet依次创建了mysql-0 mysql-1 mysql-2

查看各个Pod部在哪个节点:

6. 通过创建临时容器,使用MySQL客户端发送测试请求给MySQL master节点

注意:

主机名为mysql-0.mysql;跨命名空间的话,主机名请使用mysql-0.mysql. [NAMESPACE_NAME].如果没有指定命名空间,默认为default,即 mysql-0.mysql. default。

   

这里笔者打算关闭node2节点来模拟node2宕机,来测试是否实现数据的持久化存储,

所以我们向node2上的mysql1写入数据。

 

执行以下命令,访问mysql1:

kubectl run mysql-client --image=mysql:5.6 -it --rm --restart=Never -- mysql -h mysql-1.mysql.default -p password

创建数据库demo,并向messages表中写入hello-world

CREATE DATABASE demo; 

CREATE TABLE demo.messages (message VARCHAR(250)); 

INSERT INTO demo.messages VALUES ('hello-world');

如图所示

接下来我们来关闭k8s-node2虚拟机,模拟宕机

查看nodes的运行状态,可知node2的状态已转变为NotReady

一段时间后,k8s将Pod MySql -1迁移到节点k8s-node1

由于时间过长,笔者把三个Pod都删除重启后,验证数据:

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

Docker数据持久化

一、前言

当我们使用Docker创建一个mysql的container, 数据是存储在container内的.
如果有一天不小心执行了docker rm $(docker ps -aq)删除所有container. 那么mysql里的数据也会被删掉, 这是不安全的.
我们需要将数据持久化, 存储在container外部. 即使删除container也不会删除原有的数据.

二、容器的缺陷

容器中的数据可以存储在容器层。但是将数据存放在容器层存在以下问题:
1.数据不是持久化。意思是如果容器删除了,这些数据也就没了
2.主机上的其它进程不方便访问这些数据
3.对这些数据的I/O会经过存储驱动,然后到达主机,引入了一层间接层,因此性能会有所下降

三、data volume有两种挂载方式:

1)bind mount(用户管理):将宿主机上的某个目录或文件(不可以是没有格式化的磁盘文件),挂载到容器中,默认在容器内对此目录是有读写权限的,如果只需要向容器内添加文件,不希望覆盖目录,需要注意源文件必须存在,否则会被当做一个目录bind mount给容器。
2)docker manager volume(docker自动管理):不需要指定源文件,只需要指定mount point(挂载点)。把容器里面的目录映射到了本地。
这种方式相比bind mount 缺点是无法限制对容器里边目录或文件的权限。

使用第二种挂载方式,-v 挂载时,不指定源文件位置,则默认挂载的路径是:

[root@sqm-docker01 _data]# pwd
/var/lib/docker/volumes/dd173640edd5b0205bb02f3c4139647be12528b38289b9f93f18123a6b1266a8/_data
#当有目录挂载时,默认在/var/lib/docker/volumes/下会生成一串hash值,hash值下有一个_data的目录,容器内映射的文件就在此路径下。

四、Storage Driver

数据存储方式

Centos7版本的docker,Storage Driver(数据存储方式)为:overlay2 ,Backing Filesystem(文件系统类型): xfs

可使用 “docker inspect 容器名称” 来查看数据存储方式

五、Data Volume

(Bind mount)

持久化存储:本质上是DockerHost文件系统中的目录或文件,能够直接被Mount到容器的文件系统中。在运行容器时,可通过-v实现。

特点:
**1. Data Volume是目录或文件,不能是没有格式化的磁盘(块设备)。

  1. 容器可以读写volume中的数据。
  2. Volume数据可以永久保存,即使使用它的容器已经被销毁。**

小实验:

运行一个nginx服务,做数据持久化

(1)Data Volume是目录或文件,不能是没有格式化的磁盘(块设备)。

[root@docker01 ~]# mkdir html
//创建测试目录
[root@docker01 ~]# cd html/
[root@docker01 html]# echo "This is a testfile in dockerHost." > index.html
//创建测试网页
[root@docker01 ~]# docker run -itd --name testweb -v /root/html/:/usr/share/nginx/html nginx:latest
//运行一个nginx容器,并挂载目录
[root@docker01 ~]# docker inspect testweb

技术图片

[root@docker01 ~]# curl 172.17.0.3
技术图片

注意:dockerhost上需要被挂载的源文件或目录,必须是已经存在,否则,会被当作一个目录挂载到容器中。

(2)容器可以读写volume中的数据。

[root@docker01 ~]# docker exec  -it testweb  /bin/bash
root@ef12d312a94e:/# cd /usr/share/nginx/html/
root@ef12d312a94e:/usr/share/nginx/html# echo "update" > index.html
//容器中更新网页
root@ef12d312a94e:/usr/share/nginx/html# exit
[root@docker01 ~]# cat html/index.html
//可以看到宿主目录的挂载目录也更新了

技术图片

(3)Volume数据可以永久保存,即使,使用它的容器已经被销毁,也可以通过宿主机的挂在目录重新启动一个容器挂载这个目录进行访问。

[root@docker01 ~]# docker ps -a -q |xargs docker rm -f
//删除所有容器
技术图片

[root@docker01 ~]# cat html/index.html
//容器删除之后,宿主机的测试网页也在

技术图片

[root@docker01 ~]# docker run  -itd --name t1  -P -v  /root/html/:/usr/share/nginx/html nginx:latest
//基于测试网页创建一个容器
[root@docker01 ~]# docker ps

技术图片

[root@docker01 ~]# curl 127.0.0.1:32768
//访问一下

技术图片

[root@docker01 ~]# echo "update-new" > html/index.html
//再次更新测试网页
[root@docker01 ~]# curl 127.0.0.1:32768
//在宿主机更新测试网页,刚刚创建的容器的测试网页也会更新

技术图片

(5)默认挂载到容器内的文件,容器是有读写权限。可以在运行容器是-v 后边加“:ro”限制容器的写入权限

[root@docker01 ~]# docker run  -itd --name t2 -P  -v  /root/html/:/usr/share/nginx/html:ro  nginx:latest
//创建容器设置指读权限
[root@docker01 ~]# docker exec -it t2 /bin/bash
//进入容器
root@4739c0f5d970:/# cd /usr/share/nginx/html
root@4739c0f5d970:/usr/share/nginx/html# echo 1234 > index.html
//修改测试网页(失败,因为是只读的)

技术图片

[root@docker01 ~]# echo 654321 > html/index.html 
//宿主机可以更改
[root@docker01 ~]# curl 127.0.0.1:32768

技术图片

(6)并且还可以挂载单独的文件到容器内部,一般他的使用场景是:如果不想对整个目录进行覆盖,而只希望添加某个文件,就可以使用挂载单个文件。
<1>测试1

 [root@docker01 ~]# docker run -itd --name v6 -P -v /root/html/index.html:/usr/share/nginx/html/index.html nginx:latest
[root@docker01 ~]# docker ps

技术图片

[root@docker01 ~]# curl 127.0.0.1:32770
技术图片

<1>测试2

[root@docker01 ~]#  echo test > test.html
[root@docker01 ~]# docker run -itd --name t8 -P -v /root/test.html:/usr/share/nginx/html/test.html nginx:latest

技术图片

[root@docker01 ~]# curl 127.0.0.1:32772/test.html

技术图片

六,Docker Manager Volume

会自动在宿主机生成目录,所以在挂载目录的时候只用写容器中的目录。

[root@docker01 ~]# docker run -itd --name t1 -P  -v /usr/share/nginx/html nginx:latest
[root@docker01 ~]# docker ps

技术图片

[root@docker01 ~]# docker inspect t1
技术图片

[root@docker01 _data]# cd /var/lib/docker/volumes/17c50a065a6b10ccd01ca1ce8091fdf6282dc9dcb77a0f6695906257ecc03a63/_data
[root@docker01 _data]# echo "this is a testfile" > index.html
[root@docker01 _data]# docker ps

技术图片

[root@docker01 _data]# curl 127.0.0.1:32777

技术图片

[root@docker01 _data]# docker volume ls
技术图片

[root@docker01 _data]# docker rm t1 -f
[root@docker01 _data]# cat index.html

技术图片

1.删除容器的操作,默认不会对dockerhost上的源文件操作,如果想要在删除容器时把源文件也删除,可以在删除容器时添加-v选项(一般不推荐使用这种方式,因为文件有可能被其他容器使用)

[root@docker01 _data]# docker run -itd --name t2 -P  -v /usr/share/nginx/html nginx:latest
[root@docker01 ~]# docker inspect t2

技术图片

[root@docker01 ~]# cd /var/lib/docker/volumes/2781dbfdc673fc7d149dc4f6217ef277fe72e05ba2e20fcebb617afe97eccb30/_data
[root@docker01 _data]# docker rm -v t2 -f
t2
[root@docker01 _data]# ls

七,容器与容器的数据共享

Volume container:给其他容器提供volume存储卷的容器。并且它可以提供bind mount,也可以提供docker manager volume。

创建一个vc_data容器

[root@docker01 ~]# docker create --name vc_data  -v ~/html:/usr/share/nginx/html  -v /other/useful/tools busybox
[root@docker01 ~]# docker inspect vc_data

技术图片

[root@docker01 ~]# docker run -itd --name t3 -P  --volumes-from vc_data nginx:latest
[root@docker01 ~]# docker ps

技术图片

[root@docker01 ~]# curl 127.0.0.1:32779
技术图片

以上是关于k8s中的Mysql数据库持久化存储的主要内容,如果未能解决你的问题,请参考以下文章

K8s之MySQL实现数据持久化

k8s 持久化存储-常见的存储卷介绍

docker mysql数据会保存下来吗

k8s1.19.16部署mysql5.7.35主从架构做数据持久化

k8s安装nfs设置pv pvc并部署mysql

k8s安装nfs设置pv pvc并部署mysql