关于Docker的挂载

 底层原理不懂就上手,上手出了问题就懵逼,最近在对接阿里云时遇到Docker存储驱动的神坑,爬了几天爬不出来,最后发现是节点中Docker存储驱动的问题,由此引发此次学习,避免类似问题再次懵逼。

 关于镜像images,核心首先必须明确一点,镜像都是只读的,如果需要进行写操作,必须在该镜像上创建一个新的镜像层(我们所有的写操作其实都是在一个可写的镜像层上操作的)。同时镜像也是共享的,那些依赖于同一个 image 的多个容器,并不会将单独复制需要的镜像到自己的容器中进行启动,那样会浪费巨大的空间,实际节点上只会有一个镜像,多个容器是共享这一个镜像的。存储驱动可以将容器中的数据进行持久化同时避免性能问题。存储驱动允许我们在容器的可写层创建数据,这些数据在容器销毁后也就没有了,且这些文件的读写速度都比本地文件系统的性能低。

 默认情况下,容器内所有创建的文件都存储在一个可写层,所以这些文件仅仅存活于容器运行时,一旦容器被销毁这些文件也会被销毁。容器的可写层和宿主机器紧密耦合,很难将可写层的文件或数据迁移到非宿主机器外的地方。要将数据写入容器的可写层必须要有一个存储驱动(storage driver)来管理文件系统,存储驱动程序使用Linux内核提供的联合文件系统,这种方式与使用直接写入主机文件系统的数据卷相比降低了性能。Docker提供几种种持久化容器中数据或文件的方式:

  • volumes:Volumes是持久化Docker中数据最好的方式,存在于宿主机器文件系统的一部分(Linux中位于/var/lib/docker/volumes/目录下的xx.db文件),由Docker自己管理,非Docker进程去修改这部分的文件;
  • bind mounts:这种方式可以将容器中的数据持久化到宿主机器的任何位置(文件或目录),任何进程都可以进行修改
  • tmpfs mount:Linux 上专用,tmpfs挂载仅存储在主机系统的内存中,永远不会写入主机系统的文件系统;
  • named pipe:windowns 上专用,同上;

关于上述的几种方式的区别,官网形象的图文解释:

几种持久化方式

1. Volumes(最推荐的挂载方式)

 Volumes(数据卷) 由 Docker 自行创建和管理,可以使用docker volume create显式的创建一个Volume,当然如果不人为创建,Docker会在创建容器或服务时自行创建。在使用docker volume create xxx创建 Volume 时,Docker会在宿主机器的/var/lib/docker/volumes/目录下创建xxx文件夹用于容器数据的持久化。当将xxx的Volume挂载到容器上时,此目录就是容器中对应的目录。这种方式和bind mounts很相似,但 Volumes 方式是和宿主机器核心功能隔离并且是由Docker自己管理的。注意同一个Volume是可以同时挂载到多个容器内的,当没有使用该存储卷的容器时,该存储卷并不会自动销毁(因为主要是解决容器可写层数据持久化的问题,当然不会自动销毁),如果需要删除某个存储卷需要手动调用docker volume prune命令,这个命令将会移除所有宿主机器本地的Volumes(谨慎操作)。

 当挂载一个 Volume 时,该存储卷可以进行命名或直接匿名,匿名存储卷首次挂载到容器时并不会显式的给它一个名字,而是Docker给它们一个随机名字,且保证该名字是Docker主机中唯一的,匿名和命名的存储卷唯一的区别就是它们名字。

 Volumes 是支持 volume driver 的,它允许使用远程主机的存储卷或者其他云供应商提供的数据卷或者其他的存储形式。

下面是一个示例:

# 创建数据卷
docker volume create testvolumes
# 直接拉一个ubuntu镜像来实验
docker pull ubuntu
# 通过 '-v/--volume 存储卷' 的方式即可挂载  /var/lib/docker/volumes/testvolumes:
docker run -it -v testvolumes ubuntu:latest
# 在容器中的 /testvolumes/_data 目录下创建空文件 addDatas,退出容器并查看宿主机器的 /var/lib/docker/volumes/testvolumes/_data 创建成功
touch addDatas

 Volum应用场景包含:

  • Volume可以让多容器共享的数据(读写或只读),若不显式创建它,会在被挂载前自动创建,Volume只有在显式移除时才会被移除;
  • Docker宿主机不具备目录结构或者文件系统,Voulme 可以帮助将Docker宿主机的配置从容器运行时解耦;
  • 远程存储,这点应该是最广泛的场景,目前很多应用都“上云”,使用的是云提供商或者远程机器,而不是宿主机器本身的存储;
  • Volume可以在备份、还原、迁移Dokcer宿主机发挥很人性化的优势,可以先停止使用某个Volume的容器,然后备份Volume(通常目录为/var/lib/docker/volumes/<volume-name>)即可;

 Volume 方式有点注意点:

  • 当将一个空数据卷(volume)挂载到容器中某个已存在的文件或目录时,那么容器该文件或目录中的内容将会被复制到这个空数据卷中;
  • 当挂载一个不存在的数据卷时,Docker会自动创建一个空的数据卷,这是预先填充另一个容器所需数据的好方法,比如B容器需要一个数据卷VolumeX,他会去检测VolumeX是否存在,那如果A容器在B容器之前启动并且创建了一个VolumeX,那么B的检测就能通过;

 数据卷驱动,当创建数据卷docker volume create xxx或启动容器挂载一个还未创建的数据卷时,此时可以指定一个数据卷驱动。下面是一个示例

 数据卷 Volume 支持--mount--volume/-v的语法,当和服务(即swarm services)一起使用数据卷时,仅支持--mount参数,所以官方也是一直推荐使用--mount,完整的示例:

# 1. 单个容器的示例
# 创建数据卷
docker volume create my-vol
# 查看数据卷列表
docker volume ls
# 使用ubuntu镜像创建一个容器devtest,将数据卷my-vol挂载到目录/app下,并且该数据卷是只读的
docker run -d --name devtest --mount src=my-vol,dst=/app,readonly ubuntu:latest
# 检查容器信息(注意查看 Mounts 字段是否和期望的一样)
docker volume inspect devtest
# 移除数据卷
docker container stop devtest
docker container rm devtest
docker volume rm my-vol

# 2. 容器服务的示例
# 将当前节点进行 swarm 初始化,并且成为master
docker swarm init
# 创建副本为4的service,service仅支持--mount,不支持-v/--volume的形式
docker service create -d --replicas=4 --name devtest-service --mount src=my-vol,dst=/app/test ubuntu:latest
# 查看service的状态
docker service ps devtest-service
# 移除所有 devtest-service 的task
docker service rm devtest-service

2. Bind mounts

 Bind mounts (绑定加载)的方式在Dokcer早期版本就提供了,相对于 Volumes 方式功能有限。Bind mounts 就是将宿主机器中一个文件或者目录挂载到容器中,挂载时必须以该文件或目录的绝对路径指定,而且指定的宿主机器上的路径不一定非要在宿主机器上存在,Docker在加载时会去按需创建,而且绑定加载的性能非常好,但它依赖于宿主机器上特定的目录结构。所以目前为官网还是推荐使用数据卷(Volumes)的形式来作存储驱动。此外,bind mounts 不能使用使用Dokcer命令行直接管理这些绑定加载(bind mounts)。

 此外 bind mounts 方式必须对一些敏感文件(比如host文件)有权限,可以通过运行在容器中的进程修改(增长改查)系统host文件,这个功能可能会引发安全问题,因为此时Dokcer对宿主机器上非Docker进程甚至系统级别的文件都可以随意更改。

下面是一个示例:

# 通过 `-v/--volume 宿主机目录:容器目录` 的形式将宿主机器的 /root/helm 目录挂载到容器的 /usr/local/helm 目录
docker run --volume /root/helm:/usr/local/helm -it ubuntu:latest

 绑定挂载适用的场景有:

  • 给容器共享宿主机上的配置文件,这也是 Docker 通过将宿主机上的/etc/resolv.conf挂载到容器内从而给容器提供的默认DNS策略;
  • 在开发环境的宿主机器和容器之间共享代码或者构建的jar包、war包,比如对于maven项目,直接将服务模块的target目录绑定挂载到容器中,这样就不需要要在容器内再次构建了;
  • 当确保Docker主机的文件或目录结构与绑定挂载所需的容器目录一致时;

 绑定挂载和数据卷同时有一个注意点,如果将一个非空宿主机目录挂载到容器中已存在的文件或者目录,那么容器内的这些文件或目录将会被宿主机的文件或者目录将会被遮挡,就像你把文件存在宿主机的/mnt目录,然后将一个USB驱动也挂载到/mnt,那此时/mnt目录中的内容将会被USB驱动遮挡直到USB驱动取消挂载,被遮挡的文件或目录并不会被移除或修改,只是使用绑定挂载或者数据卷形式时这些文件是不可得的;

3. tmpfs mounts

tmpfs挂载不会持久化在磁盘上持久化,也不会存储在宿主机器上,可以在容器的生命声明周期内使用,用于存储不需要持久化或者一些敏感信息,典型应用在内部,群集服务使用tmpfs挂载将机密安装到服务的容器中。使用--tmpfs参数进行挂载。

tmpfs挂载适用于那些不需要在宿主机器或容器中持久化数据的场景,比如可能为了安全原因或者是为了在application 需要写大量非持久化数据时保证容器的性能(我觉得这个原因靠谱点)。

4. named pipes

npipe挂载可以用于宿主机器和Docker容器的通信,典型应用就是在容器中运行第三方工具时使用named pipe连接 Docker Engine 的 API。

注:上述4种挂载方式在语法上不太一样,使用-v/--volume来使用,在17.06+可以不区分挂载方式直接使用--mount进行挂载(本来这个参数是用于 swarm services,而单个容器使用-v/--volume),因为之前使用的 -v/--volume 参数名和数据卷Volume的形式一样,很容易误导开发者是转专用于数据挂载方式的参数,而且对于参数的定义较为严格,使用--mount参数语义更加清晰,诸如:docker run -it --mount source=testvolumes,target=/usr/local/helm ubuntu:latest(前提是建立自己的Volume)。

5.关于语法

5.1 -v/–volume

-v/--volume命令实际是有三个参数的,之间以:分隔,而且必须以规定的顺序出现,三个参数的具体含义为:

  • 第一个参数:对于有名字的数据卷表示数据卷的名字,该名字必须在宿主机上唯一;对于匿名数据卷,第一个参数需要省略;
  • 第二个参数:挂载到容器内的路径;
  • 第三个参数(可选):是一系列以,分隔的参数;
5.2 --mount

--mount命令参数是由多个<key>=<value>形式的键值对组成,之间以,分隔,不要求顺序,主要参数的键值对有:

  • type=xxxtype参数用来表示挂载的方式,value可以是volumebind或者tmpfs
  • source/src=xxxsource或者src参数表示数据卷(有名字的,匿名数据卷该参数省略),value为数据卷的名字;
  • target/destination/dst=xxxtarget或者destination或者dst参数表示内容器的挂载路径,value即为容器内的目录;
  • readonly:表示绑定挂载是否只读bind mount,如果出现(该字段非键值对),那容器内对该文件/目录只具备读的能力;
  • volume-opt:表示除上述参数之外的其他参数,可以出现多个volume-opt参数,每个都以键值对的形式出现;

 如果数据卷驱动可以接受多个以,分隔的数组,那在传参时必须在CSV编译器检查语法时正常通过,为此用双引号""volume-opt这个参数对象包裹起来,然后整个--mount参数对象使用单引号''包裹,示例:

$ docker service create \
     --mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
    --name myservice \
    <IMAGE>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Docker挂载指的是将主机上的目录或文件系统挂载到容器中,使容器可以访问主机上的文件或目录。挂载可以让容器与主机之间共享数据,方便容器中的应用程序对主机上的文件进行读写操作。同时,挂载还可以让容器中的数据得以持久化,即使容器被删除,挂载的数据也不会丢失。 Docker挂载可以使用`-v`参数或者`--mount`参数来实现。`-v`参数是较早期的挂载方式,而`--mount`参数可以提供更多的挂载选项。挂载的语法为: ``` docker run -v /host/path:/container/path image_name ``` 或 ``` docker run --mount type=bind,source=/host/path,target=/container/path image_name ``` 其中,`/host/path`是主机上的目录或文件系统路径,`/container/path`是容器中的目录或文件系统路径。Docker将主机上的目录或文件系统挂载到容器中的`/container/path`目录或文件系统中,使得容器可以访问主机上的文件或目录。 除了`type=bind`,`--mount`参数还支持其他类型的挂载方式,例如`tmpfs`和`volume`。`tmpfs`类型的挂载可以将主机上的目录或文件系统挂载到容器中的一个临时文件系统中,而`volume`类型的挂载可以将主机上的目录或文件系统挂载Docker Volume中,以便其他容器可以共享这个Volume。 ### 回答2: Docker挂载是指将主机文件系统中的目录或文件与Docker容器中的对应目录或文件进行关联,实现在不修改容器镜像的情况下对容器内部进行文件操作的功能。它通过将主机文件系统中的目录或文件映射到容器中的对应位置,可以在容器内部读取、写入和修改主机文件系统上的文件。 Docker挂载的过程可以分为两个步骤。首先,需要在运行容器时使用"-v"或"--mount"参数指定要进行挂载的主机目录或文件以及对应的容器目录。其次,当容器在运行过程中对挂载目录或文件进行操作时,实际上操作的是主机文件系统上的对应目录或文件。 Docker挂载具有以下几个优点。首先,它实现了主机与容器之间的文件共享,使得容器可以方便地访问主机上的文件资源。其次,挂载可以使容器在运行过程中对文件进行修改和写入,这对于一些需要持久化储存数据的应用非常重要。此外,挂载还可以实现容器与主机之间的文件共享,用于多个容器之间进行文件共享和数据交换。 然而,Docker挂载也有一些注意事项。首先,当主机文件系统上的文件被容器修改后,主机上的文件也会相应地被修改,因此需要谨慎处理对文件的操作。其次,当挂载目录或文件在主机上不存在时,容器可能无法正常执行,因此在进行挂载时需要确保目录或文件存在并且具有合适的权限。最后,挂载的目录或文件可能会受到主机系统的限制,例如文件系统的类型、权限等,需注意处理可能遇到的问题。 总之,Docker挂载是一种实现主机与容器之间文件共享和数据交换的机制,它极大地方便了容器的使用和文件的管理。通过合理的使用挂载功能,可以有效地利用Docker的灵活性和便携性。 ### 回答3: Docker 挂载是指将主机上的文件或目录与 Docker 容器中的文件系统进行关联,从而使容器能够访问主机上的文件。通过挂载,可以实现主机与容器之间的文件共享和数据交互。 Docker 提供了多种挂载方式,包括目录挂载和文件挂载。目录挂载是将主机上的目录映射到容器中的指定路径,这样容器中的应用程序就可以读取和写入主机上的文件。文件挂载则是将主机上的单个文件映射到容器中,容器可以直接读取和修改该文件。 使用 Docker 挂载的好处是可以方便地修改容器中的文件,而无需重新构建镜像。例如,在开发过程中,可以将代码目录挂载到容器中,这样在主机上修改代码后,容器中的代码也会自动更新,从而实现实时调试。同时,使用挂载还可以保护容器中的数据,将重要的数据文件存储在主机上,以防容器被删除或重新创建。 要实现挂载,可以使用 Docker 命令行中的 `-v` 参数来指定挂载的目录或文件路径。例如,`docker run -v /host/path:/container/path` 表示将主机上的 `/host/path` 目录挂载到容器中的 `/container/path` 路径。 需要注意的是,如果要挂载主机上的文件或目录,需要确保路径存在并有相应的读写权限。此外,挂载的路径必须在容器的文件系统中是空的,否则挂载可能会失败。 总而言之,Docker 挂载是一种非常有用的功能,可以实现主机和容器之间的文件共享和数据交互。通过挂载,可以方便地修改容器的文件,并保护容器中的数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值