利用Docker的自定义网络来管理ip绑定


Docker最近推出了docker network的功能,允许用户自己创建网络。刚好手头合租了一台服务器想试试。

这台服务器有4个公网ip(173.208.194.202,203,205,206/29)。我单独占了个173.208.194.205。我期待的效果是:这个docker network内创建的容器,默认会publish到173.208.194.205(即外界连.205:port也能访问到映射的容器);并且容器内对外connect时,默认的localaddr也是.205。

创建网络并设置默认publish IP

docker network create -o "com.docker.network.bridge.host_binding_ipv4"="173.208.194.205" htfy_net

这里的host_binding_ipv4在 https://docs.docker.com/engine/userguide/networking/work-with-networks/#linking-containers-in-user-defined-networks 的文档有提到,指的是会把默认的-p host_port:container_port转化成-p173.208.194.205:host_port:container_port

让我们看看效果,首先知道htfy_net的子网是172.18.0.0/16,然后创建一个容器172.18.0.3,-p 80:80 --network htfy_net,然后iptables -L -t nat看看怎么回事:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL (1)

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL (2)

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           (3)
MASQUERADE  tcp  --  172.18.0.3           172.18.0.3           tcp dpt:80 (4)

Chain DOCKER (2 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            173.208.194.205      tcp dpt:80 to:172.18.0.3:80 (5)

截至目前为止,外界发往173.208.194.205:80的包,会经过(1), (5)改写成到172.18.0.3的包。看起来很正常。但不幸的是,对外connect的包,在(3)的作用下会被MASQUERADE到网卡第一个IP(173.208.194.202)上,这很明显不是我们想要的。

设置默认LocalAddr

在上网查找方案时,发现了 https://github.com/docker/docker/issues/8519 ,不过似乎开发者没有明白这位同学的意图。既然这样就只有手动修改了。把MASQUERADE改成硬点IP的手动nat

iptables -t nat -R POSTROUTING 4 -s 172.18.0.0/16 -d 0.0.0.0/0 -j SNAT --to-source 173.208.194.205

之后的效果:

Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL (1)

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         
DOCKER     all  --  0.0.0.0/0            0.0.0.0/0            ADDRTYPE match dst-type LOCAL (2)

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
SNAT       all  --  172.18.0.0/16        0.0.0.0/0            to:173.208.194.205 (3')
MASQUERADE  tcp  --  172.18.0.3           172.18.0.3           tcp dpt:80 (4)

Chain DOCKER (2 references)
target     prot opt source               destination         
DNAT       tcp  --  0.0.0.0/0            173.208.194.205      tcp dpt:80 to:172.18.0.3:80 (5)

对外的包经过3’规则被改成了source=173.208.194.205,这样以后docker run --network htfy_net的所有容器都能绑定到这个.205的IP了,实现了IP隔离。