docker 数据卷和网络

概述

本文介绍 Docker 中与数据持久化相关的 volume 和与通信相关的 network

volume (数据卷)

默认情况下,容器一旦被移除,其中包含的数据也会自动消失。为避免这种情况,需要用到数据持久化技术。

Docker 提供宿主机与容器之间共享文件,从而将数据持久化于宿主机。其具体分为两种方式 —— volumesbind mounts。另外,对于 Linux 而言,Docker 提供 tmpfs mount ,它将数据直接保存于宿主机内存之中,而非容器之中。

volumes

volumes 由 Docker 创建并管理,且其中数据仅能由 Docker 进程操纵,其位于由 Docker 所管理的宿主机文件系统部分 (对于 Linux 而言,具体位于 /var/lib/docker/volumes/)。

Docker 提供 docker volume 命令管理 volumes,该命令的详细信息具体如下:

1
2
3
4
5
6
7
8
9
10
Usage:  docker volume COMMAND

Manage volumes

Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes

为持久化容器数据,我们可在启动容器时使用 -v--mount 参数将特定 volumes 挂载于容器的特定目录。举例如下:

1
2
3
// 挂载volumeName数据卷至centos的/var/lib目录,且指定数据卷为只读模式。
docker run -v volumeName:/var/lib:ro centos
docker run --mount 'type=volume,src=volumeName,dst=/var/lib,readonly'

-v--mount 的区别在于:前者混杂多种使用情况,后者使用键值对形式将这些情况区分开来。建议使用 --mount 挂载数据卷。

有关 volumns 的使用,作如下几点说明:

  1. volumes 具体细分为 Named volumesAnonymous volumes,前者由用户分配数据卷名称,后者由 Docker 分配数据卷名称。命令 docker run -v volumeName:/var/lib:ro centos 使用的是 Named volumes,命令 docker run -v /var/lib:ro centos 使用的是 Anonymous volumes
  2. 如果容器目录不存在,则自动创建;如果数据卷不存在,则自动创建。
  3. 如果将空数据卷挂载至容器非空目录,则容器目录内容会首先被自动复制至数据卷,然后该容器挂载并使用数据卷。
  4. 启动容器时,可使用 --volumes-from 参数以挂载特定容器中的数据卷,从而实现两容器数据卷内容共享。

bind mounts

bind mounts 由用户创建并管理,其中数据可为任何进程操纵,其所在位置由用户自主决定。

为持久化容器数据,我们可在启动容器时使用 -v--mount 参数将宿主机指定目录与容器特定目录绑定挂载。举例如下:

1
2
3
// 绑定挂载宿主机/usr/lib目录与centos的/var/lib目录,且指定为只读模式。
docker run -v /usr/lib:/var/lib:ro centos
docker run --mount 'type=bind,src=/usr/lib,dst=/var/lib,readonly'

有关 bind mounts 的使用,作如下几点说明:

  1. 如果容器目录或文件不存在,则自动创建;如果宿主机目录或文件不存在,此时分为两种情况:若使用 -v 参数,则总是创建相应的目录,若使用 --mount 参数,则不会创建相应目录或文件,并提示报错。
  2. 对于 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 无法挂载于多个容器,而 volumesbind mounts 可以。

为使用 tmpfs mounts,我们可在启动容器时使用 --tmpfs--mount 参数挂载容器特定目录至宿主机内存。举例如下:

1
2
3
// 挂载centos的/var/lib目录至宿主机内存
docker run --tmpfs /var/lib centos
docker run --mount 'type=tmpfs,dst=/var/lib' centos

--tmpfs--mount 的区别在于:前者不允许配置 tmpfs 相关选项 (具体指代 tmpfs-sizetmpfs-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 的区别:

    1. 前者提供容器之间的 DNS 解析,而后者不提供。在默认 bridge network 之中,容器间通信只能基于 IP 地址 (一种取巧方式是使用 --link,随后使用容器名通信。其实际是在容器的 hosts 文件下添加一条 IP 地址与容器名的映射,因此其本质仍是基于 IP 地址进行通信)。而在自定义 bridge network 之中,容器间可基于 IP 地址、容器名、网络别名实施通信。
    2. 前者可以提供更好的隔离性能。未使用 --network 指定网络的容器均归于默认 bridge network,这使得其中包含各种应用,鱼龙混杂,无法提供较好的隔离。
    3. 对于前者而言,容器可随时连接或断开连接;对于后者而言,如果希望断开连接,需要停止容器并以合适的网络选项重新启动它。
    4. 对于后者而言,基于 --link 参数启动的容器与 link 对象容器共享相同的环境变量。
  • 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

这里涉及太多的网络知识,不懂。