本文主要討論的是Docker容器(container)網路(networking)及Namespace,以下實驗參考自Sébastien Goasguen撰寫的Docker Cookbook (ISBN 978-1-491-91971-2)第三章Page76~Page80。

Understanding Docker Container Networking

在安裝Docker的過程中,默認會在宿主機上創建名爲docker0的bridge(網橋)。該bridge有相關的私有地址(private address)和子網(subnet),在本人電腦上分配的子網地址是172.17.0.1/16

docker0

[flying@lemp ~]$ ip addr show dev docker0
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:20:7a:e7:7d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:20ff:fe7a:e77d/64 scope link
       valid_lft forever preferred_lft forever
[flying@lemp ~]$

docker0 bridge的地址是172.17.0.1,所有attach到該bridge的容器得到172.17.0.1/16網絡的地址,並且將docker0 bridge的地址作爲網關(networking gateway)。

當容器被創建,Docker會創建一對同等的網路接口(network interface)分別放置在2個獨立的networking namespace中,一個在容器中(如eth0),一個在宿主機,attachdocker0 bridge

container ip

[flying@lemp ~]$ docker run -ti --rm alpine /bin/sh
/ # ip addr show eth0
87: eth0@if88: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link
       valid_lft forever preferred_lft forever

/ # ping -c 3 172.17.0.1
PING 172.17.0.1 (172.17.0.1): 56 data bytes
64 bytes from 172.17.0.1: seq=0 ttl=64 time=0.258 ms
64 bytes from 172.17.0.1: seq=1 ttl=64 time=0.173 ms
64 bytes from 172.17.0.1: seq=2 ttl=64 time=0.149 ms

--- 172.17.0.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.149/0.193/0.258 ms
/ #

在容器中可以ping通網關172.17.0.1

veth*

在宿主機開啓新Shell窗口查看

[flying@lemp ~]$ ip -d link show
...
...

6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT
    link/ether 02:42:20:7a:e7:7d brd ff:ff:ff:ff:ff:ff promiscuity 0
    bridge addrgenmode eui64
88: veth12492dd@if87: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT
    link/ether 12:40:ef:b3:12:31 brd ff:ff:ff:ff:ff:ff link-netnsid 0 promiscuity 1
    veth addrgenmode eui64
[flying@lemp ~]$

可看到有名爲veth12492dd@if87的網卡接口,關閉容器後再查看,已經沒有veth開頭的網卡。

Start another container on a separate terminal and try to ping each container. Verify that the second container interface is also attached to the bridge. Since there are no IP table rules dropping traffic, both containers can communicate with each other on any port. –page78

Choosing a Container Networking Namespace

Container Networking Namespace主要有nonehostbridgecontainer等模式,可通過docker run命令的--net具體指定。

none

容器只能與自身通信

[flying@lemp ~]$ docker run -ti --rm --net=none --name alpinenone alpine:latest  /bin/sh
/ # route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
/ # exit
[flying@lemp ~]$

只有迴環網卡lo,顯示本地地址

host

容器使用的是宿主機的網卡接口、IP

[flying@lemp ~]$ docker run -ti --rm --net=host --name alpinehost alpine:latest  /bin/sh
/ # route
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         bogon           0.0.0.0         UG    600    0        0 wlp3s0
172.17.0.0      *               255.255.0.0     U     0      0        0 docker0
192.168.0.0     *               255.255.255.0   U     600    0        0 wlp3s0
192.168.122.0   *               255.255.255.0   U     0      0        0 virbr0
/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp5s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000
    link/ether 54:04:a6:7d:65:6e brd ff:ff:ff:ff:ff:ff
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    link/ether 00:08:ca:6c:a1:2b brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.107/24 brd 192.168.0.255 scope global dynamic wlp3s0
       valid_lft 601473sec preferred_lft 601473sec
    inet6 fe80::208:caff:fe6c:a12b/64 scope link
       valid_lft forever preferred_lft forever
4: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 52:54:00:82:49:9f brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
5: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN qlen 500
    link/ether 52:54:00:82:49:9f brd ff:ff:ff:ff:ff:ff
6: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
    link/ether 02:42:20:7a:e7:7d brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:20ff:fe7a:e77d/64 scope link
       valid_lft forever preferred_lft forever
/ # ip link set wlp3s0 down
ip: ioctl 0x8914 failed: Operation not permitted
/ # exit
[flying@lemp ~]$

與宿主機相同,但在容器中默認無法關閉網卡。

使用host模式時,無法再使用-h顯式指定主機名

[flying@lemp ~]$ docker run -ti --rm --net=host -h ddddd --name alpinehost alpine:latest  /bin/sh
docker: Error response from daemon: Conflicting options: hostname and the network mode.
See 'docker run --help'.
[flying@lemp ~]$

Starting a container with --net=hostcan be dangerous, especially if you start a privileged container with --privileged=true . Host networking will allow you to change your host network configuration from within the container. If you were to run an application as root in a privileged container started with --net=host , a vulnerability of your application would let an intruder control your Docker host networking entirely. However, it can also be useful for processes that need a lot of network I/O. –page80

Container Host Name

使用-h設置主機名 * -h, --hostname: Container host name

[flying@lemp ~]$ docker run -ti --rm -h dddocker --name centos centos7:latest bash
[root@dddocker /]# hostnamectl
Failed to create bus connection: No such file or directory
[root@dddocker /]# hostname   
dddocker
[root@dddocker /]# exit
exit
[flying@lemp ~]$

Use the same network namespace

也可使用--net=container:CONTAINER_NAME_OR_ID共用network namespace

容器1

[flying@lemp ~]$ docker run -ti --rm -h dddocker --name apline1 alpine:latest /bin/sh
/ # hostname
dddocker
/ #

在新Shell窗口中進行如下操作

[flying@lemp ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
72bc168fd518        alpine:latest       "/bin/sh"           28 seconds ago      Up 25 seconds                           apline1
[flying@lemp ~]$ docker run -ti --rm --net=container:apline1 alpine:latest /bin/sh
/ # hostname
dddocker
/ #

可以看到容器2的主機名使用的是容器1的主機名

As you see, the new container has the same hostname as the first container started and of course has the same IP. The processes in each container will be isolated and exist in their own process namespace, but they share the same networking namespace and can communicate on the loopback device.

References


Change Log

  • 2016.04.15 12:31 Fri Asia/Beijing
    • 初稿完成

  • Note Time: 2016.04.15 12:31 Fri
  • Note Location: Asia/Beijing
  • Writer: lempstacker