欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

docker 的数据卷挂载volume(持久化)及其意义(三种方式--volume,自定义volume,volume继承)

程序员文章站 2022-05-11 14:12:19
...

docker 的数据卷挂载volume(持久化)及其意义(三种方式--volume,自定义volume,volume继承)

docker中有许多新的概念,其实也就因为这些新的概念使得学习docker有很多难度,比如说,docker的三要素 仓库,镜像,容器中的仓库是老概念,比较好理解,而镜像和容器对新手来说就很难理解了。

在镜像启动为容器这个阶段,docker需要定义镜像如何使用(比如,必须的环境变量,配置文件的剥离,共享,以方便的定义如何启动镜像)和定义启动为容器后的网络通信形式(比如,是bridge还是nat还是host形式与外界通信,当然,不指定的情况下就默认使用最常使用的bridge模式了,但,桥接模式的IP地址会发生动态的变化,而这作为一个服务来说通常是不可接受的),docker的网络配置是由使用目的来决定的,比较复杂,这不在本文讨论范围,现在要讨论的是容器与宿主机共享数据的问题(也就是通过volume来共享)。

数据共享使得各种集群的部署成为可能,同样的,docker通过镜像所启动的每一个实例(一般将这个实例叫做容器)可以看做一个单独的个体,因为它具有完整的单独的操作系统的大部分特质,这些容器通过它自己所搭建的网络进行通信,互相传递消息,从而使得集群的搭建成为可能。

那么,现在问题来了,如果我有一个镜像,该镜像是一个MySQL5.7的镜像,将它启动为一个容器后,发现这个镜像里的MySQL使用的字符集是utf8,现在我想将数据库使用的字符集更改为utf8mb4,怎么办?

如果是在物理机安装的MySQL,遇到上述问题,我们通常的做法是在MySQL的主配置文件 my.cnf 文件中指定使用哪个字符集并重启MySQL服务使之生效即可,对于docker容器,当然也可以使用这种方法,进入容器-->找到配置文件-->修改文件并保存-->重启容器内的服务(很多容器并没有安装vi,vim这些文本编辑器,还需要自己手动安装~!~~!!!),可是如果一会又有了别的需求,比如,容器运行的MySQL服务缓慢,需要排查什么原因,这个时候怎么办呢?  还是重复上面的步骤  进入容器-->找到日志文件-->排查原因-->找到原因后修复问题?毫无疑问,这样是低效的方法。正是由于这些原因,docker提出了volume这个概念。

如果,能将容器内的所需要经常修改或者监控的文件放在宿主机并与容器内所在的原文件同步,那么这些痛点是不是就不是痛点了呢(也就是相互映射)?答案是肯定的,docker的volume就是互相映射宿主机和容器的文件的(比如将容器内的文件 A映射到了宿主机的家目录下,也就是家目录也有一个A文件,在容器内修改A文件,在宿主机家目录下的A文件也同时改变,同理,宿主机的A改变了,容器的A文件也改变 了,这样的情况,我们就称之为映射)。实现volume的前提是宿主机和容器可以互相的双向通信哦。

以上是docker  volume的意义,下面讲述 volume的实现方式


volume的实现分为两种基本模式:volume 模式,也就是默认的模式和bind模式,也就是绑定模式。和一种简洁模式,tmpfs模式。

本文示例使用的镜像为hub.c.163.com/library/mysql:latest,新手请在安装完docker后执行  docker pull hub.c.163.com/library/mysql:latest  命令

[[email protected] ~]# docker images
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
postgres                      latest              f51c55ac75ed        2 weeks ago         314MB
adminer                       latest              476c78d02a95        4 weeks ago         89.9MB
hub.c.163.com/library/mysql   latest              9e64176cd8a2        3 years ago         407MB

一,=====================Volume模式================================

[[email protected] ~]# docker run -itd -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /var/lib/mysql --name mysql_test hub.c.163.com/library/mysql:latest
6e04a2504b4d523cae3ea36787806da8dc8417242dec81f411ad216353045924

启动了一个新容器,后台模式,volume模式,mysqlroot密码为123456,端口映射3306,容器名称为mysql_test

[[email protected] ~]# docker ps -a
CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS              PORTS                    NAMES
6e04a2504b4d        hub.c.163.com/library/mysql:latest   "docker-entrypoint.s…"   4 minutes ago       Up 4 minutes        0.0.0.0:3306->3306/tcp   mysql_test
[[email protected] ~]# docker inspect 6e04a
#输出做了省略,截取的需要关心的那一部分
"Mounts": [
            {
                "Type": "volume",
                "Name": "27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a",
                "Source": "/var/lib/docker/volumes/27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a/_data",
                "Destination": "/var/lib/mysql",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }

请关注一下  "Type": "volume", "Source": "/var/lib/docker/volumes/27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a/_data",
                "Destination": "/var/lib/mysql", 这三个字段,volume模式只需要在-v后 加要挂载的容器内的文件绝对路径,source的值指的是宿主机的挂载点路径,destination的值指向的是容器内部的mysql 数据库存放目录。

[[email protected] ~]# cd -
/var/lib/docker/volumes/27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a/_data
[[email protected] _data]# ll
total 188484
-rw-r----- 1 polkitd ssh_keys       56 Dec  4 23:13 auto.cnf
-rw------- 1 polkitd ssh_keys     1675 Dec  4 23:13 ca-key.pem
-rw-r--r-- 1 polkitd ssh_keys     1074 Dec  4 23:13 ca.pem
-rw-r--r-- 1 polkitd ssh_keys     1078 Dec  4 23:13 client-cert.pem
-rw------- 1 polkitd ssh_keys     1679 Dec  4 23:13 client-key.pem
-rw-r----- 1 polkitd ssh_keys     1321 Dec  4 23:13 ib_buffer_pool
-rw-r----- 1 polkitd ssh_keys 79691776 Dec  4 23:13 ibdata1
-rw-r----- 1 polkitd ssh_keys 50331648 Dec  4 23:13 ib_logfile0
-rw-r----- 1 polkitd ssh_keys 50331648 Dec  4 23:13 ib_logfile1
-rw-r----- 1 polkitd ssh_keys 12582912 Dec  4 23:13 ibtmp1
drwxr-x--- 2 polkitd ssh_keys     4096 Dec  4 23:13 mysql
drwxr-x--- 2 polkitd ssh_keys     8192 Dec  4 23:13 performance_schema
-rw------- 1 polkitd ssh_keys     1675 Dec  4 23:13 private_key.pem
-rw-r--r-- 1 polkitd ssh_keys      451 Dec  4 23:13 public_key.pem
-rw-r--r-- 1 polkitd ssh_keys     1078 Dec  4 23:13 server-cert.pem
-rw------- 1 polkitd ssh_keys     1679 Dec  4 23:13 server-key.pem
drwxr-x--- 2 polkitd ssh_keys     8192 Dec  4 23:13 sys

可以看到,27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a是一个65位的字符串,这个是由docker自动生成的,如果要在宿主机管理这些文件是十分不方便的,并且这样的一串也不是见名知意,如果后期挂载更多的目录,管理就会混乱了。那么,有什么好的办法解决这样的问题呢?

当然有了,自定义宿主机挂载点的目录的名称即可。

[[email protected] mysql.conf.d]# docker volume list
DRIVER              VOLUME NAME
local               15d6e03f521c068b63287d63a55c2abe38d57ebfa081577e9012002c13943c32
local               27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a
[[email protected] mysql.conf.d]# docker volume create mysql
mysql
[[email protected] mysql.conf.d]# docker volume list
DRIVER              VOLUME NAME
local               15d6e03f521c068b63287d63a55c2abe38d57ebfa081577e9012002c13943c32
local               27fe35c28d6b073bbc8638d6172ea53fcf6de9c5918f400ea5483b7ef3afa30a
local               mysql
#建立了一个自定义的volume ,名字叫mysql,下面就使用它,看看会有什么变化
[[email protected] _data]# docker rm -f $(docker ps -qa)
50fbc82dbfa8
6e04a2504b4d
[[email protected] _data]# docker run -itd -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -v mysql:/var/lib/mysql --name mysql_test hub.c.163.com/library/mysql:latest
85c4316cd729bac756dd92d7fb6d172cbddb59654f3a8aa1255f25b6e4502632
[[email protected] _data]# pwd
/var/lib/docker/volumes/mysql/_data
[[email protected] _data]# ls
auto.cnf    ca.pem           client-key.pem  ibdata1      ib_logfile1  mysql               private_key.pem  server-cert.pem  sys
ca-key.pem  client-cert.pem  ib_buffer_pool  ib_logfile0  ibtmp1       performance_schema  public_key.pem   server-key.pem
[[email protected] _data]# docker inspect 85c43
#输出省略部分内容,截取需要的部分
"Mounts": [
            {
                "Type": "volume",
                "Name": "mysql",
                "Source": "/var/lib/docker/volumes/mysql/_data",#宿主机的目录
                "Destination": "/var/lib/mysql",#容器的目录
                "Driver": "local",#驱动是本地驱动
                "Mode": "z",#相比第一个默认,这有一个值哦
                "RW": true,   #注意了,这个地方表示可读写,启动的时候可以指定是rw还是ro只读
                "Propagation": ""
            }

 

可以看到,启动容器的时候 -v后指定了使用自定义的volume    mysql(自定义的名字就是mysql),与容器的目录之间用:分隔开就可以啦。/var/lib/docker/volumes/mysql/_data这样的形式就很好接受了,见到这个就知道是mysql所使用的volume,并且映射的内容也都有了(也就是容器的数据库所有文件)。

一般推荐使用自定义的volume名称,这样不会造成管理上的混乱。(-v 容器内需要映射的目录,绝对路径形式书写  或者 -v  自定义的volume:容器内需要映射的目录,绝对路径形式书写)

也可以这样写:

[[email protected] _data]# docker run -itd -p 3310:3306  --mount src=mysql,dst=/var/lib/mysql  --name mysql1 -e MYSQL_ROOT_PAAWORD=123456  hub.c.163.com/library/mysql:latest
16150e02d1186e671443d00546a8230b466393301078c5028af3529ce9565917
#原来的旧容器没有删除,因此改了端口和容器名称。-v 改为了--mount, 路径用src和dst指定了

 

二,bind mounts 模式,

删除所有volume的命令为:docker volume rm -f $(docker volume ls -q)

删除所有容器的命令为:docker rm -f $(docker ps -qa)  ,先执行这两个命令恢复原始环境,防止其它的干扰。

bind模式就简单了,

[[email protected] data]# docker run -itd -p 3306:3306 --name mysql -v /opt/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD hub.c.163.com/library/mysql
1c3e7a9160d8116f9af5aceb8a52746e29967d49d5ec64adb25266ff107c469d
[[email protected] data]# docker inspect 1c2e7
#部分输出省略
Mounts": [
            {
                "Type": "bind",
                "Source": "/opt/mysql/data",
                "Destination": "/var/lib/mysql",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }

"Source": "/opt/mysql/data" 这个目录不用事先创建,会自动帮你在宿主机创建好的哦。可以看到type变为了bind。-v 后面 的:左边是宿主机的目录,右边是容器的目录

也可以这样写:指定挂载模式为bind

[[email protected] data]# docker run -itd -p 3306:3306 --name mysql --mount type=bind,src=/opt/mysql/data,dst=/var/lib/mysql  -e MYSQL_ROOT_PASSWORD=123456  hub.c.163.com/library/mysql
9f87a7076d15c0f12e4ba080c12f82154f89ef7b99fa51e4d99eecf6c6dbe52f