docker入门教程三:数据卷与端口

数据卷volume

简介

Docker的镜像是由一系列的只读层组合而来,当启动一个容器的时候,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题:

  • 容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问
  • 多个容器之间的数据无法共享
  • 当删除容器时,容器产生的数据将丢失

为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供一下便利。

  • volume在容器创建时就初始化,在容器运行时就可以使用其中的文件
  • volume能在不同的容器之间共享和重用
  • 对volume中的数据的操作会马上生效
  • 对volume中数据操作不会影响到镜像本身
  • volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除

创建数据卷

Docker 提供了volume 子命令来管理数据卷,如下命令可以快速在本地创建一个数据卷。docker volume命令非常简单,只有5个command。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@master ~]# docker volume --help
...
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove all unused local volumes
rm Remove one or more volumes
[root@master ~]# docker volume create mydata
mydata
[root@master ~]# docker volume ls
DRIVER VOLUME NAME
local mydata
[root@master ~]# ll /var/lib/docker/volumes/
total 24
-rw------- 1 root root 32768 Sep 21 22:46 metadata.db
drwxr-xr-x 3 root root 19 Sep 21 22:46 mydata

这时查看/var/lib/docker/volumes/路径下,会发现所创建的数据卷位置。

绑定数据卷

在用docker [container] run命令的时候,可以使用--mount 选项来使用数据卷。mount 选项支持三种类型的数据卷,包括:

  • volume :普通数据卷,映射到主机/var/lib/docker/volumes/路径下;
  • bind :绑定数据卷,映射到主机指定路径下;
  • tmpfs :临时数据卷,只存在于内存中。

如下,使用—mount来绑定目录,其效果docker run -itd --name busybox -v /test:/test busybox是一样的。

1
2
[root@master ~]# docker run -itd --name busybox --mount type=bind,source=/test,destination=/test busybox
6e82c9a94dc22480ed8f125182dbd1c193408d90228182a8d440916a4673103f

使用volume来绑定也是一样的。如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@master ~]# docker run -itd --name busybox --mount type=volume,source=mydata,destination=/test busybox
7a0493e6103eccd7d2293dc45c6dedebe08260fa702e0ec8681c3f7359c9d1df
[root@master ~]# docker-enter busybox
/ # cd /test/
/test # ls
/test # echo 123 >123.txt
/test # exit
123
[root@master ~]# docker rm -f busybox
busybox
# 将容器删除完之后,数据还在有存在volumes下
[root@master ~]# cat /var/lib/docker/volumes/mydata/_data/123.txt
123

同时,由于也可以简化为-v来运行。mydata:/test:ro后接的ro,表示只读。

1
2
3
4
5
6
[root@master ~]# docker run -itd --name busybox -v mydata:/test:ro busybox
50616a0220d42a4704f564a7fe1c424ace720d6b1d5d9d2752c24fdcbfd81db1
[root@master ~]# docker-enter busybox
/ # echo 456 >>/test/123.txt
sh: can't create /test/123.txt: Read-only file system
/ # exit

其实,在使用-v时,如果用的是名字,docker会自动增加volume,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@master ~]# docker run -itd --name busybox -v mydata11:/test:ro busybox
fa1d2c1f4530f66fb8849352da9b811706bcd3039d7f160638e11e08fdaf051d
[root@master ~]# docker inspect -f '{{json .Mounts}}' busybox |jq
[
{
"Type": "volume",
"Name": "mydata11",
"Source": "/var/lib/docker/volumes/mydata11/_data",
"Destination": "/test",
"Driver": "local",
"Mode": "ro",
"RW": false,
"Propagation": ""
}
]
[root@master ~]# docker volume ls
DRIVER VOLUME NAME
local mydata
local mydata11

docker建议使用-v用来挂载目录,不要用来挂载文件。

Dockerfile有VOLUME指令,会创建volume数据卷,这样,容器被删除,但是数据并不会删除掉。

1
2
3
4
5
6
7
FROM centos
VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
CMD echo "finished,------success1"
CMD /bin/bash

#等同于
docker run -it -v /dataVolumeContainer1 -v /dataVolumeContainer2 centos /bin/bash

有兴趣的朋友可以阅读:Docker 容器内添加数据卷的2种方式

数据卷容器

如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。使用--volumes-from container_NAME实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@master ~]# docker run -itd -v /data --name db busybox
d32e2bedca3e4b43efa20d0adbe83ec63b1fb01e3a9a97a826e7a152bea14e32

# 注意,--volumes-from后面接的是容器名
[root@master ~]# docker run -itd --volumes-from db --name db1 busybox
f925e1e76c39be335d6de8d6ae4b2f3f769d3d5684f7333bba90013cca4ad945
# 写入一个数据
[root@master ~]# docker-enter db
/ # echo aaa >/data/a.txt
/ # exit

# 在另一个容器中查看数据
[root@master ~]# docker-enter db1
/ # cat /data/a.txt
aaa
/ # exit

此时, 容器db1都挂载同一个数据卷到相同的 /data 目录,两个容器任何一方在该目录下的写人,其他容器都可以看到。

利用这个特性非常容易去备份或者还原volume里面的数据:

1
2
3
4
5
6
7
[root@master ~]# docker run --rm --volumes-from db -v `pwd`:/backup busybox tar zcvf /backup/data.tgz /data
tar: removing leading '/' from member names
data/
data/a.txt
[root@master ~]# tar ztvf data.tgz
drwxr-xr-x root/root 0 2019-09-21 23:28 data/
-rw-r--r-- root/root 4 2019-09-21 23:28 data/a.txt

其他高级用法,请参考:Docker容器数据持久化

端口与互联

端口映射实现访问容器

在启动容器的时候,如果不指定对应的参数,在容器外部是无法通过网络来访问容器内部的网络应用和服务的。当容器中运行一些网络应用,要让外部访问这些应用时,可以通过-p或-P参数来指定端口映射。当使用-P(大写P)标记时,Docker会随机映射一个端口到内部容器开放的网络端口(端口范围在Linux系统使用的端口之外,一般都过万)。

-p(小写p)可以指定要映射的端口,并且在一个指定的端口上只可以绑定一个容器。支持的格式有:IP:HostPort:ContainerPort | IP::ContainerPort | HostPort:ContainerPort。多次使用-p参数可以绑定多个端口。

  • 使用HostPort:ContainerPort格式将本地的一个端口映射到容器的指定端口

  • 使用IP:HostPort:ContainerPort格式指定将使用一个特定的IP地址+端口,映射到容器的指定端口

  • 使用IP::ContainerPort格式绑定本机的任意端口到容器的指定端口

1
2
3
4
5
6
[root@master ~]# docker run -itd --name tank -p 8080:80 tank
[root@master ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4d14a9c701b7 tank "nginx -g 'daemon of…" 15 hours ago Up 15 hours 0.0.0.0:8080->80/tcp tank
[root@master ~]# docker port tank
80/tcp -> 0.0.0.0:8080

访问8080端口的流量会自动转至容器的80端口进行服务了。

容器的互联机制

容器的互联是一种让多个容器中应用进行快速交互的方式,它会在源和接收容器之间建立连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址。使用—link参数可以让容器之间安全地进行交互。

1
2
3
4
[root@master ~]# docker run -itd --name db --env MYSQL_ROOT_PASSWORD=123456  mariadb
8eafe543e87bbb327a9bf0dbdabed29f4426c48a74ab1975787131ab4bb1af6b
[root@master ~]# docker run -itd -P --name web --link db:db nginx:latest
658c55dd5edbe3e31fc0e17cec260944f4180b9ecba4f3dbb1a2616ccbfcb004

此时web容器已经和db容器建立互联关系:—link参数的格式为:—link name:alias,其中name是要连接的容器名称,alias是这个连接的别名。Docker相当于在两个互联的容器之间创建了一个虚拟通道,而不用映射它们的端口到宿主机上。在启动db容器的时候并没有使用-p或者-P参数,从而避免了暴露数据库服务端口到外部网络上。

通过link来为窗口建立互联,主要是做了2个事情,一是会更新环境变量,二是更新/etc/hosts文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@master ~]# docker exec web env
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=658c55dd5edb
DB_PORT=tcp://172.17.0.4:3306
DB_PORT_3306_TCP=tcp://172.17.0.4:3306
DB_PORT_3306_TCP_ADDR=172.17.0.4
DB_PORT_3306_TCP_PORT=3306
DB_PORT_3306_TCP_PROTO=tcp
DB_NAME=/web/db
DB_ENV_MYSQL_ROOT_PASSWORD=123456
DB_ENV_GOSU_VERSION=1.10
DB_ENV_GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8
DB_ENV_MARIADB_MAJOR=10.4
DB_ENV_MARIADB_VERSION=1:10.4.8+maria~bionic
NGINX_VERSION=1.17.0
NJS_VERSION=0.3.2
PKG_RELEASE=1~stretch
HOME=/root
[root@master ~]# docker exec web cat /etc/hosts
127.0.0.1 localhost
172.17.0.4 db 8eafe543e87b
172.17.0.5 658c55dd5edb

其中DB_开头的环境变量是提供web容器连接db容器使用的,前缀采用大写的连接别名。

这里有两个hosts信息,第一个是db容器的IP和容器名+容器ID,第二个是web自己的IP和容器ID,web容器中hosts文件采用容器的ID作为主机名。互联的容器之间是可以ping通的。

参考链接:https://www.cnblogs.com/jie-fang/p/7920863.html

  • 本文作者: wumingx
  • 本文链接: https://www.wumingx.com/k8s/docker-volume-port.html
  • 本文主题: docker入门教程三:数据卷与端口
  • 版权声明: 本博客所有文章除特别声明外,转载请注明出处!如有侵权,请联系我删除。
0%