Docker将运用与运行的环境打包形成容器运行, Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来, 那么当容器删除后,数据自然也就没有了。 为了能保存数据在Docker中我们使用卷。
卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但卷不属于联合文件系统(Union FileSystem),因此能够绕过联合文件系统提供一些用于持续存储或共享数据的特性:。
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。
数据卷的特点:
数据卷可在容器之间共享或重用数据
卷中的更改可以直接生效
数据卷中的更改不会包含在镜像的更新中
数据卷的生命周期一直持续到没有容器使用它为止
总结一句话:容器的持久化和同步操作!容器间也是可以数据共享的!
运行容器,指定挂载数据卷命令:
docker run -it -v 主机目录:容器目录
将主机目录/home/test和容器/home建立数据卷,首先在容器目录下创建test.java文件,再去主机目录下查看是否有该文件。(双向绑定)
查看容器对应元数据docker inspect 容器id,可以在Mounts节点查看建立的数据卷信息。
"Mounts": [
{
"Type": "bind",
"Source": "/home/test", # 主机文件夹地址
"Destination": "/home", # 容器文件夹地址
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
即使容器停止运行或者容器删除,仍然可以实现数据同步,本地的数据卷不会丢失,如下图:
好处:以后修改只需要在本地进行修改接口,容器内会自动同步!
在Linux下的MySQL默认的数据文档存储目录为/var/lib/mysql,默认的配置文件的位置/etc/mysql/conf.d,为了确保MySQL镜像或容器删除后,造成的数据丢失,下面建立数据卷保存MySQL的数据和文件。
# 获取镜像
[root@zecan /]# docker pull mysql:5.7
# 运行容器,需要做数据挂载! # 安装启动mysql 需要配置密码的,这是要注意点!
官方测试:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag
# 启动
-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 容器名字
[root@zecan /]# docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/cinf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
[root@iZwz99sm8v95sckz8bd2c4Z home]# docker images;
REPOSITORY TAG IMAGE ID CREATED SIZE
mytomcat 1.0 f189aac861de About an hour ago 653MB
mysql 5.7 f07dfa83b528 6 days ago 448MB
tomcat latest feba8d001e3f 10 days ago 649MB
nginx latest ae2feff98a0c 12 days ago 133MB
centos latest 300e315adb2f 2 weeks ago 209MB
portainer/portainer latest 62771b0b9b09 5 months ago 79.1MB
elasticsearch 7.6.2 f29a1ee41030 9 months ago 791MB
[root@iZwz99sm8v95sckz8bd2c4Z home]# docker run -d -p 6603:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
72efdb845471b6bd19077b596af51122baa982c01211c39f989afaca556b149f
[root@iZwz99sm8v95sckz8bd2c4Z home]# cd /home
[root@iZwz99sm8v95sckz8bd2c4Z home]# ls
hai mysql pan test test.java
[root@iZwz99sm8v95sckz8bd2c4Z home]# cd mysql/conf
[root@iZwz99sm8v95sckz8bd2c4Z conf]# ls
[root@iZwz99sm8v95sckz8bd2c4Z conf]# cd /home/mysql/data
[root@iZwz99sm8v95sckz8bd2c4Z data]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem
[root@iZwz99sm8v95sckz8bd2c4Z data]# ls
auto.cnf client-cert.pem ibdata1 ibtmp1 private_key.pem server-key.pem
ca-key.pem client-key.pem ib_logfile0 mysql public_key.pem sys
ca.pem ib_buffer_pool ib_logfile1 performance_schema server-cert.pem test
启动成功后,用sqlyog测试一下:
sqlyog连接到服务器的3310 — 3310 和容器内的3306映射,这时即可连接上!
在本地测试创建一个数据库,查看我们映射的路径是否ok:
即便将容器删除,(这里为啥是mysql01来着?)
发现,我们挂载到本地的数据卷依旧没有丢失,这就实现了容器数据持久化功能!
(1)创建数据卷
docker volume create my-vol
(2)查看所有的数据卷
$ docker volume ls
local my-vol
(3)查看指定数据卷的信息
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
]
(4)删除数据卷 docker volume rm …
$ docker volume rm my-vol
(5)删除容器之时删除相关的卷
$ docker rm -v ...
数据卷是被设计用来持久化数据的,它的生命周期独立于容器,Docker 不会在容器被删除后自动删除数据卷,并且也不存在垃圾回收这样的机制来处理没有任何容器引用的数据卷 。如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 docker rm -v 这个命令。
无主的数据卷可能会占据很多空间,要清理请使用以下命令
$ docker volume prune
(5)使用 --mount创建数据卷
挂载一个主机目录作为数据卷。使用 --mount 标记可以指定挂载一个本地主机的目录到容器中去。
$ docker run -d -P \
--name web \
# -v /src/webapp:/opt/webapp \
--mount type=bind,source=/src/webapp,target=/opt/webapp \
training/webapp
python app.py
上面的命令挂载主机的/src/webapp目录到容器的/opt/webapp目录。用户可以放置一些程序到本地目录中,来查看容器是否正常工作。本地目录的路径必须是绝对路径,如果目录不存在 Docker 会自动为你创建它。
Docker 挂载主机目录的默认权限是读写 ,用户也可以通过添加readonly 参数指定为只读 。
$ docker run -d -P \
--name web \
# -v /src/webapp:/opt/webapp:ro \
--mount type=bind,source=/src/webapp,target=/opt/webapp,readonly \
training/webapp \
python app.py
加了readonly之后,就挂载为只读了。如果你在容器内/src/webapp目录新建文件,会显示如下错误
/src/webapp # touch new.txt
touch: new.txt: Read-only file system
匿名挂载就是在指定数据卷的时候,不指定容器路径对应的主机路径,这样对应映射的主机路径就是默认的路径/var/lib/docker/volumes/中自动生成一个随机命名的文件夹。
如下运行并匿名挂载Nginx容器:
[root@zecan home]# docker run -d -P --name nginx02 -v /etc/nginx nginx
3d7cea96607f7ae29c95e723216913ca56a156efe570d6f3dcf572bc14c0e3eb
查看所有的数据卷volume的情况, VOLUME NAME这里的值是真实存在的目录。
[root@zecan home]# docker volume ls
DRIVER VOLUME NAME
local 59729f6eb208943f3a7055249acbb7218073fcb0b6315942aa339241b2b51aeb
local dfb7a1316027a577726ab95a125b36543790f1a0b089928eca7d7c6b373d823d
local fe2e310a2267d09fb47a35bcaa79acacbc31f034c374a250e0f5aa63fbd60b9a
# 匿名挂载
具名挂载,就是指定文件夹名称,区别于指定路径挂载,这里的指定文件夹名称是在Docker指定的默认数据卷路径下的。通过docker volume ls命令可以查看当前数据卷的目录情况。
[root@zecan home]# docker run -d -P --name nginx03 -v juming:/etc/nginx nginx
e3a432eda550769c78e2c092842699f7dc4514fb1dfb803f313da4f7bfc2c14e
[root@zecan home]# docker volume ls
DRIVER VOLUME NAME
local 59729f6eb208943f3a7055249acbb7218073fcb0b6315942aa339241b2b51aeb
local dfb7a1316027a577726ab95a125b36543790f1a0b089928eca7d7c6b373d823d
local fe2e310a2267d09fb47a35bcaa79acacbc31f034c374a250e0f5aa63fbd60b9a
local juming
查看指定的数据卷信息的命令:docker volume inspect数据卷名称
[root@zecan home]# docker volume inspect juming
[
{
"CreatedAt": "2021-11-17T09:25:09+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/juming/_data", #此处注意
"Name": "juming",
"Options": null,
"Scope": "local"
}
]
可以看到主机数据卷挂载在/var/lib/docker/volumes/juming-nginx/_data上
Docker所有的数据卷默认在/var/lib/docker/volumes/ 目录下
[root@iZwz99sm8v95sckz8bd2c4Z volumes]# ls
0cd45ab893fc13971219ac5127f9c0b02491635d76d94183b0261953bdb52d26 backingFsBlockDev juming-nginx
668a94251e562612880a2fdb03944d67d1acdbbdae6ef7c94bee8685644f2956 e605f3dc4bf11ab693972592b55fb6911e5bf2083425fd58869c5f574998a09a metadata.db
匿名挂载,具名挂载,指定路径挂载的命令区别如下:
-v 容器内路径 #匿名挂载
-v 卷名:容器内路径 #具名挂载
-v /宿主机路径:容器内路径 #指定路径挂载
指定数据卷映射的相关参数:
ro —— readonly 只读。设置了只读则只能操作宿主机的路径,不能操作容器中的对应路径。
rw ----- readwrite 可读可写
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:ro nginx
[root@iZwz99sm8v95sckz8bd2c4Z ~]# docker run -d -P --name nginx02 -v juming-nginx:/etc/nginx:rw nginx
我们可以在Dockerfile中使用VOLUME指令来给镜像添加一个或多个数据卷。
下面使用Dockerfile构建一个新的镜像,dockerfile01文件的内容,匿名挂载了volume01和volume02两个目录:
FROM centos
VOLUME ["volume01","volume02"]
CMD echo "----end----"
CMD /bin/bash
执行构建镜像
[root@zecan docker-test-volume]# vim dockerfile1
[root@zecan docker-test-volume]# cat dockerfile1
FROM centos
VOLUME ["volume01","voloume02"]
CMD echo "------end------"
CMD /bin/bash
[root@zecan docker-test-volume]# docker build -f /home/docker-test-volume/dockerfile1 -t zecan/centos:1.0 .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM centos
---> 5d0da3dc9764
Step 2/4 : VOLUME ["volume01","voloume02"]
---> Running in 144849831ffc
Removing intermediate container 144849831ffc
---> 6ec86a221b62
Step 3/4 : CMD echo "------end------"
---> Running in f770c6c9a3c5
Removing intermediate container f770c6c9a3c5
---> 719356789287
Step 4/4 : CMD /bin/bash
---> Running in f53bcade48d3
Removing intermediate container f53bcade48d3
---> 03f7a55d4c61
Successfully built 03f7a55d4c61
Successfully tagged zecan/centos:1.0
[root@zecan docker-test-volume]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
zecan/centos 1.0 03f7a55d4c61 39 seconds ago 231MB
完成镜像的生成后,启动自己生成的容器
[root@iZwz99sm8v95sckz8bd2c4Z docker-test-volume]# docker run -it 1df90e6fd790 /bin/bash
[root@828d43dba78e /]# ls -l
total 56
lrwxrwxrwx 1 root root 7 Nov 3 15:22 bin -> usr/bin
drwxr-xr-x 5 root root 360 Dec 29 15:41 dev
drwxr-xr-x 1 root root 4096 Dec 29 15:41 etc
drwxr-xr-x 2 root root 4096 Nov 3 15:22 home
lrwxrwxrwx 1 root root 7 Nov 3 15:22 lib -> usr/lib
lrwxrwxrwx 1 root root 9 Nov 3 15:22 lib64 -> usr/lib64
drwx------ 2 root root 4096 Dec 4 17:37 lost+found
drwxr-xr-x 2 root root 4096 Nov 3 15:22 media
drwxr-xr-x 2 root root 4096 Nov 3 15:22 mnt
drwxr-xr-x 2 root root 4096 Nov 3 15:22 opt
dr-xr-xr-x 111 root root 0 Dec 29 15:41 proc
dr-xr-x--- 2 root root 4096 Dec 4 17:37 root
drwxr-xr-x 11 root root 4096 Dec 4 17:37 run
lrwxrwxrwx 1 root root 8 Nov 3 15:22 sbin -> usr/sbin
drwxr-xr-x 2 root root 4096 Nov 3 15:22 srv
dr-xr-xr-x 13 root root 0 Dec 29 15:41 sys
drwxrwxrwt 7 root root 4096 Dec 4 17:37 tmp
drwxr-xr-x 12 root root 4096 Dec 4 17:37 usr
drwxr-xr-x 20 root root 4096 Dec 4 17:37 var
drwxr-xr-x 2 root root 4096 Dec 29 15:41 volume01
drwxr-xr-x 2 root root 4096 Dec 29 15:41 volume02
可以看到自动挂载的数据卷目录。下面查看对应宿主机的数据卷目录
[root@zecan docker-test-volume]# docker inspect 3611dc30d500
[
{
"Id": "3611dc30d500bdd597b6f07bded158e35c7378c65e9ff6b8cee33179fb219f03",
"Created": "2021-11-17T02:03:19.7881666Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 705,
"ExitCode": 0,
"Error": "",
"StartedAt": "2021-11-17T02:03:20.120572239Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
...
#重点:
"Mounts": [
{
"Type": "volume",
"Name": "d54f252280e68f9f3eeb8514ffc0c8efe4e352c13532bd539c73fd70d00bff73",
"Source": "/var/lib/docker/volumes/d54f252280e68f9f3eeb8514ffc0c8efe4e352c13532bd539c73fd70d00bff73/_data",
"Destination": "volume01",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "80a4472df985398bb2c0d77cfab68f5ab2e5e491d4b1f551b28a2b7df5db9959",
"Source": "/var/lib/docker/volumes/80a4472df985398bb2c0d77cfab68f5ab2e5e491d4b1f551b28a2b7df5db9959/_data",
"Destination": "voloume02",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
以看到Mounts下有宿主机的挂载目录。因为dockerfile中没有指定宿主机目录,所以属于匿名挂载,在/var/lib/docker/volumes/目录下生成了随机命名的路径。
这种方式我们未来使用的特别多,
容器数据卷是指建立数据卷,来同步多个容器间的数据,实现容器间的数据同步。
首先启动容器1,volume01、volume02为挂载目录。\
[root@zecan /]# docker run -it --name volume01 zecan/centos:1.0
[root@a063cc5d2f7c /]# ls
bin etc lib lost+found mnt proc run srv tmp var volume01
dev home lib64 media opt root sbin sys usr voloume02
然后启动容器2,通过参数–volumes-from,设置容器2和容器1建立数据卷挂载关系。
[root@zecan /]# docker run -it --name docker02 --volumes-from docker01 zecan/centos:1.0
[root@c7cf5c9cd866 /]# ls
bin etc lib lost+found mnt proc run srv tmp var volume01
dev home lib64 media opt root sbin sys usr voloume02
首先在容器2中的volume01中添加文件
[root@edf164e3efbf /]# cd volume01
[root@edf164e3efbf volume01]# touch 456.txt
[root@edf164e3efbf volume01]# ls
456.txt 789.txt
然后就可以看到容器1的文件也会添加上了。
小结:实际上第三个容器加进来也一样,而三者之间形成了一种“拷贝”的状态,也是一种备份方式。
下面同步两个MySQL的数据库和配置文件,与上面的操作相同,首先建立数据卷,然后给另一个MySQL容器建立容器数据卷挂载,示例:
[root@iZwz99sm8v95sckz8bd2c4Z home]# docker run -d -p 6603:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 --name mysql01 mysql:5.7
[root@iZwz99sm8v95sckz8bd2c4Z home]# docker run -d -p 6604:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql02 --volumes-from mysql01 mysql:5.7
结论:容器之间配置信息的传递,数据卷容器的生命周期一直持续到没有容器使用为止。但是一旦你持久化到了本地,这个时候,本地的数据是不会删除的。
不懂就搜:
vim进入编辑模式、vim命令模式、vim实践
linux入门–服务器购买—宝塔部署环境说明
Nginx简单入门–学习笔记狂神说
Docker基础01–入门总结–(狂神说docker学习笔记)
Docker基础02–Docker容器数据卷详解–(狂神说docker学习笔记)
Docker基础03–Dockerfile详解与镜像发布–(狂神说docker学习笔记)
Docker基础04–Docker网络–(狂神说docker学习笔记)
Docker进阶01–Docker Compose–(狂神说docker学习笔记)
Docker知识点翻阅手册–Docker常用命令、Dockererfile、Compose、网络等整理合集
Docker实战:Mysql、Nginx、web的Docker化部署(安装、自定义镜像、compose管理容器、自定义网络、部署问题及解决)