0x00 概述

接触 docker 的朋友都知道,docker 镜像是以 layer 概念存在的,一层一层的叠加,最终成为我们需要的镜像。但该镜像的每一层都是 ReadOnly 只读的。只有在我们运行容器的时候才会创建读写层。文件系统的隔离使得:

  • 容器不再运行时,数据将不会持续存在,数据很难从容器中取出。
  • 无法在不同主机之间很好的进行数据迁移。
  • 数据写入容器的读写层需要内核提供联合文件系统,这会额外的降低性能。

docker 为我们提供了三种不同的方式将数据挂载到容器中:volume、bind mount、tmpfs

0x01 volume 方式

volume 方式是 docker 中数据持久化的最佳方式。

  • docker 默认在主机上会有一个特定的区域(/var/lib/docker/volumes/ Linux),该区域用来存放 volume。
  • 非 docker 进程不应该去修改该区域。
  • volume 可以通过 docker volume 进行管理,如创建、删除等操作。
  • volume 在生成的时候如果不指定名称,便会随机生成。
$ ls /var/lib/docker/volumes
ff664768bfe64e1a8cae4369dd4a2e1929362e29580735480290684e38c8f140
ffa4846b581c1a50a01e7a12a6342ad2aaa442701a35ae56ef2f0e5d7888b22c
  • volume 在容器停止或删除的时候会继续存在,如需删除需要显示声明。
$ docker rm -v <container_id>
$ docker volume rm <volume_name>

相关用例

volume 方式应该是持久化数据的首选方式, 其推荐用例:

  • 在多个容器之间共享数据,volume 在容器停止或删除的时候依然存在,如果需要删除需要显示(dockr rm -v…),多个容器可以加载相同的卷。
  • 当主机不能保证有一个指定的目录或文件结构时。
  • 当需要备份、还原或主机间的数据迁移时。停止容器,备份卷的目录(如/var/lib/docker/volumes/<volume-name>

使用方式

volume 在 docker 中被推荐为首选方式,它与 bind mount 相比,有以下优点:

  • 与 bind mount 相比,volume 更容易备份或迁移。
  • 可以使用 Docker CLI 命令或 Docker API 来管理。
  • volume 在 Linux 和 Windows 容器上都能工作。
  • volume 可以在多个容器之间更安全的共享。
  • volume 驱动程序允许你在远程主机或云上提供存储、加密或其他功能。
  • 新 volume 的内容可以由容器预填充。

-v/-mount 标志
最初,-v-volume 用于独立的容器,--mount 用于 swarm server。但 docker 17.06 之后,也可以使用 --mount。两者的区别在于,-v 将所有选项组合在一个字段中,--mount 则将它们分开。

新用户应使用 --mount 语法,老用户推荐使用 --mount

  • -v/--volume,由(:)分隔的三个字段组成,<卷名>:<容器路径>:<选项列表>。选项列表,如:ro只读。
  • --mount,由多个键值对组成,由,分隔,每个由一个<key=<value>>元组组成。
    • type,值可以为 bindvolumetmpfs
    • source,对于命名卷,是卷名。对于匿名卷,这个字段被省略。可能被指定为 sourcesrc
    • destination,文件或目录将被挂载到容器中的路径。可以指定为 destinationdsttarget
    • volume-opt 可以多次指定。

创建管理 volume

# 创建一个卷
$ docker volume create my-vol # 卷列表
$ docker volume ls local my-vol # 卷信息
$ docker volume inspect my-vol
[
{
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
"Name": "my-vol",
"Options": {},
"Scope": "local"
}
] # 删除卷
$ docker volume rm my-vol

用卷启动容器
下例,将卷 myvol2 挂载到容器 /app/-v--mount 产生的效果相同,但下面命令不能同时执行,会冲突:

# --mount
# 使用 --mount source=myvol2,target/app,readonly 创建只读的
$ docker run -d \
-it \
--name devtest \
--mount source=myvol2,target=/app \
nginx:latest # -v
# 使用 -v myvol2:/app:ro 创建只读的
$ docker run -d \
-it \
--name devtest \
-v myvol2:/app \
nginx:latest

你可以执行 docker inspect devtest 验证卷是否创建并且挂载正确:

"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],

该卷有正确的 Source 和 Destination,可读写。

停止容器和清理卷:

$ docker container stop devtest

$ docker container rm devtest

$ docker volume rm myvol2

当启动 service 的时候,如果 Driverlocal 的时候,则任何容器都不能共享此数据。另外 service 只能使用 --mount 标志。

使用 volume driver

当使用 docker volume create 创建卷或启动尚未创建卷的容器的时候,可以指定卷驱动程序。

下面这个例子,首先创建独立卷时使用 volume driver,然后在启动创建新卷的容器时使用 volume driver。

初始设置
这个例子假定你有 2 个节点,第一个是 docker 主机,可以使用 SSH 连接到第二个节点。

在 docker 主机上安装 vieux/sshfx 插件:

$ docker plugin install --grant-all-permissions vieux/sshfs

使用 volume driver 创建卷
下面指定了一个 SSH 密码,但如果 2 台主机共享密钥已配置,则可以省略密码。每个 volume driver 可以有多个配置选项,使用 -o 标志指定。

$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume

创建容器时使用 volume driver
这里需要注意的是,如果需要在命令中使用选项,则必须使用 --mount,而不是 -v

$ docker run -d \
-it \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
nginx:latest

0x02 bind mount 方式

通过 bind mount 方式,你可以将你主机上的任何文件或目录(绝对路径)挂载到容器中。

  • 挂载的文件或目录可以被任何进程修改,因此有时候容器中修改了该文件或目录将会影响其他进程。
  • 如果挂载主机的文件或目录不存在将会自动创建。
  • 使用该方式不能通过 docker volume 管理,推荐使用 volume 方式。

相关用例

bind mounts,一般情况在如下方式使用:

  • 从主机共享配置文件到容器。默认情况,docker 会绑定类似 /etc/resolv.conf 的文件用于 DNS 的解析。
  • 主机与容器共享源代码或构建工具。如,你可以将 Maven target/ 挂载到容器中,并且每次主机上构建 Maven 项目时,容器都可以访问重建的构件。
  • 主机的文件或目录结构与容器所需的一致时。

如果将空文件或目录挂载到容器,容器中的该目录又有文件,那么,这些文件将会被复制到主机上的目录中。如果将非空的文件或目录挂载到容器,容器中的该目录也有文件,那么,容器中的文件将会被隐藏。

使用方式

-v/-mount 标志
最初,-v-volume 用于独立的容器,--mount 用于 swarm server。但 docker 17.06 之后,也可以使用 --mount。两者的区别在于,-v 将所有选项组合在一个字段中,--mount 则将它们分开。

新用户应使用 --mount 语法,老用户推荐使用 --mount

  • -v--volume:由(:)分隔的字段组成。这些字段是有顺序的。

    • 第一个字段,主机上的文件或目录。
    • 第二个字段,容器中的文件或目录。
    • 第三个字段,可选,且用逗号分隔,如:roconsistentdelegatedcachedzZ
  • --mount:由多个键值对组成,由逗号分隔,每一个由 <key>=<value> 元祖组成。键值对没有顺序。
    • type,可以是 bindvolumetmpfs
    • source,主机上的文件或目录的路径。可能用 srcsource 指定。
    • destination,容器中的文件或目录的路径。可能用 destinationdsttarget 指定。
    • readonly,如果存在,将更改 Propagation,可以是一个 rprivate
    • consistency,如果存在,可以是 consistentdelegatedcached,只在 Mac 版有效。
    • --mount 标志不支持 zZ 修改 selinux。

-v 和 –mount 的差异
使用 -v--volume 绑定主机不存在的文件或目录,将会自动创建。始终创建的是一个目录。

使用 --mount 绑定主机上不存在的文件或目录,则不会自动创建,会产生一个错误。

使用 bind mount 启动容器
主机上的目录 source/target,容器的目录 /app/$(pwd) 将使用当前目录:

# 只读方式:--mount type=bind,source="$(pwd)"/target,target=/app,readonly
$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
nginx:latest # 只读方式:-v "$(pwd)"/target:/app:ro
$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app \
nginx:latest

docker inspect devtest 可以查看相关信息,查看 Mounts 部分:

"Mounts": [
{
"Type": "bind",
"Source": "/tmp/source/target",
"Destination": "/app",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],

这些信息表明了这是一个 bind 挂载,源路径和目的路径,并且是可读写的,且 Propagation 设置为 rprivate

停止容器:

$ docker container stop devtest

$ docker container rm devtest

配置 Propagation
Propagation 的在 bind mount 和 volume 中默认为 rprivate。它只能在 bind mount 配置,并且只能在 Linux 主机上配置。这是一个高级选项,许多用户不需要配置它。

Propagation 是指在给定的挂载卷或命名卷中创建的挂载是否可以传播到该挂载的副本。考虑一个挂载点 /mnt,它被挂载在 /tmp。传播设置控制是否挂载 /tmp/a 也可用 /mnt/a.每个 Propagation 设置都有一个递归对应点。在递归的情况下,考虑 /tml/a 被挂载为 /foo。传播设置控制是否 /mnt/a/tmp/a 将存在。

Propagation 设置 描述
shared 原始安装的子安装会暴露给副本安装,并且副本安装的子安装也会传播到原始安装。
slave 类似于共享的安装,但仅在一个方向上。如果原始安装显示一个子安装,副本安装可以看到它。但是,如果副本安装公开了子安装,则原始安装无法看到它。
private 这座山是私人的。其中的子安装不会暴露给副本安装,并且副安装的子安装不会暴露给原始安装。
rshared 与共享相同,但是传播也扩展到嵌套在任何原始或副本安装点内的挂载点。
rslave 与从属设备相同,但传播也延伸到嵌套在任何原始或副本安装点内的挂载点。
rprivate 默认。与私有相同,这意味着在原始或副本安装点内的任何位置都不会有安装点向任一方向传播。

在可以在安装点上设置绑定传播之前,主机文件系统需要已经支持绑定传播。有关绑定传播的更多信息,请参阅 共享子树Linux内核文档

以下示例将 target/ 目录装载到容器中两次,第二个装入设置 ro 选项和 rslave 绑定传播选项。

--mount-v 实例有同样的结果。

$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,target=/app \
--mount type=bind,source="$(pwd)"/target,target=/app2,readonly,bind-propagation=rslave \
nginx:latest $ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app \
-v "$(pwd)"/target:/app2:ro,rslave \
nginx:latest

现在如果你创建 /app/foo//app2/foo/ 也将存在。

配置selinux标签

如果使用的 selinux 话,可以添加 z 或者 Z 选项来修改正在装入容器的主机文件或目录selinux 标签。这会影响主机本身的文件或目录,并可能导致Docker范围之外的后果。

  • z 选项指示绑定安装内容在多个容器之间共享。
  • Z 选项指示绑定安装内容是私有的和非共享的。

使用极端谨慎使用这些选项。绑定一个系统目录,例如 /home或者 /usr 用这个 Z 选项,将会使你的主机无法工作,你可能需要手工重新标记主机文件。

重要:在使用绑定安装服务时,selinux标签(:Z:z)以及 :ro 被忽略。有关详细信息,请参阅 moby/moby#32579

这个例子设置 z 选项来指定多个容器可以共享绑定挂载的内容:

使用 --mount 标志来修改selinux标签是不可能的。

$ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:z \
nginx:latest

配置macOS的安装一致性

Docker for Mac用于 osxfs 将从 macOS 共享的目录和文件传播到 Linux VM。这种传播使这些目录和文件可用于在 Docker for Mac 上运行的 Docker 容器。

默认情况下,这些共享是完全一致的,这意味着每次在 macOS 主机上发生写入或通过容器中的挂载时,都会将更改刷新到磁盘,以便共享中的所有参与者都具有完全一致的视图。在某些情况下,完全一致可能会严重影响性能。Docker 17.05 和更高版本引入了选项来调整一个一个,每个容器的一致性设置。以下选项可用:

  • consistent 或者 default:完全一致的默认设置,如上所述。
  • delegated:容器运行时的挂载视图是权威的。在容器中进行的更新可能在主机上可见之前可能会有延迟。
  • cached:macOS主机的挂载视图是权威的。在主机上进行的更新在容器中可见之前可能会有延迟。

这些选项在除 macOS 以外的所有主机操作系统上完全忽略。

在–mount和-v实例有同样的结果。

$ docker run -d \
-it \
--name devtest \
--mount type=bind,source="$(pwd)"/target,destination=/app,consistency=cached \
nginx:latest $ docker run -d \
-it \
--name devtest \
-v "$(pwd)"/target:/app:cached \
nginx:latest

0x03 tmpfs 方式

tmpfs,仅存储在主机系统的内存中,不会写入主机的文件系统。

相关用例

tmpfs,使用它的情况一般是,对安全比较重视以及不需要持久化数据。

使用方式

--tmpfs--mount 的关系与前面两种方式的关系不用多说。那它们之间的差异是:

  • --tmpfs 不允许指定任何可配置选项。
  • --tmpfs 不能用语 swarm service,你必须使用 --mount

tmpfs 容器的限制

  • tmpfs 挂载不能在容器间共享。
  • tmpfs 职能在 Linux 容器上工作,不能在 windows 容器上工作。

容器中使用 tmpfs

$ docker run -d \
-it \
--name tmptest \
--mount type=tmpfs,destination=/app \
nginx:latest $ docker run -d \
-it \
--name tmptest \
--tmpfs /app \
nginx:latest

tmpfs 通过运行 docker container inspect tmptest 并查找 Mounts 部分来验证安装是挂载:

"Tmpfs": {
"/app": ""
},

删除容器:

$ docker container stop tmptest

$ Docker container rm tmptest

指定 tmpfs 选项
tmpfs 挂载允许两个配置选项,这两个都是不需要的。如果您需要指定这些选项,则必须使用该 --mount 标志,因为该 --tmpfs 标志不支持它们。

选项 描述
tmpfs-size tmpfs 的大小,以字节为单位。无限制默认。
tmpfs-mode tmpfs 的八进制文件模式。例如,700 或者 0770。默认为 1777 或世界可写。

以下示例将设置 tmpfs-mode1770,以便在容器内不可世界读取。

docker run -d \
-it \
--name tmptest \
--mount type=tmpfs,destination=/app,tmpfs-mode=1770 \
nginx:latest

本文链接:https://deepzz.com/post/the-docker-volumes-basic.html

Docker学习笔记之docker volume 容器卷的那些事(一)的更多相关文章

  1. Docker学习笔记之docker volume 容器卷的那些事(二)

    预览目录 更改目录拥有者 Data Container 切换用户 参考文章 0x00 概述 如果你读了docker volume 容器卷的那些事(一),我想应该不会遇到下面这些问题的,毕竟是具有指导意 ...

  2. Docker学习笔记:镜像、容器、数据卷

    核心概念 镜像:一个只读的模板,类似虚拟机的镜像. 容器:可以理解为镜像的一个运行实例.运行时类似于沙箱,多个容器互相独立. 仓库:存放镜像文件的地方. 镜像 命令表格 命令 解释 选项 docker ...

  3. Docker学习笔记之镜像与容器

    0x00 概述 镜像和容器作为 Docker 里最基础的概念,我们很有必要了解 Docker 对它们的很多定义以及其他与它们有关的知识.在这一小节里,我们就专门针对镜像与容器两个概念展开,细致的梳理与 ...

  4. Docker学习笔记2: Docker 概述

    一.什么是Docker Docker是基于Go语言实现的云开源项目. Docker 的主要目标是:"Bulid,Ship and  Run Any App ,AnyWhere" , ...

  5. Docker学习笔记之Docker的数据管理和存储

    0x00 概述 数据是应用程序重要的产出,所以很好的管理和存储数据,是对应用程序劳动结果的尊重.特别是在大数据时代,所有的数据都是重要的资产,保护好数据是每个开发者必须掌握的技能.我们知道,在 Doc ...

  6. Docker学习笔记_10 docker应用 - 部署TOMCAT服务

    选择基镜像 基镜像使用dokcer hub官方提供的tomcat8 alpine当前最新版本,https://hub.docker.com/_/tomcat/ docker pull tomcat:8 ...

  7. Docker学习笔记(2)-docker镜像操作

    本节将会涉及Docker的镜像操作. 1. 获取镜像 如何获取Docker Hub上的镜像?可通过docker pull命令获取,其格式为: docker pull [选项] [Docker Regi ...

  8. DOCKER 学习笔记8 Docker Swarm 集群搭建

    前言 在前面的文章中,已经介绍如何在本地通过Docker Machine 创建虚拟Docker 主机,以及也可以在本地Windows 创建虚拟主机,也是可以使用的.这一节,我们将继续学习 Docker ...

  9. Docker学习笔记(1) — docker 常用命令

    1. docker version显示 Docker 版本信息.2. docker info显示 Docker 系统信息,包括镜像和容器数.3. docker searchdocker search ...

随机推荐

  1. Jmeter知识点

    聚合报告说明 https://www.cnblogs.com/duanxz/p/5464993.html JMeter之Ramp-up Period(in seconds)说明(可同时并发) http ...

  2. cloud-api-service和cloud-iopm-web提交merge方法

    cloud-api-service应该push to '自己的分支',然后去gitserver请求合并 cloud-iopm-web(master分支)应该push to Upstream,然后去gi ...

  3. PHP Fatal error: Uncaught ErrorException: preg_match_all (): JIT compilation failed: no more memory in phar

    PHP 升级到 7.3 后,出现 BUG: 解决办法:修改php.ini文件,;pcre.jit=1 =>  pcre.jit=0

  4. jmeter二次开发----Loadrunner或Jmeter发送邮件报告

    Loadrunner支持Java Vuser,而Jmeter本身就是基于Java开发的,所以两者都可以通过JMail组件实现邮件发送.本人使用的是mail-1.4.7.jar,可以通过下载获得:htt ...

  5. recover database noredo时报错ORA-19573

    环境: RHEL6.4 + Oracle 11.2.0.4 Primary RAC + Standby RAC 今天发现DG备库归档空间满,清理后发现备库出现GAP,需要从主库做基于SCN的增量备份进 ...

  6. NewWord

    identification: 鉴定,识别; 验明; 身份证明; 认同; peer:PEER-TO-PEER:同等延迟机制.根据网络中共享资源方式的不同,局域网有两种组织形式 filters: n. ...

  7. 强力上攻后,缓解期结束,MACD死叉的案例

    eg1.顶部,MACD收紧,缓解期刚过,正好下M5,触发减仓条件

  8. JavaScript-合同到期续约案例

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. nginx空白图片(empty_gif模块)

    用过百度统计的兄弟有没有注意到百度使用1x1的空白图片传递统计参数,自己做异步统计的兄弟是否使用静态文件来传递参数.为什么使用空白图片呢,而不是自己存放一张小图呢,nginx里面的空白图片是保存在内存 ...

  10. executing in nfs will not generate core dump file

    最近遇到了一个奇怪的问题. linux系统的pc搭建nfs server,开发板作为nfs client,开发板中全程root权限操作,执行的程序放到 nfs server 中 exports 出的目 ...