引言

docker 是一个非常方便的工具,在在使用过程中,需要使用一些网络相关的信息。找了一些资料,在这里做点笔记。

docker网络模式

docker网络有四种模式:桥模式、主机模式、容器模式和无网络模式。

bridge 模式网络

在桥模式中,Docker守护进程创建一个虚拟网卡,附加在其上的任何网卡之间都能自动转发数据包。默认情况下,守护进程会创建一对对等接口,将其中一个接口设置为容器的eth0接口,另一个接口放置在宿主机的命名空间中,从而将宿主机上的所有容器都连接到这个内部网络上。同时,守护进程还会从网桥的私有地址空间中分配一个IP地址和子网给该容器。

1
2
3
4
5
6
$ docker run -d -P --net=bridge nginx:1.9.1
$ docker ps
CONTAINER ID   IMAGE                  COMMAND    CREATED
STATUS         PORTS                  NAMES
17d447b7425d   nginx:1.9.1            nginx -g   19 seconds ago
Up 18 seconds  0.0.0.0:49153->443/tcp, 0.0.0.0:49154->80/tcp  trusting_feynman

因为bridge模式是Docker的默认设置,所以你也可以使用docker run -d -P nginx:1.9.1。如果你没有使用-P(发布该容器暴露的所有端口)或者-p host_port:container_port(发布某个特定端口),IP数据包就不能从宿主机之外路由到容器中。

{% asset_img bridge-mode.png breige %}

host模式网络

该模式将禁用Docker容器的网络隔离。因为容器共享了宿主机的网络命名空间,直接暴露在公共网络中。因此,你需要通过端口映射(port mapping)来进行协调。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
$ docker run -dit --rm -net=host --name=testnet  centos:7

$ ip addr | grep -A 2 eth0:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:c6:38:28 brd ff:ff:ff:ff:ff:ff
    inet 172.27.16.10/20 brd 172.27.31.255 scope global eth0

$ docker exec -it testnet bash
# apt-get update
# apt-get install iproute2
# ip addr | grep -A 2 eth0:
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:c6:38:28 brd ff:ff:ff:ff:ff:ff
    inet 172.27.16.10/20 brd 172.27.31.255 scope global eth0

我们可以从上例中看到:容器和宿主机具有相同的IP地址 172.27.16.10

在下图中,我们可以看到:当使用host模式网络时,容器实际上继承了宿主机的IP地址。该模式比bridge模式更快(因为没有路由开销),但是它将容器直接暴露在公共网络中,是有安全隐患的。

{% asset_img host-mode.png host %}

container模式网络

该模式会重用另一个容器的网络命名空间。通常来说,当你想要自定义网络栈时,该模式是很有用的。实际上,该模式也是Kubernetes使用的网络模式。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 $ docker run -dit --rm --net=bridge --name=testnet ubuntu:16.04 
 $ docker exec -it testnet bash 
 # apt-get update
# apt-get install iproute2
# ip addr 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
290: eth0@if291: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

$ docker run -dit --rm --net=container:testnet --name=testnet2 ubuntu:16.04 
$ docker exec -it testnet2 bash
# apt-get update
# apt-get install iproute2
# ip addr 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    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
290: eth0@if291: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

结果(上面的例子)显示:第二个容器使用了--net=container 参数,因此和第一个容器 testnet具有相同的IP地址172.17.0.2

none模式网络

该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。实际上,该模式关闭了容器的网络功能,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务);你希望自定义网络,在第3章中有很多选项使用了该模式。

使用固定IP

使用固定IP可以自己先创建一个 bridge 的网卡,然后启动的时候指定网卡和IP(默认的网卡不能指定IP启动)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$  docker network create \
  --driver=bridge \
  --subnet=172.28.0.0/16 \
  --ip-range=172.28.5.0/24 \
  --gateway=172.28.5.254 \
  br0

# subnet 创建子网 , ip-range IP地址池 
# 172.28.0.0/16 地址范围是 172.28.0.1 到 172.28.255.254 
# 172.28.5.0/24 地址范围是 172.28.5.1 到 172.28.5.254

可以通过站长工具 进行IP的计算

参考资料