文章目录
  1. 1. 指定存储(Volumn)
  2. 2. docker容器网络访问控制
  3. 3. docker端口映射

指定存储(Volumn)

Volumn是Docker容器中,用于将数据存储在容器之外的路径的工具。

主要有两个地方会用到,一个是在使用docker run命令的时候,可以用-v参数指定存储,如-v [host dir]:[container dir],将宿主机的目录[host dir]挂载到容器内的[container dir],也可以只指定容器目录,如-v [container dir],表示在容器内创建一个目录container dir,该目录的修改不会记录在容器的修改中,而会存在/var/lib/docker目录下的./volumnes目录中。./volumnes目录下的数据文件不会被docker删除,即使容器被删除也不会,如果要清理这个目录下的文件,只能手动进行。例如,可以使用docker inspect查看存储的路径,如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
$ docker inspect 9f47cb4bb97f
...... // 省略部分内容
"Mounts": [
{
"Name": "05d30758ebf0ca16e86026b2328b2c6b48cfaa62e9f7a262c0a6dfddde003a11",
"Source": "/var/lib/docker/volumes/05d30758ebf0ca16e86026b2328b2c6b48cfaa62e9f7a262c0a6dfddde003a11/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true
}
],
...... // 省略部分内容

Volumn的另一种用法是在dockerfile中,其含义与docker run的后一种用法相同。可以参考mysql的dockerfile的例子,无论是标准的mysql镜像,或者是mariadb镜像,又或者是Oracle的mysql镜像,其dockerfile123中指定volumn的都只有如下一行,

1
VOLUME /var/lib/mysql

即创建容器的存储路径/var/lib/mysql。这是因为,mysql的数据存储目录就是/var/lib/mysql,在mysql的容器被删除之后,我们希望数据目录仍然存在,不要跟着容器被一并删除;同样,如果容器做了修改,提交时应该也不能包含该目录,因为我们不能将业务相关的数据跟着容器中的程序一并提交。这正式Volumn存在的意义。

docker容器网络访问控制

docker容器网络放开控制默认是通过iptables来完成。以tomcat的容器为例,如下,

1
2
3
4
5
6
7
8
9
10
11
$ docker run -p 8080:8080 -d tomcat
9a1b9aca0fddeb68489c974df5d09e6093d8e774ff7db9132d8d25606643dc1f
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9a1b9aca0fdd tomcat "catalina.sh run" 4 seconds ago Up 2 seconds 0.0.0.0:8080->8080/tcp silly_jennings
$ iptables-save | grep 8080
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
-A DOCKER -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8080
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT

可以发现,对容器8080端口配置了3条iptables规则。解释这几条规则,需要先理解docker的网络,默认情况下,所有的docker容器全都运行在docker0作为虚拟路由器的子网内,一般是一个172开头的网段,与外界的连接通过NAT方式桥接。

第一条规则是,容器(172.17.0.2)访问外网时做的源地址伪装;第二条规则是,任意网络节点访问8080端口,转发到172.17.0.2:8080,这是一个由外网节点向NAT内网机节点做转发的常见配置;第3条规则是,所有通过docker0访问172.17.0.2的8080端口的数据输入,除了输入是从docker0来的,都是被允许的,这是容器所在的NAT内网访问本节点的配置,也就是容器访问容器。以上所有转发规则都使用tcp协议。

如果在docker run的时候使用了--net=host--net=container:<name|id>选项,那么容器将使用宿主机的网络,或使用另一个容器的网络。这种情况下不会产生新的iptables规则。如果使用了--net=container:<name|id>选项,在另一个容器被关闭的时候,本容器也会无法访问,即使另一个容器又重启,本容器也需要重启后才可以访问。

与iptables有关的选项在docker后台启动进程(daemon)上,--icc=true--iptables=true--icc=true表示不同容器之间是允许网络互通的,这是默认值,如果设置为false,那么只有使用--link才能实现两个容器之间的互联。如果设置了这个选项,即使设置--iptables=false也可以容器间互通,但这样是不安全的,建议设置--icc=false--iptables=true,表示通过设置iptables实现特殊的网络连接,如果设置了这个选项,在容器启动的时候就会新增iptables规则。这些选项建议放在/etc/default/docker中,

1
DOCKER_OPTS="--icc=false --iptables=true"

也可以手动启动docker后台启动进程时加上,docker daemon --icc=false --iptables=true。上述的iptables的例子就已经设置了这些选项,如果没有加这些选项的话,默认--icc=true,以上的iptables规则会不一样,如下,

1
2
3
4
$ iptables-save| grep 8080
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8080
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT

注意,只有第二条规则不一样,增加了一个条件,所有输入来源不是docker0的网络访问,转发到172.17.0.2:8080。系统会添加一个iptables的全局ACCEPT规则,这个规则不受--iptables参数影响。

docker端口映射

容器可以在启动的时候使用-p选项来增加容器内和宿主机之间的端口映射。但是默认情况下,每增加一个端口映射都会产生一个docker-proxy进程,而这样一个进程需要消耗大约10M内存。如果映射的端口过多,就会导致内存耗尽,这样的情况,无论是宿主机上有一个映射端口很多的容器,还是容器虽然映射端口很少,但宿主机上有很多个这种容器,都会发生。为了解决这个问题,docker改进了设计,将docker-proxy进程设计为非必要。可以在docker后台启动进程中加入--userland-proxy=false选项来禁止docker-proxy进程的产生4。同样这个参数可以加在后台启动进程上,也可以加在/etc/default/docker中,

1
DOCKER_OPTS="--icc=false --iptables=true --userland-proxy=false"

文章目录
  1. 1. 指定存储(Volumn)
  2. 2. docker容器网络访问控制
  3. 3. docker端口映射

欢迎来到Valleylord的博客!

本博的文章尽量原创。