一.什么是卷挂载
当我们使用mysql容器的时候,会想如果容器被销毁了(很常见的事情)那么我的数据不就丢失了吗
所以就引出了docker的卷挂载技术
它支持将容器内的数据完全的同步到宿主机上,当容器销毁的时候,不会影响到宿主机上的数据
当再次创建容器只需要将数据再挂载到容器对应的目录即可
二.使用场景
- mysql等容器的数据持久化
- 容器配置文件持久化
- 其他容器数据持久化
三.简单使用
我们将会把mysql的数据库挂载到本地,以此为例子做一个简单的使用
首先确保已经有了mysql的镜像
- 创建并启动mysql实例
- 我们将容器中的/var/lib/mysql目录挂载到了本机的/Users/fujunhua/mysql_data上
docker run -itd --name test-volume -p 3305:3306 -eMYSQL_ROOT_PASSWORD=123456 -v /Users/fujunhua/mysql_data:/var/lib/mysql mysql:5.7
- 我们可以用 -v 宿主机路径:容器路径 -v 宿主机路径:容器路径 … 挂载很多个路径
- 查看本机上的数据
(base) fujunhua@Antg ~ % ls mysql_data
auto.cnf client-cert.pem ib_logfile0 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile1 mysql public_key.pem sys
ca.pem ib_buffer_pool ibdata1 performance_schema server-cert.pem
-
创建一个数据库测试数据是否同步
-
测试删除容器后数据是否还在(数据未删除)
(base) fujunhua@Antg hello_world_web % docker stop 91509d26a004
91509d26a004
(base) fujunhua@Antg hello_world_web % docker rm 91509d26a004
91509d26a004
(base) fujunhua@Antg ~ % (base) fujunhua@Antg ~ % ls mysql_data
auto.cnf client-cert.pem ib_buffer_pool ibdata1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem hello ib_logfile1 performance_schema server-cert.pe
- 测试从新创建容器并挂载到这个目录上后数据是否恢复(数据可以恢复)
四.深入理解
挂载的方式共有3种
# 匿名挂载(仅写容器内需要挂载的路径,不指定宿主机路径)
-v /var/lib/mysql
# 具名挂载(宿主机路径位置写一个挂载名称不指定宿主机路径)
-v mysql-data:/var/lib/mysql
# 路径挂载(宿主机路径:容器挂载路径)
-v /User/xxxx/msyql-data:/var/lib/mysql
1.匿名挂载
当我们创建msyql容器的时候不指定挂载的时候,镜像其实为我们做了一个匿名的挂载
docker run -itd --name test-volume -p 3305:3306 -eMYSQL_ROOT_PASSWORD=123456 mysql:5.7
docker inspect 7ad330d2265a
"Mounts": [
{
"Type": "volume",
"Name": "d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445",
"Source": "/var/lib/docker/volumes/d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "7ad330d2265a",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": true,
"OpenStdin": true,
"StdinOnce": false,
"Env": [
"MYSQL_ROOT_PASSWORD=123456",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"MYSQL_MAJOR=5.7",
"MYSQL_VERSION=5.7.36-1debian10"
],
"Cmd": [
"mysqld"
],
"Image": "mysql:5.7",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
我们可以看到在Config中的Volumes是没有进行挂载的
但是Mounts中为我们将/var/lib/mysql这个路径挂载到了路径
/var/lib/docker/volumes/d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445/_data
我们可以通过命令来看一下挂载的卷
其中就可以找到匿名挂载的名称
(base) fujunhua@Antg hello_world_web % docker volume ls
DRIVER VOLUME NAME
local 0a44bcaa0a13aa9aa328225f7396f3b2b8dd020a03ac9b533fba548288946a6a
local 0b7c5c28250b44df9b546bc8b7cbd7262a419f96ee74b487cea941735c11a919
local 4773859115f3e5dea3b1082da2fb8448eba6aca2b067cd7f067491c0e32eb49c
local d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445
local d1ff004413bc5ab9f4a31876ca07e14a364db5b9fb6a2901a5188281690b5b5e
local my_wordpress_db_data
local my_wordpress_wordpress_data
那它到底在宿主机的何方呢
(base) fujunhua@Antg hello_world_web % docker volume inspect d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445
[
{
"CreatedAt": "2022-03-29T09:08:32Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445/_data",
"Name": "d0f86d6241773144a220a7089e8160a1f64bed5947ee8743e7d67b0262ab8445",
"Options": null,
"Scope": "local"
}
]
可以看到它是在路径/var/lib/docker/volumes/下
在这里还遇到了一个小的问题,因为我使用的是mac,然后这个路径是在docker vm上的mac显示不出来(虽然显示不出来,但是是存在的)
所以我们找一个容器来访问这个路径就可以
解决方法如下:
docker run -it --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
可以看到匿名挂载的数据都在这里
如何使用匿名挂载呢
1.可以在Dockerfile中进行匿名挂载(mysql镜像就是如此)
# 这里我们查看一下mysql是如何做出来的
(base) fujunhua@Antg hello_world_web % docker history mysql:5.7
IMAGE CREATED CREATED BY SIZE COMMENT
c20987f18b13 3 months ago /bin/sh -c #(nop) CMD ["mysqld"] 0B
<missing> 3 months ago /bin/sh -c #(nop) EXPOSE 3306 33060 0B
<missing> 3 months ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
<missing> 3 months ago /bin/sh -c ln -s usr/local/bin/docker-entryp… 34B
<missing> 3 months ago /bin/sh -c #(nop) COPY file:345a22fe55d3e678… 14.5kB
<missing> 3 months ago /bin/sh -c #(nop) VOLUME [/var/lib/mysql] 0B
<missing> 3 months ago /bin/sh -c { echo mysql-community-server m… 313MB
<missing> 3 months ago /bin/sh -c echo 'deb http://repo.mysql.com/a… 55B
<missing> 3 months ago /bin/sh -c #(nop) ENV MYSQL_VERSION=5.7.36-… 0B
<missing> 3 months ago /bin/sh -c #(nop) ENV MYSQL_MAJOR=5.7 0B
<missing> 3 months ago /bin/sh -c set -ex; key='A4A9406876FCBD3C45… 1.84kB
<missing> 3 months ago /bin/sh -c apt-get update && apt-get install… 52.2MB
<missing> 3 months ago /bin/sh -c mkdir /docker-entrypoint-initdb.d 0B
<missing> 3 months ago /bin/sh -c set -eux; savedAptMark="$(apt-ma… 4.17MB
<missing> 3 months ago /bin/sh -c #(nop) ENV GOSU_VERSION=1.12 0B
<missing> 3 months ago /bin/sh -c apt-get update && apt-get install… 9.34MB
<missing> 3 months ago /bin/sh -c groupadd -r mysql && useradd -r -… 329kB
<missing> 3 months ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 3 months ago /bin/sh -c #(nop) ADD file:bd5c9e0e0145fe33b… 69.3MB
可以看到 使用VOLUME 指令进行了匿名挂载,一般我们在做一些需要持久化数据的镜像时都需要在Dockerfile中将目录进行挂载以防run的时候忘记挂载
2.可以在容器启动的时候进行匿名挂载
docker run -itd --name mysql-test -p3305:3306 -eMYSQL_ROOT_PASSWORD=123456 -v /var/lib/mysql mysql:5.7
2.具名挂载
其实懂了匿名挂载后,具名挂载就是给随机生成的名字自己定义一个名字
用法
docker run -itd --name juming-mysql -p3305:3306 -eMYSQL_ROOT_PASSWORD=123456 -v juming-mysql:/var/lib/mysql mysql:5.7
一般我们都会使用具名挂载这种方式(路径挂载太麻烦,匿名挂载不具有语义性)
3.路径挂载
路径挂载就是将容器上的某个路径挂载到宿主机的某个路径
用法
docker run -itd --name test-volume -p 3305:3306 -eMYSQL_ROOT_PASSWORD=123456 -v /Users/fujunhua/mysql_data:/var/lib/mysql mysql:5.7