使用Pipework来手工创建Docker网络
首先启动一个不带网络的容器
ubuntu@ubuntu:~$ docker run -it --rm --net none --name testbri ubuntu:14.04 bash
root@9149d27f1306:/# ip -d link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0
在另一个终端中使用pipework创建一个网桥 br0,为容器分配一个IP地址,从容器到主机设置正确的路由。
ubuntu@ubuntu:~$ sudo pipework br0 testbri 192.168.1.10/24@192.168.1.254
[sudo] password for ubuntu:
Warning: arping not found; interface may not be immediately reachable
在容器中可以看到eth1已经开启,路由信息也配好
root@9149d27f1306:/# ip -d link show eth1
129: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 4a:81:42:00:ca:b5 brd ff:ff:ff:ff:ff:ff promiscuity 0
veth
root@9149d27f1306:/# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.1.254 0.0.0.0 UG 0 0 0 eth1
192.168.1.0 * 255.255.255.0 U 0 0 0 eth1
在主机上可以看到br0的网络
ubuntu@ubuntu:~$ ip -d link show br0
128: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 86:20:dd:61:af:e5 brd ff:ff:ff:ff:ff:ff promiscuity 0
bridge
ubuntu@ubuntu:~$ brctl show
bridge name bridge id STP enabled interfaces
br0 8000.8620dd61afe5 no veth1pl606
docker0 8000.000000000000 no
现在容器内到br0的网络是通的,但到外部还不通,因为NAT还没配置
$ sudo iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -j MASQUERADE
现在容器内部就可以跟外网通信了。
我们看一下pipework命令都做了哪些工作
* 在主机上创建网桥 br0
* 分配IP地址 192.168.1.254
* 在容器内创建接口,并分配IP192.168.1.10
* 在容器内添加路由,设置网桥 为默认网关。
接下来我们不使用pipework,使用命令一步步实现pipework的功能
* 删除已经存在的br0
ubuntu@ubuntu:~$ sudo ip link set br0 down
ubuntu@ubuntu:~$ sudo brctl delbr br0
ubuntu@ubuntu:~$ sudo brctl addbr br0
ubuntu@ubuntu:~$ sudo ip addr add 192.168.1.254/24 dev br0
ubuntu@ubuntu:~$ sudo ip link set dev br0 up
ubuntu@ubuntu:~$ sudo ip link add foo type veth peer name bar
ubuntu@ubuntu:~$ sudo brctl addif br0 foo
ubuntu@ubuntu:~$ sudo ip link set foo up
查看一下我们创建的网桥和端口
ubuntu@ubuntu:~$ ip -d link show
131: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether e2:2d:a9:0f:e1:00 brd ff:ff:ff:ff:ff:ff promiscuity 0
bridge
132: bar: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether 56:5b:ae:2d:5d:83 brd ff:ff:ff:ff:ff:ff promiscuity 0
veth
133: foo: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast master br0 state DOWN mode DEFAULT group default qlen 1000
link/ether e2:2d:a9:0f:e1:00 brd ff:ff:ff:ff:ff:ff promiscuity 1
veth
ubuntu@ubuntu:~$ brctl show
bridge name bridge id STP enabled interfaces
br0 8000.e22da90fe100 no foo
docker0 8000.000000000000 no
我们已经完成了一部分,在我们使用 --net none
启动容器时,会创建一个网络命名空间,除了loopback外没有别的设备,现在我们
想去添加接口、设置路由,我们需要找到这个命名空间的ID。Docker保存的位置是 /var/run/docker/netns
,这是一个非默认的位置,
为了让ip 工具正确运行,我们需要创建一个软链接 /var/run/docker/netns
到 /var/run/netns
,这是ip 工具查找网络命名空间的默认
位置,完成之后我们就可以列出已存在的网络命名空间,容器的命名空间ID就是容器的ID。
ubuntu@ubuntu:~$ cd /var/run
ubuntu@ubuntu:/var/run$ sudo ln -s /var/run/docker/netns netns
ubuntu@ubuntu:/var/run$ sudo ip netns
a2065be4c72e
default
ubuntu@ubuntu:/var/run$ NID=a2065be4c72e
现在我们把 bar veth放到容器的命名空间中,并配置ip和MAC地址。
ubuntu@ubuntu:~$ sudo ip link set bar netns $NID
ubuntu@ubuntu:~$ sudo ip netns exec $NID ip link set dev bar name eth1
ubuntu@ubuntu:~$ sudo ip netns exec $NID ip link set eth1 address 12:34:56:78:9a:cd
ubuntu@ubuntu:~$ sudo ip netns exec $NID ip link set eth1 up
ubuntu@ubuntu:~$ sudo ip netns exec $NID ip addr add 192.168.1.1/24 dev eth1
ubuntu@ubuntu:~$ sudo ip netns exec $NID ip route add default via 192.168.1.254
至此就完成了pipework命令所完成的工作了,现在到容器里看一下已经可以跟外部通信了。