Skip to content

Commit 23d4e36

Browse files
committed
rewrite the advanced network chapter
1 parent 424e079 commit 23d4e36

File tree

11 files changed

+130
-163
lines changed

11 files changed

+130
-163
lines changed

SUMMARY.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@
3232
* [数据卷](data_management/volume.md)
3333
* [数据卷容器](data_management/container.md)
3434
* [备份、恢复、迁移数据卷](data_management/management.md)
35-
* [网络和互联](network/README.md)
36-
* [端口映射](network/port_mapping.md)
35+
* [基本网络功能](network/README.md)
36+
* [外部访问容器](network/port_mapping.md)
3737
* [容器互联](network/linking.md)
3838
* [高级网络配置](advanced_network/README.md)
39-
* [快速配置指南](advanced_network/fast_config.md)
39+
* [快速配置指南](advanced_network/quick_guide.md)
4040
* [配置DNS](advanced_network/dns.md)
41-
* [容器之间的通信](advanced_network/communication.md)
42-
* [映射一个容器端口到宿主主机](advanced_network/port_mapping.md)
43-
* [定制docker0](advanced_network/docker0.md)
44-
* [创建自己的桥接](advanced_network/bridge.md)
45-
* [Docker 如何连接到容器](advanced_network/how_connect.md)
41+
* [容器访问控制](advanced_network/access_control.md)
42+
* [端口映射实现](advanced_network/port_mapping.md)
43+
* [配置docker0](advanced_network/docker0.md)
44+
* [自定义网桥](advanced_network/bridge.md)
4645
* [工具和示例](advanced_network/example.md)
47-
* [创建一个点到点连接](advanced_network/ptp.md)
46+
* [编辑网络配置文件](advanced_network/config_file.md)
47+
* [实例:创建一个点到点连接](advanced_network/ptp.md)
4848
* [容器安全](container_security/README.md)
4949
* [内核名字空间](container_security/kernel_ns.md)
5050
* [控制组](container_security/control_group.md)

advanced_network/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
当创建一个Docker容器的时候,同时会创建了一对`veth pair`接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即`eth0`;另一端在本地并被挂载到`docker0`网桥,名称以`veth`开头(例如`vethAQI2QT`)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker就创建了在主机和所有容器之间一个虚拟共享网络。
99

10-
1110
![Docker网络](../_images/network.png)
1211

1312
接下来的部分将介绍在一些场景中,docker所有的网络定制配置。linux的原生命令将调整、补充、甚至替换docker默认的网络配置。

advanced_network/access_control.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
## 容器访问控制
2+
容器的访问控制,主要通过Linux上的`iptables`防火墙来进行管理和实现。`iptables`是Linux上默认的防火墙软件,在大部分发行版中都自带。
3+
4+
### 容器访问外部网络
5+
容器要想访问外部网络,需要本地系统的转发支持。在Linux系统中,检查转发是否打开。
6+
7+
```
8+
$sysctl net.ipv4.ip_forward
9+
net.ipv4.ip_forward = 1
10+
```
11+
如果为0,说明没有开启转发,则需要手动打开。
12+
```
13+
$sysctl -w net.ipv4.ip_forward=1
14+
```
15+
如果在启动Docker服务的时候设定`--ip-forward=true`, Docker就会自动设定系统的`ip_forward`参数为1。
16+
17+
### 容器之间访问
18+
容器之间相互访问,需要两方面的支持。
19+
* 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到`docker0`网桥上。
20+
* 本地系统的防火墙软件 -- `iptables`是否允许通过。
21+
22+
#### 访问所有端口
23+
当启动Docker服务时候,默认会添加一条转发策略到iptables的FORWARD链上。策略为通过(`ACCEPT`)还是禁止(`DROP`)取决于配置`--icc=true`(缺省值)还是`--icc=false`。当然,如果手动指定`--iptables=false`则不会添加`iptables`规则。
24+
25+
可见,默认情况下,不同容器之间是允许网络相互访问的。如果为了安全考虑,可以在`/etc/default/docker`文件中配置`DOCKER_OPTS=--icc=false`来禁止它。
26+
27+
#### 访问指定端口
28+
在通过`-icc=false`关闭网络访问后,还可以通过`--link=CONTAINER_NAME:ALIAS`选项来访问容器的开放端口。
29+
30+
例如,在启动Docker服务时,可以同时使用`icc=false --iptables=true`2个参数来关闭允许相互的网络访问,并让Docker可以修改系统中的`iptables`规则。
31+
32+
此时,系统中的`iptables`规则可能是类似
33+
```
34+
$ sudo iptables -nL
35+
...
36+
Chain FORWARD (policy ACCEPT)
37+
target prot opt source destination
38+
DROP all -- 0.0.0.0/0 0.0.0.0/0
39+
...
40+
```
41+
42+
之后,启动容器(`docker run`)时使用`--link=CONTAINER_NAME:ALIAS`选项。docker会在`iptable`中为2个容器分别添加一条`ACCEPT`规则,允许相互访问开放的端口(取决于dockerfile中的EXPOSE行)。
43+
44+
当添加了`--link=CONTAINER_NAME:ALIAS`选项后,添加了`iptables`规则。
45+
```
46+
$ sudo iptables -nL
47+
...
48+
Chain FORWARD (policy ACCEPT)
49+
target prot opt source destination
50+
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
51+
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80
52+
DROP all -- 0.0.0.0/0 0.0.0.0/0
53+
```
54+
55+
注意:`--link=CONTAINER_NAME:ALIAS`中的`CONTAINER_NAME`目前必须是Docker分配的名字,或使用`--name`参数指定的名字。主机名则不会被识别。

advanced_network/bridge.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
1-
##创建自己的桥接
2-
如果希望完全使用自己的桥接设置,可以在启动docker服务的时候,使用 -b BRIDGE or --bridge=BRIDGE 来告诉docker使用你的网桥。如果服务已经启动,旧的网桥还在使用中,那需要先停止服务,再删除旧的网桥
1+
##自定义网桥
2+
除了默认的`docker0`网桥,用户也可以指定网桥来连接各个容器。
3+
4+
在启动Docker服务的时候,使用`-b BRIDGE``--bridge=BRIDGE`来指定使用的网桥。
5+
6+
如果服务已经运行,那需要先停止服务,并删除旧的网桥。
37
```
4-
#停止旧网桥并删除
58
$ sudo service docker stop
69
$ sudo ip link set dev docker0 down
710
$ sudo brctl delbr docker0
811
```
9-
然后在开启服务前,创建你自己希望的网桥接口,这里建立一个网桥的配置:
12+
然后创建一个网桥`bridge0`
1013
```
11-
# 创建自己的网桥
1214
$ sudo brctl addbr bridge0
1315
$ sudo ip addr add 192.168.5.1/24 dev bridge0
1416
$ sudo ip link set dev bridge0 up
1517
```
18+
查看确认网桥创建并启动。
1619
```
17-
# 确认网桥启动
1820
$ ip addr show bridge0
1921
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
2022
link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
2123
inet 192.168.5.1/24 scope global bridge0
2224
valid_lft forever preferred_lft forever
2325
```
24-
26+
配置Docker服务,默认桥接到创建的网桥上。
2527
```
26-
# 告诉docker桥接设置,并启动docker服务(在ubuntu上)
2728
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
2829
$ sudo service docker start
2930
```
30-
docker服务启动成功并绑定容器到新的网桥,新建一个容器,你会看到它的ip是我们的设置的新ip段,docker会自动检测到它。用brctl
31-
show可以看到容器启动或则停止后网桥的配置变化,在容器中使用```ip addr``````ip route```来查看ip地址配置和路由信息。
31+
启动Docker服务。
32+
新建一个容器,可以看到它已经桥接到了`bridge0`上。
33+
34+
可以继续用`brctl show`命令查看桥接的信息。另外,在容器中可以使用`ip addr``ip route`命令来查看ip地址配置和路由信息。

advanced_network/communication.md

Lines changed: 0 additions & 41 deletions
This file was deleted.

advanced_network/docker0.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
1-
##定制docker0
2-
docker服务默认会创建一个docker0接口,它在linux内核层桥接所有物理或虚拟网卡,这就将所有容器和主机接口都放到同一个物理网络。
3-
Docker指定了docker0的ip地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了MTU-接口允许接收的最大传输单元,通常是1500bytes或宿主主机网络路由上支持的默认值,这2个都需要在服务启动的时候配置。
4-
* --bip=CIDR — 192.168.1.5/24.ip地址加掩码 使用这种格式
5-
* --mtu=BYTES — 覆盖默认的docker mtu配置
1+
##配置docker0
2+
Docker服务默认会创建一个`docker0`接口,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
63

7-
你可以在配置文件中配置DOCKER_OPTS,然后重启来改变这些参数。
4+
Docker默认指定了`docker0`的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了MTU(接口允许接收的最大传输单元),通常是1500bytes,或宿主主机网络路由上支持的默认值,这2个都可以在服务启动的时候进行配置。
5+
* --bip=CIDR -- IP地址加掩码格式,例如192.168.1.5/24
6+
* --mtu=BYTES -- 覆盖默认的Docker mtu配置
7+
8+
也可以在配置文件中配置DOCKER_OPTS,然后重启服务。
9+
由于目前Docker网桥是Linux网桥,用户可以使用`brctl show`来查看网桥和端口连接信息。
810
```
9-
# 当容器启动后,你可以使用brctl来确认他们是否已经连接到docker0网桥
1011
$ sudo brctl show
1112
bridge name bridge id STP enabled interfaces
1213
docker0 8000.3a1d7362b4ee no veth65f9
1314
vethdda6
14-
```
15-
如果brctl命令没安装的话,在ubuntu中你可以使用apt-get install bridge-utils这个命令来安装
16-
docker0 网桥设置会在每次创建新容器的时候被使用。docker从可用的地址段中选择一个空闲的ip地址给容器的eth0端口,子网掩码使用网桥docker0的配置,docker主机本身的ip作为容器的网关使用。
15+
```
16+
注:`brctl`命令在Debian、Ubuntu中可以使用`sudo apt-get install bridge-utils`来安装。
17+
18+
19+
每次创建一个新容器的时候,Docker从可用的地址段中选择一个空闲的ip地址分配给容器的eth0端口。Docker主机上接口`docker0`的IP作为所有容器的默认网关。
1720
```
1821
$ sudo docker run -i -t --rm base /bin/bash
1922
$ ip addr show eth0
@@ -28,4 +31,3 @@ default via 172.17.42.1 dev eth0
2831
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
2932
$ exit
3033
```
31-
转发数据包需要在主机上设定ip_forward参数为1,上文介绍过。

advanced_network/example.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
##工具和示例
22
在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣:
3-
https://github.com/jpetazzo/pipework
4-
Jérôme Petazzoni 创建了一个叫pipework的shell脚本来帮助我们在复杂的场景中完成网络连接
53

6-
https://github.com/brandon-rhodes/fopnp/tree/m/playground
7-
Brandon Rhodes创建了一个完整的docker容器网络拓扑,包含 nat 防火墙,服务包括HTTP, SMTP, POP, IMAP, Telnet, SSH, and FTP:
8-
工具使用的网络命令跟之前看到非常相似。
4+
### pipework
5+
Jérôme Petazzoni编写了一个叫[pipework](https://github.com/jpetazzo/pipework)的shell脚本,可以帮助用户在比较复杂的场景中完成容器的连接。
6+
7+
### playground
8+
Brandon Rhodes创建了一个提供完整的Docker容器网络拓扑管理的[Python库](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT防火墙;以及一些提供HTTP, SMTP, POP, IMAP, Telnet, SSH, FTP的服务器。

advanced_network/how_connect.md

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1 @@
1-
##Docker 如何连接到容器?
21

3-
让我们回顾一些基础知识:
4-
机器需要一个网络接口来发送和接受数据包,路由表来定义如何到达哪些地址段。这里的网络接口可以不是物理接口。
5-
6-
事实上,每个linxu机器上的lo环回接口(Docker 容器中也有)就是一个完整的linux内核虚拟接口,它直接复制发送缓存中的数据包到接收缓存中。Docker让宿主主机和容器使用特殊的虚拟接口来通信--通信的2端叫“peers“,他们在主机内核中连接在一起,所以能够相互通信。创建他们很简单,前面介绍过了。
7-
8-
docker创建容器的步骤如下:
9-
* 创建一对虚拟接口
10-
* 其中宿主主机一端使用一个名字比如veth65f9,他是唯一的,另外一端桥接到默认的docker0,或其它你指定的桥接网卡。
11-
* 主机上的veth65f9这种接口映射到新的新容器中的名称通常是eth0,在容器这个隔离的network namespace
12-
中,它是唯一的,不会有其他接口名字和它冲突。
13-
* 从主机桥接网卡的地址段中获取一个空闲地址给eth0使用,并设定默认路由到桥接网卡。
14-
* 完成这些之后,容器就可以使用这eth0虚拟网卡来连接其他容器和其他网络。
15-
16-
你也可以为特殊的容器设定特定的参数,在docker run的时候使用--net,它有4个可选参数:
17-
* --net=bridge — .默认连接到docker0网桥。
18-
* --net=host — 告诉docker不要将容器放到隔离的网络堆栈中。从本质上讲,这个选项告诉docker
19-
不要容器化容器的网络!尽管容器还是有自己的文件系统、进程列表和资源限制。但使用ip addr命令这样命令就可以知道实际上此时的的容器处于和docker 宿主主机的一样的网络级别,它拥有完全的宿主主机接口访问权限。虽然它不允许容器重新配置主机的网络堆栈,除非--privileged=true — 但是容器进程可以跟其他root进程一样可以打开低数字的端口,可以访问本地网络服务比如D-bus,还可以让容器做一些意想不到的事情,比如重启主机,使用这个选项的时候要非常小心!
20-
* --net=container:NAME_or_ID
21-
告诉docker将新容器的进程放到一个已经存在的容器的网络堆栈中,新容器进程有它自己的文件系统、进程列表和资源限制,但它会和那个已经存在的容器共享ip地址和端口,他们之间来可以通过环回接口通信。
22-
* --net=none — 告诉docker将新容器放到自己的网络堆栈中,但是不要配置它的网络,
23-
类似于vmware的host-only。这可以让你创建任何自定义的配置,本文最后一段将介绍 他们。
24-
25-
下面通过配置一个以--net=none启动的容器,使他达到跟平常一样具有访问网络的权限。来介绍docker是如何连接到容器中的。
26-
27-
启动一个/bin/bash 指定--net=none
28-
```
29-
$ sudo docker run -i -t --rm --net=none base /bin/bash
30-
root@63f36fc01b5f:/#
31-
```
32-
再开启一个新的终端,查找这个容器的进程id,然后创建它的命名空间,后面的ip netns会用到
33-
```
34-
$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
35-
2778
36-
$ pid=2778
37-
$ sudo mkdir -p /var/run/netns
38-
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
39-
```
40-
检查桥接网卡的ip和子网掩码
41-
```
42-
$ ip addr show docker0
43-
21: docker0: ...
44-
inet 172.17.42.1/16 scope global docker0
45-
...
46-
```
47-
创建一对”peer“接口A和B,绑定A到网桥,并启用它
48-
```
49-
$ sudo ip link add A type veth peer name B
50-
$ sudo brctl addif docker0 A
51-
$ sudo ip link set A up
52-
```
53-
将B放到容器的网络命名空间,命名为eth0,配置一个空闲的ip
54-
```
55-
$ sudo ip link set B netns $pid
56-
$ sudo ip netns exec $pid ip link set dev B name eth0
57-
$ sudo ip netns exec $pid ip link set eth0 up
58-
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
59-
$ sudo ip netns exec $pid ip route add default via 172.17.42.1
60-
```
61-
自此,你又可以像平常一样使用网络了
62-
当你退出shell后,docker清空容器,容器的eth0随网络命名空间一起被摧毁,A 接口也被自动从docker0取消注册。不用其他命令,所有东西都被清理掉了!
63-
注意ip netns exec命令,它可以让我们像root一样配置网络命名空间。但在容器内部无法使用,因为统一的安全策略,docker限制容器进程配置自己的网络。使用ip netns exec 可以让我们不用设置--privileged=true就可以完成一些可能带来危险的操作。

0 commit comments

Comments
 (0)