你不好奇嘛?Docker如何实现容器的通信?

2,438 阅读8分钟

docker数据卷

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

在学习数据卷之前,我们先来考虑这几个问题。

  1. 如何把容器中的文件拿出来?
  2. 如何把本机的一个文件放进容器?
  3. 容器之间如何交换文件?

由于容器间的东西都是隔离的,容器和主机中的文件也是隔离的,因此我们没有办法直接交换文件,此时,用数据卷就可以完成这个操作

概念

数据卷的本质就是宿主机(你的服务器)文件系统的一个目录或者文件,通常,这个目录会和容器中的某个目录进行绑定,此时,两个目录的文件就会同步,当数据卷目录中增加或者删除文件,容器中对应绑定的,目录的文件就会发生变化,反过来也一样,这个操作叫挂载

有点类似vue中的 v-bind

image-20220714144354636

一个容器可以挂载多个数据卷,并且一个数据卷可以被多个容器挂载,这是个多对多的关系

因此,我们可以得到数据卷的作用:

1.容器数据的持久化

2.外部宿主机和容器内部的通信

3.容器之间数据交换

配置数据卷

讲了数据卷的概念,我们就可以进入实战了

1)匿名挂载

案例1:一个容器和一个宿主机之间的信息交换

先在宿主机中创建一个文件夹用来通信

/root/datavolume

然后开一个debian镜像 ,用-v命令对这个文件进行挂载,这里我们挂载到/root/val目录

这样 /datavolumn 和 /val目录进行绑定挂载

docker run -id --name=d1 -v /root/datavolume:/root/vol debian /bin/bash

注意,这里的 -v 后面进行了绑定操作 debian是镜像的名字,/bin/bash是对debian的操作

我们在宿主机试着创建一个test文件

touch test

发现,容器里面也有一个test 。

然后我们进入容器

docker exec -it d1 /bin/bash
cd /root/vol
ls

删掉 test,再exit进入宿主机

发现宿主机里面的test文件也消失了

案例2:两个容器和一个宿主机之间的信息交换

由于内容太像,这里我们可以直接

docker run -id --name=d2 -v /root/datavolume:/root/vol debian /bin/bash

新开一个名字叫d2的容器 ,再进行试验。之后留给读者自行实践

案例3:如果说两者通信要挂载多个目录

docker run ... -v 宿主机目录1:容器目录1 -v 宿主机目录2:容器目录2 ...

多写几个-v即可

2)具名挂载

因为匿名挂载需要指定一个具体的绝对路径,这样的话,容器一多,挂载的数据卷一多,就会难以管理,因此,我们平时推荐用具名挂载的方式

首先,我们先用docker volume命令创建一个数据卷,本质上就是一个文件

# 创建一个名为my-config的数据卷
docker volume create my-config 

此时,就定义好了一个名为my-config的数据卷,名字可以自定义,使用

docker volume inspect my-config

查看具体位置

image-20221003204347126.png

第三行就是文件所在位置

若要创建容器时具名挂载数据卷,命令格式如下:

docker run -id -v 数据卷名:容器内路径 ...
bashcopy

例如我要创建个Debian容器并把这个名为my-config的数据卷挂载至容器内的/config目录下:

docker run -id -v my-config:/config debian
bashcopy

这样就挂载完成了!

注意:数据卷只能在创建容器的时候设定!后续一个容器的数据卷不能增加或者移除!

3)清理无用数据卷

如果一个容器挂载了数据卷,但是容器被删除了,数据卷是不会被删除的。

执行以下命令查看所有数据卷

docker volume ls

image-20221003212619473.png 可以一键删除不再使用的数据卷:

docker volume prune

这种方式只能清理具名挂载和仅持久化

(4) 数据卷文件覆盖问题

一些同学在创建数据卷的时候,会发现文件莫名其妙地不见了,这里说明我们很有必要了解一下不同情况下在创建容器并挂载数据卷时的文件覆盖问题。

匿名挂载的时候,无论宿主机上数据卷文件夹是空的还是有文件的,都会覆盖掉容器内的对应目录。

分以下情况讨论:

宿主机上数据卷文件夹对应容器文件夹结果
空文件夹空文件夹挂载并无事发生
空文件夹有内容文件夹容器内文件夹被清空
有内容文件夹空文件夹数据卷内文件被复制到容器内对应目录
有内容文件夹有内容文件夹容器内对应目录文件被清空,数据卷内文件被复制到容器内对应目录

可见在匿名挂载的时候,无论如何都是以宿主机上的数据卷文件夹情况为准的。这样的话,如果说这个容器对应目录本来就有文件,使用匿名挂载就会导致容器内文件丢失。

那么具名挂载又是什么情况呢?看下面表格:

具名数据卷对应容器内文件夹结果
空文件夹空文件夹挂载并无事发生
空文件夹有内容文件夹容器内对应文件夹中的内容被复制到数据卷中
有内容文件夹空文件夹数据卷内文件被复制到容器内对应目录
有内容文件夹有内容文件夹容器内对应目录文件被清空,数据卷内文件被复制到容器内对应目录

可见在匿名挂载和具名挂载的时候,只有一个地方是有区别的:数据卷文件夹为空而容器内文件夹由内容的时候

所以说,日常绝大多数时候,我们使用具名挂载的方式也更加的好,不仅好管理,在对于要修改容器内配置文件的情景下具名挂载也更适合。

上述情况中若有一边的指定的目录不存在,则会先被自动创建,视为空文件夹情况即可。数据卷。

3.数据卷容器

数据卷容器实际上就是一个容器,只不过数据卷容器是专门用于数据交换来用的

image-20220714151746336

也就是说,数据卷容器会挂载一个目录,然后多个容器会挂载到数据卷容器上,然后宿主机上的数据卷目录发生变化,数据卷容器对应目录也会发生变化,挂载数据卷的容器也会发生变化。

实战

我们先创建一个名为data的容器作为数据卷容器。

docker run -id --name=data -v /datavolume debian /bin/bash

现在我们-v只指定容器内的目录,那么宿主上的文件会被自动分配一个目录进行挂载。

然后再创建两个容器名为c1c2挂载到这个数据卷容器data上:

docker run -id --name=c1 --volumes-from data debian /bin/bash
docker run -id --name=c2 --volumes-from data debian /bin/bash
bashcopy

上述--volumes-from就代表指定要挂载的数据卷容器。

现在进入容器data,在其中的/datavolume中新建一个文件,然后退出并分别进入c1c2容器下的/datavolume目录,你会发现刚刚数据卷中新建的文件也同步过来了!

当然,现在可能有的同学还在好奇:上述的数据卷容器data中的/datavolume目录挂载在宿主机上的那个目录呢?通过docker inspect命令来看看:

docker inspect data
bashcopy

image-20220714153703415

输出很多信息,找到Mounts字段,其中Source表示这个容器数据卷对应的宿主机目录,而Destination对应的容器内目录。

4,docker cp命令

除了使用数据卷实现容器和宿主机的文件传输,还可以使用docker cp命令把容器内文件拷贝出来到宿主机,当然也可以反过来把宿主机内文件拷贝进容器。

# 把容器内文件拷贝到宿主机
docker cp 容器ID/容器名:容器内文件绝对路径 拷贝到宿主机的路径

# 把宿主机的文件拷进容器
docker cp 宿主机文件的路径 容器ID/容器名:拷贝到容器内的路径
bashcopy

例如:

# 把本机当前目录下的test文件拷贝到名为c1容器中的/root目录下
docker cp ./test c1:/root/

# 把本机当前目录下的test文件拷贝到ID为155ddba25935容器中的/root目录下并重命名为test-file
docker cp ./test 155ddba25935:/root/test-file

# 把名为c1容器中文件/root/test拷贝到本机当前路径下并重命名为tt
docker cp c1:/root/test ./tt

# 把本机当前目录下的datavolume目录拷贝到名为c1容器中/root目录下
docker cp ./datavolume/ c1:/root/
bashcopy

可见无论是文件还是目录都可以拷贝,通常目录后以/结尾。