Docker数据持久化

Web应用服务的核心是业务逻辑处理,不管是采用了微服务的贫血模型(Get/Set),还是实现数据增删改查的DAO层,操作的关键都是后台的应用数据。同时如果想运行带持久化功能的缓存模块如Redis、数据库集群服务MySQL、微服务配置中心Consul等容器,都需要对后台数据卷进行读写功能。换言之,数据持久化撑起来容器服务的半边天。
Docker数据持久化管理 - 图1

系统卷

之前在Docker镜像一节,大家已经看到了容器文件系统的分层加载模型。Docker在启动的时候采用了默认的storage driver,包含AUFS、Device Mapper、VFS、OverlayFS、Btrfs等。不同操作系统会选择不同的默认存储驱动。以CentOS 7为例:

  1. [root@training1 ~]# docker info
  2. Client:
  3. Debug Mode: false
  4. Server:
  5. Containers: 5
  6. Running: 1
  7. Paused: 0
  8. Stopped: 4
  9. Images: 5
  10. Server Version: 19.03.1
  11. Storage Driver: overlay2
  12. Backing Filesystem: extfs
  13. Supports d_type: true
  14. Native Overlay Diff: false
  15. ...
  16. Docker Root Dir: /var/lib/docker
  17. ...

可以看到,默认的存储驱动是overlay2,采用的文件系统是extfs,系统卷的默认目录是主机的/var/lib/docker目录
在启动启动内的所有数据增删改查操作只会对当前容器有效。容器销毁后,在主机和镜像内不会有其相关的数据残留。Writable的部分只限制于当前容器内:
Docker数据持久化管理 - 图2
图片来自dockerinfo.net,图片版权归属原作者
这个技术适合作为容器系统的系统卷使用。

数据卷

是不是摆放数据的持久化卷也是通过类似方式准备起来的呢? 答案是 ✖
数据卷有两类常见的使用方法:Bind Mount和Volume(tmpfs mount很少使用)。
Docker数据持久化管理 - 图3
图片来自docker.com,图片版权归属原作者

  1. Bind Mounts:我把这种模式称为狩猎模式。当你手提猎枪站在森林里狩猎的时候,最大的感觉就是畅快,可谓指哪打哪。在Bind Mount模式也一样,你想把主机中什么文件或者目录mount到容器的什么位置都可以。
    Docker数据持久化管理 - 图4
    还是以之前的redis为例,我们对这个缓存模块进行增强,提供数据持久化功能: ```shell [root@training1 ~]# pwd /root [root@training1 ~]# ls apache Dockerfile emacs get-docker.sh

[root@training1 ~]# docker run -v $PWD/data:/data -d redis:3.2 redis-server aa964b1b61fd2a8c503bb3cd63ee87235f85bead022b504f48f20eff575e5b05 [root@training1 ~]# ls apache data Dockerfile emacs get-docker.sh

[root@training1 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES aa964b1b61fd redis:3.2 “docker-entrypoint.s…” About a minute ago Up About a minute 6379/tcp tender_franklin [root@training1 ~]# docker exec -it aa964b1b61fd /bin/bash

root@aa964b1b61fd:/data# touch update root@aa964b1b61fd:/data# exit exit

[root@training1 ~]# ls data/ update

  1. 从上面的演示可以看出,Bind Mount模式的关键命令在于-v <host_path>:<ontainer_path>这几个字符。通过指定当前目录下的data子目录为加载的源头,容器内的/datamount点,进行目录的加载。之后在容器内的数据操作会保留到主机的相关文件和目录中,持久化存储下来。
  2. 1. **Volumes**: 我把这种模式称为靶场模式。当一个新兵开始训练的时候,通常狩猎场都不是最好的选择;相对的,靶场的封闭的场馆和方便的弹药更换环境,才更受欢迎。在Volumes模式中,用户可以创建卷名,并把它加载到指定的容器,但是在主机平台,这些卷确被统一存放在为Docker指定的靶场环境/var/lib/docker/volume中。<br />![](https://cdn.nlark.com/yuque/0/2022/jpeg/1602593/1652700194025-07f2b797-abf6-4862-acae-2280988bb442.jpeg#clientId=u5de4b1e6-b2c8-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u28e618c1&margin=%5Bobject%20Object%5D&originHeight=868&originWidth=1096&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u4b841731-61d8-4d18-aab9-db3f6503058&title=)<br />两种主流volume创建方式:
  3. - 隐式创建卷:docker run .... -v /data
  4. - 显式创建卷 docker volume create --name **<br />我们先来隐式地创建Redis缓存所需的持久化卷吧:
  5. ```shell
  6. [root@training1 volumes]# docker run -v /data2 -d redis:3.2 redis-server
  7. 8fb55dcc8a5e6b0294044a99190c89e829f152782f7eb10b45f2331223f27509
  8. [root@training1 volumes]# docker inspect 8fb55dcc8a5e6b0294044a99190c89e829f152782f7eb10b45f2331223f27509
  9. ...
  10. "Mounts": [
  11. {
  12. "Type": "volume",
  13. "Name": "f0815cce95ff0ec913f8c0a72fd04a0da72be0cccf685d9b1ecd57c14965c35a",
  14. "Source": "/var/lib/docker/volumes/f0815cce95ff0ec913f8c0a72fd04a0da72be0cccf685d9b1ecd57c14965c35a/_data",
  15. "Destination": "/data",
  16. "Driver": "local",
  17. "Mode": "",
  18. "RW": true,
  19. "Propagation": ""
  20. }
  21. ],
  22. ...
  23. [root@training1 volumes]# ls /var/lib/docker/volumes/f0815cce95ff0ec913f8c0a72fd04a0da72be0cccf685d9b1ecd57c14965c35a
  24. _data

大家可以看到,Volumes模式和Bind Mounts模式最大的区别就是-v后面没有:符号,这也就意味着我们只制定了容器内的目标mount点,而所需要从host上加载的卷,由系统在/var/lib/docker/volumes目录下随机指定,并mount到容器的/data2目录。
现在我们再来显式地创建Volume,并加载到容器内:

  1. [root@training1 ~]# docker volume create data3
  2. data3
  3. [root@training1 ~]# docker inspect data3
  4. [
  5. {
  6. "CreatedAt": "2019-08-21T00:16:47+08:00",
  7. "Driver": "local",
  8. "Labels": {},
  9. "Mountpoint": "/var/lib/docker/volumes/data3/_data",
  10. "Name": "data3",
  11. "Options": {},
  12. "Scope": "local"
  13. }
  14. ]
  15. [root@training1 ~]# ls -d /var/lib/docker/volumes/data3
  16. /var/lib/docker/volumes/data3
  17. [root@training1 ~]# docker run -v data3:/data3 -d redis:3.2 redis-server
  18. 833da638bfdc220e7f9d9e49821ac247d6abdc6b3868a9be51803097d8de649f
  19. [root@training1 ~]# docker exec -it 833da638bfdc220e7f9d9e49821ac247d6abdc6b3868a9be51803097d8de649f /bin/bash
  20. root@833da638bfdc:/data# ls -ld /data3
  21. drwxr-xr-x 2 root root 4096 Aug 20 16:16 /data3

显式地创建volume会使得其在主机上的卷名比较容易记忆,但整个加载效果其实和隐式创建类似。Volume会确保保存在/var/lib/docker/volumes目录下。

区别比较

区别点 Bind Mounts Volumes
安全性 野外乱射,容易走火伤人,容易影响主机系统非容器目录 靶场射击,安全可控,只影响docker环境/var/lib/docker/volumes
灵活性 方便指定特定文件或目录 只能对应特定目录下的子目录,不支持文件
权限控制 可设置只读权限 读写权限
跨主机共享磁盘 需要各个主机上目录结构相似,移植不方便 无特定主机目录要求,移植性强
适用人群 高手特定场景下狩猎使用 小白靶场练手起步

小结

在本节课程中,我们学习了Docker数据持久化的技术 - Bind Mounts 和 Volumes,并对使用场景做了分析比较。接下来,我们将带着大家进入整个Docker章节的最难点–网络部分,看看容器和主机是如何互相通信的。