写在前面
本来是可以将数据存储在 容器内部 的。但是存在容器内部,一旦容器被删除掉或者容器毁坏(我亲身经历的痛,当时我们的大数据平台就是运行在docker容器内,有次停电后,不管怎样容器都起不来。以前的同事也没有将数据映射到外面 。搞得最后我们重新导的数据,痛的领悟啊~~)。
再就是如果不将数据映射出来 ,比如要想使用容器内部的web日志,也是比较难搞,反正不就是其它容器/服务不是很方便。
大体上来说,一般只要使用Docker都会将 重要的数据 进行持久化。
本文有任何问题,欢迎留言指正~
Docker 持久化存储技术
默认仅在Container Layer(层) 保存的文件数据,删除容器就没有了
Data Volume(卷):数据卷,数据挂载相关,外挂一个存储
这个外挂的存储 ,即:Volume 有三种类型:
Volume 卷的三种类型:
-
Volume
Docker 自己管理的 Data Volume ,由docker后台自动创建,我们不要去 手动 更改映射出来的文件内容。挂载点 存于主机文件系统中的某个区域docker area(linux 一般是存储在 /var/lib/docker/volumes/ 目录下)。这种持久化方式是很推荐的*****。
-
Bind Mounting
将当前主机目录 与 指定的容器内部目录进行绑定 --> 实现数据共享我们在开发的时候比较推荐这种方式,实现数据共享
Docker的 **数据共享** 技术 能极大提高开发人员的开发效率
配合chrome插件super auto refresh plus,边写代码,边看运行结果。相当舒服~。
- tmpfs mount(Linux中):存于内存中(注意,并不是持久化到磁盘)。在容器的生命周期中,它能被容器用来存放非持久化的状态或敏感信息
上图 卷的三种类型,后文主要根据代码来讲解这几种类型
Volume 相关的常用命令:
列出所有卷:docker volume ls
删除某个卷:docker volume rm 卷名
删除所有未使用的卷:docker volume prune # 慎用
创建:docker volume create
查看某个卷的元信息:docker volume inspect 卷名
容器数据 持久化 实操
类型一:Volume
如果没有显式创建卷,一个卷会在最开始 挂载<VOLUME["/var/lib/mysql"] > 时被创建。当容器停止时,卷仍然存在。多个容器可以通过read-write或read-only的方式使用同一个卷。只有在显式删除时,卷才会被删除。
查看官方mysql Dockerfile 中定义的持久化存储方式:
https://github.com/docker-library/mysql/blob/6952c5d5a9889311157362c528d65dc2e37ff660/5.7/Dockerfile
发现是通过 VOLUME["/var/lib/mysql"] 这样的方式将数据持久化到本地的
意思是指,需要将容器内部/var/lib/mysql 目录下的数据 映射出去
不指定其实是不会将数据映射出来的。
映射出来的位置是在/var/lib/docker/volumes/ ,他会自己在该目录下生成一个volume ID
实际的数据就是保存在其中的。
代码验证上面这段话:
docker volume ls
docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
[root@localhost ~]# docker ps
cef34ac36e63 mysql:5.7 "docker-entrypoint.s…" 16 seconds ago Up 15 seconds 3306/tcp, 33060/tcp mysql1
[root@localhost ~]#
docker exec -it mysql1 bash
mysql -u root
create database test1;
quit
exit
回到本地主机:
docker volume ls
docker volume inspect [volume ID]
详细信息中可以看见挂载点
cd 进去,可以看见实际的数据库文件是真实存在的。
/var/lib/docker/volumes/1b7400bf5cca58f06957e865ab7c072b4cd5961c56d536357fb69575985ecbac/_data
[root@localhost _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 test1
[root@localhost _data]#
其实这个时候你把容器停止,删除容器。数据库的文件还是会在本地保留的
# 强制删除运行中的容器
docker rm -f mysql1
# 删除volume
docker volume rm VOLUME NAME
【升级1】
上面的方式有一个不好的地方就是:由于没有指定映射的对应目录,自动为我们生成了一个很长的Volume ID,
这个其实是不太好管理的。最好的方式是,我们自己指定名称。
具体如下:
通过-v 指定映射
docker run -d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
[root@localhost ~]# docker volume ls
DRIVER VOLUME NAME
local mysql
[root@localhost ~]#
发现是我们自己指定的名称mysql
【升级2】
上面的还有一个不好的一点 就是不太方便移植映射出来,
我们如果可以将映射出来的目录指定到 Dockerfile 同一级目录下就更好了,
要想实现这个 可以通过编写 docker-compose.yml 文件,在文件中定义volume
volume这种方式可以很好的将数据持久化的本地文件系统中,【推荐】
类型二:Bind Mounting
将当前目录外部 与 指定的容器内部目录进行绑定 --> 实现数据共享
案例中 实现容器内部 /usr/share/nginx/html 与 本机主机 /root/docker-nginx
两个目录下的文件共享
案例:
[root@localhost ~]# mkdir docker-nginx
[root@localhost ~]# cd docker-nginx/
[root@localhost docker-nginx]# vim Dockerfile
FROM nginx:latest
WORKDIR /usr/share/nginx/html
COPY index.html index.html
[root@localhost docker-nginx]# docker build -t liuge36docker/my-nginx .
Sending build context to Docker daemon 3.072kB
Step 1/3 : FROM nginx:latest
---> 2073e0bcb60e
Step 2/3 : WORKDIR /usr/share/nginx/html
---> Running in 8bdefed78445
Removing intermediate container 8bdefed78445
---> 747647be78f1
Step 3/3 : COPY index.html index.html
---> b6a5afe9dcf8
Successfully built b6a5afe9dcf8
Successfully tagged liuge36docker/my-nginx:latest
[root@localhost docker-nginx]#
# 创建容器
将当前目录与 指定的容器内部目录进行绑定
[root@localhost docker-nginx]# docker rm -f web
web
[root@localhost docker-nginx]# docker run -d -v $(pwd):/usr/share/nginx/html -p 8777:80 --name web liuge36docker/my-nginx
4822d9626b36c2b539527a9ba8d9cdebfaee19762b02f957559e4f2ae6e2d281
[root@localhost docker-nginx]# docker exec -it web /bin/bash
root@4822d9626b36:/usr/share/nginx/html# ls
Dockerfile index.html
root@4822d9626b36:/usr/share/nginx/html# touch hello.txt
root@4822d9626b36:/usr/share/nginx/html# exit
exit
[root@localhost docker-nginx]# ls
Dockerfile hello.txt index.html
[root@localhost docker-nginx]# echo "1111" >> hello.txt
[root@localhost docker-nginx]# docker exec -it web /bin/bash
root@4822d9626b36:/usr/share/nginx/html# cat hello.txt
1111
root@4822d9626b36:/usr/share/nginx/html#
后面我可能会根据 SpringBoot 单独写一篇文章 ,看看到底这个代码共享 该怎么去做。
本文比较基础,后面我再写一下关于 容错、 备份、恢复、迁移数据卷 相关的东西。
尽情期待~
有什么问题,欢迎留言讨论~~
更多文章:系统学习Docker 不迷路:https://blog.csdn.net/liuge36/category_7651616.html