Docker使用Linux桥接,在主机构建了一个特殊的、可定制的虚拟网络拓扑结构,Docker网桥接口路由,这个网桥接口被成为docker0。 每一个容器都被赋予一个唯一的私有IP地址,从外部的网络是不能直接连接到该私有IP。主机上的每个容器都会连接到docker0,构成一个网络,同时网桥接口docker0会连接到主机所连接的网络上。

1、查看Docker容器网络

Docker安装后自动提供了三种网络,可以使用docker network ls命令查看:

1
2
3
4
5
$~ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
50d276f46ba7   bridge    bridge    local
f7d70556f900   host      host      local
7081fbaf563c   none      null      local

2、四种网络容器原型

所有的Docker容器要符合四种原型中的一种,原型定义了一个容器如何和本地容器、主机网络进行通信,每种原型有不同的目的,隔离程度。

img

  • Closed容器,容器中进程只能访问本地回环接口,不允许任何的网络流量,容器内进程不能访问容器外的网络,容器外程序也无法连接到容器网络接口上。

docker run 命令后添加参数–net none,即可创建Closed容器:

1
2
3
4
5
6
7
8
9
$ docker run --rm --net none alpine ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    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
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: ip6tnl0@NONE: <NOARP> mtu 1452 qdisc noop state DOWN qlen 1000
    link/tunnel6 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 brd 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
  • Bridged容器 拥有两个接口:私有的本地回环接口和一个通过网桥连接主机的私有接口。Bridged容器是Docker的默认选项,可定制性最高,被认为是最佳实践。

docker run 命令忽略–net选项,或者–net 值设置为bridge,创建一个Brided容器:

1
2
$docker run --rm --net bridge alpine:latest ip addr
$docker run --rm alpine:latest ip addr

从容器中访问阿里DNS服务器:

1
2
3
4
5
6
7
8
$ docker run --rm  alpine:latest ping -w 2 223.5.5.5                                                                                                                         0 [15:36:26]
PING 223.5.5.5 (223.5.5.5): 56 data bytes
64 bytes from 223.5.5.5: seq=0 ttl=37 time=27.976 ms
64 bytes from 223.5.5.5: seq=1 ttl=37 time=31.903 ms

--- 223.5.5.5 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 27.976/29.939/31.903 ms
  • Joined

Joined容器原型隔离程度更低,这些容器共享一个网络栈,容器之间没有任何隔离。

可以使用docker run –network将两个容器进行连接,如下:第一个命令启动一个在本地回环接口监听的服务器,第二个命令连接第一个容器,并列出当前容器所有的开发端口。

1
2
3
4
5
6
7
8
9
$ docker run -d --name tudou --net none alpine:latest nc -l 127.0.0.1:4444
a72ecddb0f461720495960331c36ea29594e7986e87e8fa2f1cfff9f41468301

$ docker run -it --rm --network container:tudou alpine netstat -al
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:33957           0.0.0.0:*               LISTEN
Active UNIX domain sockets (servers and established)
Proto RefCnt Flags       Type       State         I-Node Path

当两个容器被连接,每一个接口都被共享,因此会引入端口冲突的问题。

Joined容器的使用场景

  1. 想要不同容器上的程序通过本地回环接口进行通信
  2. 一个容器中的程序将要改变Joined网络栈,而另外一个程序将要使用那个被改变的网络栈
  3. 想要监控另外一个容器中某个程序的网络流量
  • Open

Open容器非常危险。它没有网络容器,并对主机网络有完全的访问权。

docker run 命令的–net选项值为host时,就会创建Open容器:

1
$ docker run --rm --net host alpine ip addr