Docker 如何使容器连接到网络docker是正在发展中的,并会持续提升网络配置的逻辑。当前命令行是很难满足docker新建容器时所需要的网络配置。 让我们回顾一些基础知识。 通讯的时候使用网际协议(IP),一个机器需要访问至少一个网络接口用来发送和接收包,路由表定义了通过接口可达IP地址范围。网络接口不一定非是物理设备。实际上,在每一个Linux机器(和每个Docker容器内部)的lo回环接口都是有效的而且完全是虚拟的——Linux内核简单地拷贝回环(数据)包,直接从发送者的内存放入接收者的内存。 Docker使用特殊的虚拟接口让容器在主机间通讯——成对的虚拟接口被叫做“peers”,它被链接到主机内核的内部,因此(数据)包能在他们之间传输。他们简单创建,待会儿我们将会看到。 Docker配置容器的步骤是: 1.创建一对虚拟接口 2.在主Docker主机内部给它一个唯一的名称,比如veth65f9,绑定它到docker0或者Docker使用的任何网桥上 3.让其他的接口翻墙进入新的容器(已经提供了lo接口),在容器的独立和唯一网络接口命名空间内,重新命名它为更漂亮的名字eth0,名称不要和其他的物理接口冲突。 4.在网桥的网络地址访问内给容器的eth0一个新的IP地址,设置它的缺省路由为Docker主机在网桥上拥有的IP地址。 这些步骤结束后,容器将立即拥有一个eth0(虚拟)网卡,并会发现它自己可以和其他的容器以及互联网通讯。 你可以使用 --net= 这个选项来执行 docker run 启动一个容器,这个选项有一下可选参数。
去了解以下这一步是非常必要的,如果你在建立容器的时候使用 --net=none 这个选项参数。以下是一些命令去去配置自定义网络,就好像你让docker完全去自己配置一样。 # At one shell, start a container and# leave its shell idle and running$ sudo docker run -i -t --rm --net=none base /bin/bash root@63f36fc01b5f:/# # At another shell, learn the container process ID # and create its namespace entry in /var/run/netns/# for the "ip netns" command we will be using below$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f2778$ pid=2778$ sudo mkdir -p /var/run/netns $ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid# Check the bridge's IP address and netmask$ ip addr show docker021: docker0: ...inet 172.17.42.1/16 scope global docker0...# Create a pair of "peer" interfaces A and B,# bind the A end to the bridge, and bring it up$ sudo ip link add A type veth peer name B $ sudo brctl addif docker0 A $ sudo ip link set A up# Place B inside the container's network namespace,# rename to eth0, and activate it with a free IP$ sudo ip link set B netns $pid $ sudo ip netns exec $pid ip link set dev B name eth0 $ sudo ip netns exec $pid ip link set eth0 up $ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0 $ sudo ip netns exec $pid ip route add default via 172.17.42.1 到这一步你的容器应该可以正常运行网络操作了。 当你最后退出shell以及清理掉这个容器的时候,这个容器的虚拟网络 eth0 将在网络接口A 被清除后被消除,也会自动在网桥 docker0 上销毁。所以不用你执行其他的命令,所有的东西将被清理。当然,是几乎所有的东西: # Clean up dangling symlinks in /var/run/netnsfind -L /var/run/netns -type l -delete 还要注意上面的脚本使用了现代的ip命令行替代旧的弃用的封装,类似ipconfig和route,这些老的命令行还是会一直呆在我们的容器内部工作。如果你很忙碌的话,ip addr命令行也可以只键入ip a。 总之,注意这个ip netns exec重要的命令行,它让我们以root用户进入内部并配置一个网络命名空间。如果在容器内部运行,类似的命令行可能不会工作,因为安全容器化的部分是Docker剥离容器的处理过程,这个过程要正确地配置自己的网络。使用ip netns exec可以让我们完成配置,还避免了运行容器自身--privileged=true的危险步骤。 工具和实例在把自定义网络拓扑逻辑分类成下面几个部分之前,你应该关注一些外部工具盒关于配置的实例。下面就有两个例子:
两个工具都使用网络命令并和之前见到的版本很相似,在下面章节会看到。 建立点对点连接缺省情况下, Docker通过docker0将所有的容器添加到虚拟子网中。你能够按照Building your own bridge中的方法创建你自己的桥让容器连接到不同的虚拟子网。启动容器时使用命令docker run --net=none,然后使用shell命令添加容器到你自己的桥,方法见How Docker networks a container。 但是有时你想让两个特别的容器能够直接通讯,不用绑定到主机的以太网桥上。 解决方案是简单的。创建一对对等接口,将他们放到容器中,并将其配置为经典的点对点链接。两个容器就能够直接通讯了(当然要告诉每个容器对方的IP地址)。您可能会调整在上一节的指示去这样的事情: # Start up two containers in two terminal windows$ sudo docker run -i -t --rm --net=none base /bin/bash root@1f1f4c1f931a:/# $ sudo docker run -i -t --rm --net=none base /bin/bash root@12e343489d2f:/# # Learn the container process IDs # and create their namespace entries $ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a 2989 $ sudo docker inspect -f '{{.State.Pid}}' 12e343489d2f 3004 $ sudo mkdir -p /var/run/netns $ sudo ln -s /proc/2989/ns/net /var/run/netns/2989$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004# Create the "peer" interfaces and hand them out$ sudo ip link add A type veth peer name B $ sudo ip link set A netns 2989$ sudo ip netns exec 2989 ip addr add 10.1.1.1/32 dev A $ sudo ip netns exec 2989 ip link set A up $ sudo ip netns exec 2989 ip route add 10.1.1.2/32 dev A $ sudo ip link set B netns 3004$ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B $ sudo ip netns exec 3004 ip link set B up $ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B 两个容器应该可以相互ping通以确定连接成功。点对点链接不依赖于子网或子网掩码,但是ip route需要确认一些其他的单一IP地址是连接到了特定的网络接口。 请注意点对点链接可以安全的和其他类型的网络连接混合使用。如果你想用点对点链接替换容器的正常网络连接,启动的时候,不需要带参数--net=none。 在Docker主机和容器之间创建点对点链接是这个模板最终的排列方式,它允许主机和有单一IP地址的容器通讯。除非你有很特别的网络需求,让你尝试使用这样的解决方案,正如我们前面探讨的,使用--icc=false锁定跨容器的通讯是更好的方案。 |