docker 数据卷和网络
概述
本文介绍 Docker 中与数据持久化相关的 volume
和与通信相关的 network
。
volume (数据卷)
默认情况下,容器一旦被移除,其中包含的数据也会自动消失。为避免这种情况,需要用到数据持久化技术。
Docker 提供宿主机与容器之间共享文件,从而将数据持久化于宿主机。其具体分为两种方式 —— volumes
和 bind mounts
。另外,对于 Linux 而言,Docker 提供 tmpfs mount
,它将数据直接保存于宿主机内存之中,而非容器之中。
volumes
volumes
由 Docker 创建并管理,且其中数据仅能由 Docker 进程操纵,其位于由 Docker 所管理的宿主机文件系统部分 (对于 Linux 而言,具体位于 /var/lib/docker/volumes/
)。
Docker 提供 docker volume
命令管理 volumes
,该命令的详细信息具体如下:
1 | Usage: docker volume COMMAND |
为持久化容器数据,我们可在启动容器时使用 -v
或 --mount
参数将特定 volumes
挂载于容器的特定目录。举例如下:
1 | // 挂载volumeName数据卷至centos的/var/lib目录,且指定数据卷为只读模式。 |
-v
与--mount
的区别在于:前者混杂多种使用情况,后者使用键值对形式将这些情况区分开来。建议使用--mount
挂载数据卷。
有关 volumns
的使用,作如下几点说明:
volumes
具体细分为Named volumes
和Anonymous volumes
,前者由用户分配数据卷名称,后者由 Docker 分配数据卷名称。命令docker run -v volumeName:/var/lib:ro centos
使用的是Named volumes
,命令docker run -v /var/lib:ro centos
使用的是Anonymous volumes
。- 如果容器目录不存在,则自动创建;如果数据卷不存在,则自动创建。
- 如果将空数据卷挂载至容器非空目录,则容器目录内容会首先被自动复制至数据卷,然后该容器挂载并使用数据卷。
- 启动容器时,可使用
--volumes-from
参数以挂载特定容器中的数据卷,从而实现两容器数据卷内容共享。
bind mounts
bind mounts
由用户创建并管理,其中数据可为任何进程操纵,其所在位置由用户自主决定。
为持久化容器数据,我们可在启动容器时使用 -v
或 --mount
参数将宿主机指定目录与容器特定目录绑定挂载。举例如下:
1 | // 绑定挂载宿主机/usr/lib目录与centos的/var/lib目录,且指定为只读模式。 |
有关 bind mounts
的使用,作如下几点说明:
- 如果容器目录或文件不存在,则自动创建;如果宿主机目录或文件不存在,此时分为两种情况:若使用
-v
参数,则总是创建相应的目录,若使用--mount
参数,则不会创建相应目录或文件,并提示报错。 - 对于
bind mounts
而言,其不存在 “容器目录内容自动复制至数据卷” 的类似情况,而是容器直接挂载并使用宿主机目录或文件。
有关绑定传播 (bind propagation) 的知识官方文档讲的很模糊,自己没有看懂。另外,官网文档中言及 “Bind propagation is an advanced topic and many users never need to configure it.”,所以可以省略这部分内容。
tmpfs mounts
如果容器运行所产生的数据为无关数据,处理此数据的一种绝佳方法是使用 tmpfs mounts
,如此操作后,这些数据便位于宿主机内存之中,从而减小容器大小。当容器停止运行后,这些数据会自动消失。
tmpfs mounts
仅限于 Linux 使用。
tmpfs mounts
无法挂载于多个容器,而volumes
和bind mounts
可以。
为使用 tmpfs mounts
,我们可在启动容器时使用 --tmpfs
或 --mount
参数挂载容器特定目录至宿主机内存。举例如下:
1 | // 挂载centos的/var/lib目录至宿主机内存 |
--tmpfs
与--mount
的区别在于:前者不允许配置tmpfs
相关选项 (具体指代tmpfs-size
和tmpfs-mode
),且不能被用于swarm service
。
network (网络)
容器间相互通信,依赖于 Docker 强大的网络功能。
Docker 网络架构由三部分组成:Container Network Model (CNM)、Libnetwork、驱动程序,其中 CNM 为网络设计标准,它规定了 Docker 网络架构的基本组成要素;Libnetwork 为 CNM 的具体实现;驱动程序提供不同的网络拓扑实现。
CNM
CNM 规定了三个基本组成要素:沙盒 (Sandbox)、终端 (Endpoint)、网络 (Network),其中沙盒是一个独立的网络栈,包括以太网接口、端口、路由表、DNS配置等内容;终端指代虚拟网络接口,负责将沙盒连接至网络;网络为 802.1d 网桥的软件实现。三者连接关系如图所示:
驱动程序
Docker 内置若干驱动程序,包括 bridge、overlay、host、macvlan、none,我们在此一一介绍。
bridge
bridge network 仅适用于单机 (single docker daemon host) 使用,借助于链路层软件设备——网桥,实现在所负责网段之内转发流量。
Docker 内置一个默认 bridge network。容器启动时,如果未使用
--network
参数指定网络,则其存在于默认 bridge network。当然,用户也可自定义 bridge network。自定义 bridge network 与默认 bridge network 的区别:
- 前者提供容器之间的 DNS 解析,而后者不提供。在默认 bridge network 之中,容器间通信只能基于 IP 地址 (一种取巧方式是使用
--link
,随后使用容器名通信。其实际是在容器的 hosts 文件下添加一条 IP 地址与容器名的映射,因此其本质仍是基于 IP 地址进行通信)。而在自定义 bridge network 之中,容器间可基于 IP 地址、容器名、网络别名实施通信。 - 前者可以提供更好的隔离性能。未使用
--network
指定网络的容器均归于默认 bridge network,这使得其中包含各种应用,鱼龙混杂,无法提供较好的隔离。 - 对于前者而言,容器可随时连接或断开连接;对于后者而言,如果希望断开连接,需要停止容器并以合适的网络选项重新启动它。
- 对于后者而言,基于
--link
参数启动的容器与 link 对象容器共享相同的环境变量。
- 前者提供容器之间的 DNS 解析,而后者不提供。在默认 bridge network 之中,容器间通信只能基于 IP 地址 (一种取巧方式是使用
overlay
overlay network 适用于多机 (multiple docker daemon host) 间构建分布式网络,借助于 VXLAN 隧道技术,实现分布式网络内转发流量。
当初始化 swarm 或添加 Docker host 至现有 swarm 时,两个网络被自动创建:ingress,一个默认 overlay network;docker_gwbridge,一个桥接网络,允许容器访问外网。
host
如果某个容器使用 host network,则其与宿主机共享相同的网络栈 (例如,IP 地址、端口)。
macvlan
….
none
如果不希望容器使用网络功能,则可指定
--network
参数为none
。
这里涉及太多的网络知识,不懂。