Docker 容器数据 持久化(系统学习Docker05)

写在前面

本来是可以将数据存储在 容器内部 的。但是存在容器内部,一旦容器被删除掉或者容器毁坏(我亲身经历的痛,当时我们的大数据平台就是运行在docker容器内,有次停电后,不管怎样容器都起不来。以前的同事也没有将数据映射到外面 。搞得最后我们重新导的数据,痛的领悟啊~~)。
再就是如果不将数据映射出来 ,比如要想使用容器内部的web日志,也是比较难搞,反正不就是其它容器/服务不是很方便。

大体上来说,一般只要使用Docker都会将 重要的数据 进行持久化。

本文有任何问题,欢迎留言指正~

Docker 持久化存储技术

默认仅在Container Layer(层) 保存的文件数据,删除容器就没有了

Data Volume(卷):数据卷,数据挂载相关,外挂一个存储

Docker 容器数据 持久化(系统学习Docker05)
这个外挂的存储 ,即:Volume 有三种类型:

Volume 卷的三种类型:

  1. Volume
    Docker 自己管理的 Data Volume ,由docker后台自动创建,我们不要去 手动 更改映射出来的文件内容。挂载点 存于主机文件系统中的某个区域docker area(linux 一般是存储在 /var/lib/docker/volumes/ 目录下)。

    这种持久化方式是很推荐的*****。

  2. Bind Mounting
    将当前主机目录 与 指定的容器内部目录进行绑定 --> 实现数据共享

    我们在开发的时候比较推荐这种方式,实现数据共享

    Docker的 数据共享 技术 能极大提高开发人员的开发效率

    配合chrome插件super auto refresh plus,边写代码,边看运行结果。相当舒服~。

  3. tmpfs mount(Linux中):存于内存中(注意,并不是持久化到磁盘)。在容器的生命周期中,它能被容器用来存放非持久化的状态或敏感信息
    Docker 容器数据 持久化(系统学习Docker05)
    上图 卷的三种类型,后文主要根据代码来讲解这几种类型

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 
[ ~]# docker ps
cef34ac36e63        mysql:5.7           "docker-entrypoint.s…"   16 seconds ago      Up 15 seconds       3306/tcp, 33060/tcp                          mysql1
[ ~]# 
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
[ _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
[ _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 
[ ~]# docker volume ls
DRIVER              VOLUME NAME
local               mysql
[ ~]# 
发现是我们自己指定的名称mysql 

【升级2】
上面的还有一个不好的一点 就是不太方便移植映射出来,
我们如果可以将映射出来的目录指定到 Dockerfile 同一级目录下就更好了,
要想实现这个 可以通过编写 docker-compose.yml 文件,在文件中定义volume

volume这种方式可以很好的将数据持久化的本地文件系统中,【推荐】

类型二:Bind Mounting
将当前目录外部 与 指定的容器内部目录进行绑定 --> 实现数据共享

案例中 实现容器内部 /usr/share/nginx/html 与 本机主机 /root/docker-nginx
两个目录下的文件共享

案例:

[ ~]# mkdir docker-nginx
[ ~]# cd docker-nginx/

[ docker-nginx]# vim Dockerfile 
FROM nginx:latest
WORKDIR /usr/share/nginx/html
COPY index.html index.html

[ 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
[ docker-nginx]# 


# 创建容器
将当前目录与 指定的容器内部目录进行绑定 
[ docker-nginx]# docker rm -f web
web
[ docker-nginx]# docker run -d -v $(pwd):/usr/share/nginx/html -p 8777:80 --name web liuge36docker/my-nginx
4822d9626b36c2b539527a9ba8d9cdebfaee19762b02f957559e4f2ae6e2d281

[ docker-nginx]# docker exec -it web /bin/bash
:/usr/share/nginx/html# ls
Dockerfile  index.html
:/usr/share/nginx/html# touch hello.txt
:/usr/share/nginx/html# exit
exit

[ docker-nginx]# ls
Dockerfile  hello.txt  index.html
[ docker-nginx]# echo  "1111" >> hello.txt 
[ docker-nginx]# docker exec -it web /bin/bash

:/usr/share/nginx/html# cat hello.txt 
1111
:/usr/share/nginx/html#

后面我可能会根据 SpringBoot 单独写一篇文章 ,看看到底这个代码共享 该怎么去做。

本文比较基础,后面我再写一下关于 容错、 备份、恢复、迁移数据卷 相关的东西。

尽情期待~

有什么问题,欢迎留言讨论~~

更多文章:系统学习Docker 不迷路:https://blog.csdn.net/liuge36/category_7651616.html

相关推荐