数据卷volume
简介
Docker的镜像是由一系列的只读层组合而来,当启动一个容器的时候,Docker加载镜像的所有只读层,并在最上层加入一个读写层。这个设计使得Docker可以提高镜像构建、存储和分发的效率,节省了时间和存储空间,然而也存在如下问题:
- 容器中的文件在宿主机上存在形式复杂,不能在宿主机上很方便的对容器中的文件进行访问
- 多个容器之间的数据无法共享
- 当删除容器时,容器产生的数据将丢失
为了解决这些问题,Docker引入了数据卷(volume)机制。volume是存在一个或多个容器中的特定文件或文件夹,这个目录能够独立于联合文件系统的形式在宿主机中存在,并为数据的共享与持久提供一下便利。
- volume在容器创建时就初始化,在容器运行时就可以使用其中的文件
- volume能在不同的容器之间共享和重用
- 对volume中的数据的操作会马上生效
- 对volume中数据操作不会影响到镜像本身
- volume的生存周期独立于容器的生存周期,即使删除容器,volume仍然会存在,没有任何容器使用的volume也不会被Docker删除
创建数据卷
Docker 提供了volume 子命令来管理数据卷,如下命令可以快速在本地创建一个数据卷。docker volume
命令非常简单,只有5个command。
1 | [root@master ~]# docker volume --help |
这时查看/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 | [root@master ~]# docker run -itd --name busybox --mount type=bind,source=/test,destination=/test busybox |
使用volume来绑定也是一样的。如下:
1 | [root@master ~]# docker run -itd --name busybox --mount type=volume,source=mydata,destination=/test busybox |
同时,由于也可以简化为-v来运行。mydata:/test:ro
后接的ro,表示只读。
1 | [root@master ~]# docker run -itd --name busybox -v mydata:/test:ro busybox |
其实,在使用-v时,如果用的是名字,docker会自动增加volume,如下:
1 | [root@master ~]# docker run -itd --name busybox -v mydata11:/test:ro busybox |
docker建议使用-v用来挂载目录,不要用来挂载文件。
Dockerfile有VOLUME指令,会创建volume数据卷,这样,容器被删除,但是数据并不会删除掉。
1 | FROM centos |
有兴趣的朋友可以阅读:Docker 容器内添加数据卷的2种方式
数据卷容器
如果用户需要在多个容器之间共享一些持续更新的数据,最简单的方式是使用数据卷容器。数据卷容器也是一个容器,但是它的目的是专门提供数据卷给其他容器挂载。使用--volumes-from container_NAME
实现。
1 | [root@master ~]# docker run -itd -v /data --name db busybox |
此时, 容器db1都挂载同一个数据卷到相同的 /data 目录,两个容器任何一方在该目录下的写人,其他容器都可以看到。
利用这个特性非常容易去备份或者还原volume里面的数据:
1 | [root@master ~]# docker run --rm --volumes-from db -v `pwd`:/backup busybox tar zcvf /backup/data.tgz /data |
其他高级用法,请参考: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 | [root@master ~]# docker run -itd --name tank -p 8080:80 tank |
访问8080端口的流量会自动转至容器的80端口进行服务了。
容器的互联机制
容器的互联是一种让多个容器中应用进行快速交互的方式,它会在源和接收容器之间建立连接关系,接收容器可以通过容器名快速访问到源容器,而不用指定具体的IP地址。使用—link参数可以让容器之间安全地进行交互。
1 | [root@master ~]# docker run -itd --name db --env MYSQL_ROOT_PASSWORD=123456 mariadb |
此时web容器已经和db容器建立互联关系:—link参数的格式为:—link name:alias,其中name是要连接的容器名称,alias是这个连接的别名。Docker相当于在两个互联的容器之间创建了一个虚拟通道,而不用映射它们的端口到宿主机上。在启动db容器的时候并没有使用-p或者-P参数,从而避免了暴露数据库服务端口到外部网络上。
通过link来为窗口建立互联,主要是做了2个事情,一是会更新环境变量,二是更新/etc/hosts文件:
1 | [root@master ~]# docker exec web env |
其中DB_开头的环境变量是提供web容器连接db容器使用的,前缀采用大写的连接别名。
这里有两个hosts信息,第一个是db容器的IP和容器名+容器ID,第二个是web自己的IP和容器ID,web容器中hosts文件采用容器的ID作为主机名。互联的容器之间是可以ping通的。