三种可以挂载在容器的存储类型:绑定挂载、常驻内存存储、Docker 卷 。
这三种方式均通过 docker run
或 docker create
的 --mount
选项来设置。
绑定挂载
绑定挂载可以将主机文件系统上的文件挂载到容器文件树中的特定位置。比如下面这个例子中,在容器上挂载了 NGINX 的配置文件以及日志文件:
# NGINX 配置文件位置 & 容器中挂载位置
CONF_SRC=~/example.conf
CONF_DST=/etc/nginx/conf.d/default.conf
# 日志文件位置 & 容器中挂载位置
LOG_SRC=~/example.log
LOG_DST=/var/log/nginx/custom.host.access.log
docker run -d --name diaweb \
--mount type:bind,src=${CONF_SRC},dst=${CONF_DST},readonly=true \
--mount type:bind,src=${LOG_SRC},dst=${LOG_DST} \
-p 80:80 \
nginx:latest
type:bind
表示使用绑定挂载;src
和dst
定义了主机文件系统的源位置和容器文件树上要挂载的位置,必须用绝对路径来表示;readonly=true
表示只读,防止文件被修改;- 如果要挂载的文件位置已有文件,则会覆盖已有文件。
绑定挂载在一些场景下会存在问题:
- 如果容器描述依赖主机中的特定文件,那么该容器描述无法应用到别的主机上;
- 如果多个容器挂载了相同的主机路径(比如数据库实例),可能会因为操作相同文件而产生竞争。
所以绑定挂载模式最好避免用在通用平台或硬件池中。
常驻内存存储
大多数软件服务中,敏感数据或者缓存数据应当放在内存中存储。可以通过 type=tmpfs
来将内存的文件系统挂载到容器文件树中:
docker run --rm \
--mount type=tmpfs,dst=/tmp \
--entrypoint mount \
alpine:latest -v
该命令会创建一个新的 tmpfs 设备,并挂载到容器的 /tmp
位置。执行完命令后会打印所有挂载点的列表,其中会包含该内存挂载的(默认配置)信息:
# 括号内信息表示:可读可写、忽略 suid 位、无设备、无可执行文件、以 relatime 模式更新文件访问时间
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,noexec,relatime)
tmpfs 设备默认情况下没有大小限制,且可写(八进制文件权限为 1777)。可以通过 tmpfs-size
和 tmpfs-mode
进行更改:
# 限定 tmpfs 大小为 16KB ,且容器内其他用户无法读取
docker run --rm \
--mount type=tmpfs,dst=/tmp,tmpfs-size=16k,tmpfs-mode=1770 \
--entrypoint mount \
apline:latest -v
Docker 卷
Docker 卷是由 Docker 管理的文件系统树,它们可以通过主机的磁盘存储或外部的后端系统(比如云存储)来实现。Docker 卷可以解耦容器存储与主机文件系统之间的关联。
默认情况下,Docker 使用 local
驱动来创建卷。Docker 会将主机文件系统中的一部分映射为 Docker 卷,而卷的内容就保存在该目录下。Docker 卷的大多数操作由 docker volume
完成。比如下面例子中将创建一个名为 location-example 的卷,并显示该卷在主机文件系统下的位置:
docker volume create --driver local location-example
docker volume inspect --format "{{json .Mountpoint}}" location-example
除了
local
,当前还有很多驱动来应用不同存储方案,比如专有云块存储、网络文件系统挂载、专有存储硬件等。
容器可用 --volume
使用 Docker 卷:
# 创建一个用于存储数据库文件的卷
docker volume create cass-shared
# 运行一个 Cassandra 数据库服务
docker run -d \
--volume cass-shared:/var/lib/cassandra/data \
--name cass
cassandra:2.2
或者用 --mount
指定 type=volume
来使用:
docker volume create logging-example
docker run --name plath -d \
--mount type=volume,src=logging-example,dst=/data \
dockerinaction/ch4_writer_a
docker run --rm
--mount type=volume,src=logging-example,dst=/data \
alpine:latest \
head /data/logA
多个容器之间可以使用同一 Docker 卷。与绑定挂载不同,在执行 docker run
或 docker create
之前可以不用手动创建 Docker 卷,它会根据给定的名称自动创建卷。
也可以通过不指定 src
的方式来创建一个匿名卷,但与此同时如果有别的容器想使用该匿名卷,则可以用 --volumes-from
选项从别的容器中复制其所有的挂载点:
docker run --name fowler \
--mount type=volume,dst=/library/PoEAA \
--mount type=bind,src=/tmp,dst=/library/DSL \
alpine:latest \
echo "Fowler collection created."
# PoEAA 和 DSL 均会复制到 reader 中
docker run --name reader \
--volumes-from fowler \
alpine:latest ls -l /library/
可以多次调用 --volumes-from
来从多个容器中复制挂载点。如果同一挂载点有多个源,则只会有一个生效。
清理卷
可以用 docker volume remove
删除多个卷。可通过 docker volume list
查看当前所有卷。
对于匿名卷,若容器被自动清理,匿名卷也会被自动删除。
如果尝试删除正在使用的卷,Docker 会发出警告:卷正在使用。可以用 docker volume prune
来删除当前所有具备删除条件的卷。