docker 容器端口与数据卷
▶ docker 容器端口
docker 容器中与端口有关的设置是在 docker run 下面的选项中。
| 选项 | 解释 |
|---|---|
| -p | 指定端口 |
| -P | 不指定端口,端口自动分配 |
▷ -P 自动分配端口
[root@server ~]# docker run -d -P nginx
[root@server ~]# docker port vigilant_thompson
80/tcp -> 0.0.0.0:32768
80/tcp -> [::]:32768
这里使用 docker run -d -P 来自动分配容器的端口,通过 docker port 来做一个查看。
▶ docker 设置数据卷
对于 docker 的数据卷来说有三种方式。
▷▷ 方式一:在 docker run 的时候 -v 来宣告一个数据卷
-v:宣告一个数据卷。
[root@server ~]# docker run -it --name container-test -h CONTAINER -v /data debian /bin/bash
-
-it:容器启动的时候进入文本控制台界面。 -
-name:指定容器的名字 container-test。 -
-h:指定容器内部的主机名的名字。 -
-v:本节的重点,在容器中创建一个指定的目录数据卷。
root@CONTAINER:/# ls /data/
root@CONTAINER:/#
此时容器中的 /date 是没有内容的。
开启一个新的终端:
[root@server _data]# docker inspect -f {{.Mounts}} container-test
[{volume 5145f34d2b96a5fc2d0901a20e8bc6feb003ac132563fd1324897ed2a5f32b35
/var/lib/docker/volumes/5145f34d2b96a5fc2d0901a20e8bc6feb003ac132563fd1324897ed2a5f32b35/_data /data local true }]
通过 docker inspect 来查看制定容器的信息,-f,--format 这里指定了 .Mounts 挂载,这也就是说在之前 docker run 的时候创建的 /date 目录其实是系统中的一个目录,然后以挂载的形式挂载到了容器当中。
输出的信息不多,只是内容不比较长而已,输出的前面是容器中的卷,后面跟的是系统中的目录,这表明与以往系统挂载一样。
/var/lib/docker/volumes/5145f34d2b96a5fc2d0901a20e8bc6feb003ac132563fd1324897ed2a5f32b35/_data/ 就是 /date 的实际地址。
进入该目录,在目录中创建一个 hello.txt 的文件
[root@server ~]# cd /var/lib/docker/volumes/5145f34d2b96a5fc2d0901a20e8bc6feb003ac132563fd1324897ed2a5f32b35/_data/
[root@server _data]# touch hello.txt
回到原来的终端界面,此时该终端的内容是容器内的界面。
root@CONTAINER:/# cd /data/
root@CONTAINER:/data# ls
hello.txt
▷▷ 方式二:使用 Dockerfile 文件的时候指定逻辑卷
Dockerfile 中的每个指令执行后都会产生一个新的镜像层,这个镜像层可以用来启动容器,一个新的镜像层的建立就是在上一层的镜像启动容器,然后执行 Dockerfile 的指令后,将其保存为一个新的镜像。
Dockerfile 的指令都成功后留下的中间指令产生的容器默认就会被删掉。
Dockerfile 中的数据卷:
FROM debian
VOLUME /data
VOLUME 和 docker run ... ... -v /data 的效果是一样的。
▷▷▷ 要考虑的问题
上面的简单演示在 docker build 是没有问题的。但是使用后面的 Dockerfile 的就有问题了。
FROM debian
VOLUME /data
RUN touch /data/hello.txt
这个看起和上面的一样简单,只是增加了 RUN touch /data/hello.txt 从直观上看起来没有问题,这是在之前创建的 /data 下面新建了一个文件 hello.txt
[root@server the_dockerfile]# docker build -t hello .
--snip--
> [2/3] RUN touch /data/hello.txt:
0.225 touch: cannot touch '/data/hello.txt': No such file or directory
------
Dockerfile:3
--------------------
1 | FROM debian
2 | VOLUME /data
3 | >>> RUN touch /data/hello.txt
4 | RUN mkdir /the_good
5 |
--------------------
ERROR: failed to solve: process "/bin/sh -c touch /data/hello.txt" did not complete successfully: exit code: 1
--snip--
问题就出在最后一行指令上。问题表明在 touch 的时候失败了。
原因:这是因为临时容器的原因,实际上,它们是在一个用来创建容器层的临时容器内的数据卷上执行的。在第二行执行了 VOLUME 的时候确实是存在一个 /data 卷,但是这个卷是在临时的容器中,在执行下一条指令的时候,这个卷被删除了。第4指令没有办法找到这个卷,即使在容器中确实是有 /data,但是 /data 实际对应的主机的卷已经没有了,因为这个对应的卷是在临时的容器中,在下一行后就没有了,自然第4行也写入不了,失败了。
▷▷▷ 解决上面的问题
解决这个问题用一个成语来讲就是 未雨绸缪,即讲要对 /data 的目录进行的操作提前。
FROM debian
RUN mkdir /data && touch /data/test.txt
VOLUME /data
未雨绸缪:在 VOLUME 指令之前先 RUN 指令执行对目录的操作,相当于是调换位置了,此时基于 RUN mkdir /data && touch /data/test.txt 构建的镜像对目录的操作是有的,现在做的就是将容器中的目录和主机目录的关系也就是 VOLUME 的操作即可。
当使用这个镜像来启动一个容器的时候,Docker 会把这个数据卷目录内的所有文件从镜像复制到容器。
[root@server the_dockerfile]# docker build -t hello .
[+] Building 0.3s (6/6) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 162B 0.0s
=> [internal] load metadata for docker.io/library/debian:latest 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> CACHED [1/2] FROM docker.io/library/debian:latest 0.0s
=> [2/2] RUN mkdir /data && touch /data/test.txt 0.2s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:66d449c034e4fff2644ac597cb72ab8498beaab6ee03fa3 0.0s
=> => naming to docker.io/library/hello 0.0s
当使用这个镜像来启动一个容器的时候,Docker 会把那个数据卷目录内的所有文件从镜像复制到容器。但如果数据卷是和主机目录绑定的话,那么镜像的数据就不会复制到容器了(这是为了防止主机文件被意外覆写)。
▷▷ 方式三:使用 docker run -v 的扩充,指定主机上挂载的卷
-v HOST_DIR:CONTAINER_DIR
前面的方式一、方式二在进行的卷的挂载在删除的时候数据也会连带着一起被删除,但是这种指定挂载的数据卷不会有这样的操作。
示列:
在主机中的 /tmp/ 中创建一个 /test 的目录,这个目录是容器要挂在的卷
[root@server tmp]# cd /tmp/
[root@server tmp]# mkdir test; cat "指定挂载目录" ./test/hello.txt
在这个 test 目录文件中创建了一个 hello.txt 的文件,里面有 指定挂载目录 的内容,方便后面再容器挂载后验证查看。
创建容器,指定挂载:
[root@server tmp]# docker run -it -v /tmp/test/:/home debian /bin/bash
root@380ffbd2e3e3:/# cd /home; ls -l
total 4
-rw-r--r--. 1 root root 19 Sep 17 07:50 hello.txt
root@380ffbd2e3e3:/home# cat hello.txt
指定挂载目录
显然这个目录被容器挂载为数据卷了,里面的 hello.txt 中的内容也能被读取。
root@380ffbd2e3e3:/home# exit
exit
[root@server tmp]#
[root@server tmp]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
380ffbd2e3e3 debian "/bin/bash" 7 minutes ago Exited (0) 50 seconds ago quirky_antonelli
[root@server tmp]# docker rm 380ffbd2e3e3
380ffbd2e3e3
[root@server tmp]# ll
drwxr-xr-x. 2 root root 23 Sep 17 15:50 test
退出容器后删除该该容器,指定挂载的卷是没有被删除的。

浙公网安备 33010602011771号