mirror of
https://github.com/yeasy/docker_practice.git
synced 2024-12-25 14:38:54 +00:00
rewrite the advanced network chapter
This commit is contained in:
parent
424e07993e
commit
23d4e36c64
18
SUMMARY.md
18
SUMMARY.md
@ -32,19 +32,19 @@
|
|||||||
* [数据卷](data_management/volume.md)
|
* [数据卷](data_management/volume.md)
|
||||||
* [数据卷容器](data_management/container.md)
|
* [数据卷容器](data_management/container.md)
|
||||||
* [备份、恢复、迁移数据卷](data_management/management.md)
|
* [备份、恢复、迁移数据卷](data_management/management.md)
|
||||||
* [网络和互联](network/README.md)
|
* [基本网络功能](network/README.md)
|
||||||
* [端口映射](network/port_mapping.md)
|
* [外部访问容器](network/port_mapping.md)
|
||||||
* [容器互联](network/linking.md)
|
* [容器互联](network/linking.md)
|
||||||
* [高级网络配置](advanced_network/README.md)
|
* [高级网络配置](advanced_network/README.md)
|
||||||
* [快速配置指南](advanced_network/fast_config.md)
|
* [快速配置指南](advanced_network/quick_guide.md)
|
||||||
* [配置DNS](advanced_network/dns.md)
|
* [配置DNS](advanced_network/dns.md)
|
||||||
* [容器之间的通信](advanced_network/communication.md)
|
* [容器访问控制](advanced_network/access_control.md)
|
||||||
* [映射一个容器端口到宿主主机](advanced_network/port_mapping.md)
|
* [端口映射实现](advanced_network/port_mapping.md)
|
||||||
* [定制docker0](advanced_network/docker0.md)
|
* [配置docker0](advanced_network/docker0.md)
|
||||||
* [创建自己的桥接](advanced_network/bridge.md)
|
* [自定义网桥](advanced_network/bridge.md)
|
||||||
* [Docker 如何连接到容器](advanced_network/how_connect.md)
|
|
||||||
* [工具和示例](advanced_network/example.md)
|
* [工具和示例](advanced_network/example.md)
|
||||||
* [创建一个点到点连接](advanced_network/ptp.md)
|
* [编辑网络配置文件](advanced_network/config_file.md)
|
||||||
|
* [实例:创建一个点到点连接](advanced_network/ptp.md)
|
||||||
* [容器安全](container_security/README.md)
|
* [容器安全](container_security/README.md)
|
||||||
* [内核名字空间](container_security/kernel_ns.md)
|
* [内核名字空间](container_security/kernel_ns.md)
|
||||||
* [控制组](container_security/control_group.md)
|
* [控制组](container_security/control_group.md)
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
当创建一个Docker容器的时候,同时会创建了一对`veth pair`接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即`eth0`;另一端在本地并被挂载到`docker0`网桥,名称以`veth`开头(例如`vethAQI2QT`)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker就创建了在主机和所有容器之间一个虚拟共享网络。
|
当创建一个Docker容器的时候,同时会创建了一对`veth pair`接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包)。这对接口一端在容器内,即`eth0`;另一端在本地并被挂载到`docker0`网桥,名称以`veth`开头(例如`vethAQI2QT`)。通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。Docker就创建了在主机和所有容器之间一个虚拟共享网络。
|
||||||
|
|
||||||
|
|
||||||
![Docker网络](../_images/network.png)
|
![Docker网络](../_images/network.png)
|
||||||
|
|
||||||
接下来的部分将介绍在一些场景中,docker所有的网络定制配置。linux的原生命令将调整、补充、甚至替换docker默认的网络配置。
|
接下来的部分将介绍在一些场景中,docker所有的网络定制配置。linux的原生命令将调整、补充、甚至替换docker默认的网络配置。
|
||||||
|
55
advanced_network/access_control.md
Normal file
55
advanced_network/access_control.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
## 容器访问控制
|
||||||
|
容器的访问控制,主要通过Linux上的`iptables`防火墙来进行管理和实现。`iptables`是Linux上默认的防火墙软件,在大部分发行版中都自带。
|
||||||
|
|
||||||
|
### 容器访问外部网络
|
||||||
|
容器要想访问外部网络,需要本地系统的转发支持。在Linux系统中,检查转发是否打开。
|
||||||
|
|
||||||
|
```
|
||||||
|
$sysctl net.ipv4.ip_forward
|
||||||
|
net.ipv4.ip_forward = 1
|
||||||
|
```
|
||||||
|
如果为0,说明没有开启转发,则需要手动打开。
|
||||||
|
```
|
||||||
|
$sysctl -w net.ipv4.ip_forward=1
|
||||||
|
```
|
||||||
|
如果在启动Docker服务的时候设定`--ip-forward=true`, Docker就会自动设定系统的`ip_forward`参数为1。
|
||||||
|
|
||||||
|
### 容器之间访问
|
||||||
|
容器之间相互访问,需要两方面的支持。
|
||||||
|
* 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到`docker0`网桥上。
|
||||||
|
* 本地系统的防火墙软件 -- `iptables`是否允许通过。
|
||||||
|
|
||||||
|
#### 访问所有端口
|
||||||
|
当启动Docker服务时候,默认会添加一条转发策略到iptables的FORWARD链上。策略为通过(`ACCEPT`)还是禁止(`DROP`)取决于配置`--icc=true`(缺省值)还是`--icc=false`。当然,如果手动指定`--iptables=false`则不会添加`iptables`规则。
|
||||||
|
|
||||||
|
可见,默认情况下,不同容器之间是允许网络相互访问的。如果为了安全考虑,可以在`/etc/default/docker`文件中配置`DOCKER_OPTS=--icc=false`来禁止它。
|
||||||
|
|
||||||
|
#### 访问指定端口
|
||||||
|
在通过`-icc=false`关闭网络访问后,还可以通过`--link=CONTAINER_NAME:ALIAS`选项来访问容器的开放端口。
|
||||||
|
|
||||||
|
例如,在启动Docker服务时,可以同时使用`icc=false --iptables=true`2个参数来关闭允许相互的网络访问,并让Docker可以修改系统中的`iptables`规则。
|
||||||
|
|
||||||
|
此时,系统中的`iptables`规则可能是类似
|
||||||
|
```
|
||||||
|
$ sudo iptables -nL
|
||||||
|
...
|
||||||
|
Chain FORWARD (policy ACCEPT)
|
||||||
|
target prot opt source destination
|
||||||
|
DROP all -- 0.0.0.0/0 0.0.0.0/0
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
之后,启动容器(`docker run`)时使用`--link=CONTAINER_NAME:ALIAS`选项。docker会在`iptable`中为2个容器分别添加一条`ACCEPT`规则,允许相互访问开放的端口(取决于dockerfile中的EXPOSE行)。
|
||||||
|
|
||||||
|
当添加了`--link=CONTAINER_NAME:ALIAS`选项后,添加了`iptables`规则。
|
||||||
|
```
|
||||||
|
$ sudo iptables -nL
|
||||||
|
...
|
||||||
|
Chain FORWARD (policy ACCEPT)
|
||||||
|
target prot opt source destination
|
||||||
|
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
|
||||||
|
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80
|
||||||
|
DROP all -- 0.0.0.0/0 0.0.0.0/0
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:`--link=CONTAINER_NAME:ALIAS`中的`CONTAINER_NAME`目前必须是Docker分配的名字,或使用`--name`参数指定的名字。主机名则不会被识别。
|
@ -1,31 +1,34 @@
|
|||||||
##创建自己的桥接
|
##自定义网桥
|
||||||
如果希望完全使用自己的桥接设置,可以在启动docker服务的时候,使用 -b BRIDGE or --bridge=BRIDGE 来告诉docker使用你的网桥。如果服务已经启动,旧的网桥还在使用中,那需要先停止服务,再删除旧的网桥
|
除了默认的`docker0`网桥,用户也可以指定网桥来连接各个容器。
|
||||||
|
|
||||||
|
在启动Docker服务的时候,使用`-b BRIDGE`或`--bridge=BRIDGE`来指定使用的网桥。
|
||||||
|
|
||||||
|
如果服务已经运行,那需要先停止服务,并删除旧的网桥。
|
||||||
```
|
```
|
||||||
#停止旧网桥并删除
|
|
||||||
$ sudo service docker stop
|
$ sudo service docker stop
|
||||||
$ sudo ip link set dev docker0 down
|
$ sudo ip link set dev docker0 down
|
||||||
$ sudo brctl delbr docker0
|
$ sudo brctl delbr docker0
|
||||||
```
|
```
|
||||||
然后在开启服务前,创建你自己希望的网桥接口,这里建立一个网桥的配置:
|
然后创建一个网桥`bridge0`。
|
||||||
```
|
```
|
||||||
# 创建自己的网桥
|
|
||||||
$ sudo brctl addbr bridge0
|
$ sudo brctl addbr bridge0
|
||||||
$ sudo ip addr add 192.168.5.1/24 dev bridge0
|
$ sudo ip addr add 192.168.5.1/24 dev bridge0
|
||||||
$ sudo ip link set dev bridge0 up
|
$ sudo ip link set dev bridge0 up
|
||||||
```
|
```
|
||||||
|
查看确认网桥创建并启动。
|
||||||
```
|
```
|
||||||
# 确认网桥启动
|
|
||||||
$ ip addr show bridge0
|
$ ip addr show bridge0
|
||||||
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
|
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
|
||||||
link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
|
link/ether 66:38:d0:0d:76:18 brd ff:ff:ff:ff:ff:ff
|
||||||
inet 192.168.5.1/24 scope global bridge0
|
inet 192.168.5.1/24 scope global bridge0
|
||||||
valid_lft forever preferred_lft forever
|
valid_lft forever preferred_lft forever
|
||||||
```
|
```
|
||||||
|
配置Docker服务,默认桥接到创建的网桥上。
|
||||||
```
|
```
|
||||||
# 告诉docker桥接设置,并启动docker服务(在ubuntu上)
|
|
||||||
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
|
$ echo 'DOCKER_OPTS="-b=bridge0"' >> /etc/default/docker
|
||||||
$ sudo service docker start
|
$ sudo service docker start
|
||||||
```
|
```
|
||||||
docker服务启动成功并绑定容器到新的网桥,新建一个容器,你会看到它的ip是我们的设置的新ip段,docker会自动检测到它。用brctl
|
启动Docker服务。
|
||||||
show可以看到容器启动或则停止后网桥的配置变化,在容器中使用```ip addr```和```ip route```来查看ip地址配置和路由信息。
|
新建一个容器,可以看到它已经桥接到了`bridge0`上。
|
||||||
|
|
||||||
|
可以继续用`brctl show`命令查看桥接的信息。另外,在容器中可以使用`ip addr`和`ip route`命令来查看ip地址配置和路由信息。
|
||||||
|
@ -1,41 +0,0 @@
|
|||||||
##容器之间的通信
|
|
||||||
判断2个容器之间是否能够通信,在操作系统层面,取决于3个因素:
|
|
||||||
* 网络拓扑是否连接到容器的网络接口?默认docker会将所有的容器连接到docker0这网桥来提供数据包通信。其他拓扑结构将在稍后的文档中详细介绍。
|
|
||||||
* 主机是否开启ip转发,ip_forward参数为1的时候可以提供数据包转发。通常你只需要为docker 设定 --ip-forward=true,
|
|
||||||
docker 就会在服务启动的时候设定ip_forward参数为1。
|
|
||||||
|
|
||||||
下面是手工检查并手工设定该参数的方法。
|
|
||||||
```
|
|
||||||
# Usually not necessary: turning on forwarding,
|
|
||||||
# on the host where your Docker server is running
|
|
||||||
$ cat /proc/sys/net/ipv4/ip_forward
|
|
||||||
0
|
|
||||||
$ sudo echo 1 > /proc/sys/net/ipv4/ip_forward
|
|
||||||
$ cat /proc/sys/net/ipv4/ip_forward
|
|
||||||
1
|
|
||||||
```
|
|
||||||
*你的iptables是否允许这条特殊的连接被建立?当docker的设定--iptables=false时,docker不会改变系统的iptables
|
|
||||||
设定,否则它会在--icc=true的时候添加一条默认的ACCEPT策略到 FORWARD链,当—icc=false时,策略为DROP。几乎所有的人都会开启ip_forward来启用容器间的通信。但是否要改变icc-true配置是一个战略问题。这样iptable就可以防止其他被感染容器对宿主主机的恶意端口扫描和访问。
|
|
||||||
当你选择更安全的设定--icc=false后,如何保持你希望的容器之间通信呢?
|
|
||||||
答案就是--link=CONTAINER_NAME:ALIAS选项,在之前的dns服务设定中提及过。如果docker 使用icc=false and --iptables=true 2个参数,当docker run使用--link=选型时,docker会为2个容器在iptable中参数一对ACCEPT规则,开放的端口取决与dockerfile中的EXPOSE行,详见第五章。
|
|
||||||
注意:--link= 中的CONTAINER_NAME 必须是自动生成的docker名字比如stupefied_pare,或者你用--name参数指定的名字,主机名在--link中不会被识别。
|
|
||||||
你可以使用iptables命令来检查FORWARD链是ACCEPT 还是DROP
|
|
||||||
当--icc=false时,默认规则应该是这样
|
|
||||||
```
|
|
||||||
$ sudo iptables -L -n
|
|
||||||
...
|
|
||||||
Chain FORWARD (policy ACCEPT)
|
|
||||||
target prot opt source destination
|
|
||||||
DROP all -- 0.0.0.0/0 0.0.0.0/0
|
|
||||||
...
|
|
||||||
```
|
|
||||||
当添加了--link后,ACCEPT规则被改写了,添加了新的端口和IP规则
|
|
||||||
```
|
|
||||||
$ sudo iptables -L -n
|
|
||||||
...
|
|
||||||
Chain FORWARD (policy ACCEPT)
|
|
||||||
target prot opt source destination
|
|
||||||
ACCEPT tcp -- 172.17.0.2 172.17.0.3 tcp spt:80
|
|
||||||
ACCEPT tcp -- 172.17.0.3 172.17.0.2 tcp dpt:80
|
|
||||||
DROP all -- 0.0.0.0/0 0.0.0.0/0
|
|
||||||
```
|
|
@ -1,19 +1,22 @@
|
|||||||
##定制docker0
|
##配置docker0
|
||||||
docker服务默认会创建一个docker0接口,它在linux内核层桥接所有物理或虚拟网卡,这就将所有容器和主机接口都放到同一个物理网络。
|
Docker服务默认会创建一个`docker0`接口,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
|
||||||
Docker指定了docker0的ip地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了MTU-接口允许接收的最大传输单元,通常是1500bytes或宿主主机网络路由上支持的默认值,这2个都需要在服务启动的时候配置。
|
|
||||||
* --bip=CIDR — 192.168.1.5/24.ip地址加掩码 使用这种格式
|
|
||||||
* --mtu=BYTES — 覆盖默认的docker mtu配置
|
|
||||||
|
|
||||||
你可以在配置文件中配置DOCKER_OPTS,然后重启来改变这些参数。
|
Docker默认指定了`docker0`的IP地址和子网掩码,让主机和容器之间可以通过网桥相互通信,它还给出了MTU(接口允许接收的最大传输单元),通常是1500bytes,或宿主主机网络路由上支持的默认值,这2个都可以在服务启动的时候进行配置。
|
||||||
|
* --bip=CIDR -- IP地址加掩码格式,例如192.168.1.5/24
|
||||||
|
* --mtu=BYTES -- 覆盖默认的Docker mtu配置
|
||||||
|
|
||||||
|
也可以在配置文件中配置DOCKER_OPTS,然后重启服务。
|
||||||
|
由于目前Docker网桥是Linux网桥,用户可以使用`brctl show`来查看网桥和端口连接信息。
|
||||||
```
|
```
|
||||||
# 当容器启动后,你可以使用brctl来确认他们是否已经连接到docker0网桥
|
|
||||||
$ sudo brctl show
|
$ sudo brctl show
|
||||||
bridge name bridge id STP enabled interfaces
|
bridge name bridge id STP enabled interfaces
|
||||||
docker0 8000.3a1d7362b4ee no veth65f9
|
docker0 8000.3a1d7362b4ee no veth65f9
|
||||||
vethdda6
|
vethdda6
|
||||||
```
|
```
|
||||||
如果brctl命令没安装的话,在ubuntu中你可以使用apt-get install bridge-utils这个命令来安装
|
注:`brctl`命令在Debian、Ubuntu中可以使用`sudo apt-get install bridge-utils`来安装。
|
||||||
docker0 网桥设置会在每次创建新容器的时候被使用。docker从可用的地址段中选择一个空闲的ip地址给容器的eth0端口,子网掩码使用网桥docker0的配置,docker主机本身的ip作为容器的网关使用。
|
|
||||||
|
|
||||||
|
每次创建一个新容器的时候,Docker从可用的地址段中选择一个空闲的ip地址分配给容器的eth0端口。Docker主机上接口`docker0`的IP作为所有容器的默认网关。
|
||||||
```
|
```
|
||||||
$ sudo docker run -i -t --rm base /bin/bash
|
$ sudo docker run -i -t --rm base /bin/bash
|
||||||
$ ip addr show eth0
|
$ ip addr show eth0
|
||||||
@ -28,4 +31,3 @@ default via 172.17.42.1 dev eth0
|
|||||||
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
|
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
|
||||||
$ exit
|
$ exit
|
||||||
```
|
```
|
||||||
转发数据包需要在主机上设定ip_forward参数为1,上文介绍过。
|
|
@ -1,8 +1,8 @@
|
|||||||
##工具和示例
|
##工具和示例
|
||||||
在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣:
|
在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣:
|
||||||
https://github.com/jpetazzo/pipework
|
|
||||||
Jérôme Petazzoni 创建了一个叫pipework的shell脚本来帮助我们在复杂的场景中完成网络连接
|
|
||||||
|
|
||||||
https://github.com/brandon-rhodes/fopnp/tree/m/playground
|
### pipework
|
||||||
Brandon Rhodes创建了一个完整的docker容器网络拓扑,包含 nat 防火墙,服务包括HTTP, SMTP, POP, IMAP, Telnet, SSH, and FTP:
|
Jérôme Petazzoni编写了一个叫[pipework](https://github.com/jpetazzo/pipework)的shell脚本,可以帮助用户在比较复杂的场景中完成容器的连接。
|
||||||
工具使用的网络命令跟之前看到非常相似。
|
|
||||||
|
### playground
|
||||||
|
Brandon Rhodes创建了一个提供完整的Docker容器网络拓扑管理的[Python库](https://github.com/brandon-rhodes/fopnp/tree/m/playground),包括路由、NAT防火墙;以及一些提供HTTP, SMTP, POP, IMAP, Telnet, SSH, FTP的服务器。
|
||||||
|
@ -1,63 +1 @@
|
|||||||
##Docker 如何连接到容器?
|
|
||||||
|
|
||||||
让我们回顾一些基础知识:
|
|
||||||
机器需要一个网络接口来发送和接受数据包,路由表来定义如何到达哪些地址段。这里的网络接口可以不是物理接口。
|
|
||||||
|
|
||||||
事实上,每个linxu机器上的lo环回接口(Docker 容器中也有)就是一个完整的linux内核虚拟接口,它直接复制发送缓存中的数据包到接收缓存中。Docker让宿主主机和容器使用特殊的虚拟接口来通信--通信的2端叫“peers“,他们在主机内核中连接在一起,所以能够相互通信。创建他们很简单,前面介绍过了。
|
|
||||||
|
|
||||||
docker创建容器的步骤如下:
|
|
||||||
* 创建一对虚拟接口
|
|
||||||
* 其中宿主主机一端使用一个名字比如veth65f9,他是唯一的,另外一端桥接到默认的docker0,或其它你指定的桥接网卡。
|
|
||||||
* 主机上的veth65f9这种接口映射到新的新容器中的名称通常是eth0,在容器这个隔离的network namespace
|
|
||||||
中,它是唯一的,不会有其他接口名字和它冲突。
|
|
||||||
* 从主机桥接网卡的地址段中获取一个空闲地址给eth0使用,并设定默认路由到桥接网卡。
|
|
||||||
* 完成这些之后,容器就可以使用这eth0虚拟网卡来连接其他容器和其他网络。
|
|
||||||
|
|
||||||
你也可以为特殊的容器设定特定的参数,在docker run的时候使用--net,它有4个可选参数:
|
|
||||||
* --net=bridge — .默认连接到docker0网桥。
|
|
||||||
* --net=host — 告诉docker不要将容器放到隔离的网络堆栈中。从本质上讲,这个选项告诉docker
|
|
||||||
不要容器化容器的网络!尽管容器还是有自己的文件系统、进程列表和资源限制。但使用ip addr命令这样命令就可以知道实际上此时的的容器处于和docker 宿主主机的一样的网络级别,它拥有完全的宿主主机接口访问权限。虽然它不允许容器重新配置主机的网络堆栈,除非--privileged=true — 但是容器进程可以跟其他root进程一样可以打开低数字的端口,可以访问本地网络服务比如D-bus,还可以让容器做一些意想不到的事情,比如重启主机,使用这个选项的时候要非常小心!
|
|
||||||
* --net=container:NAME_or_ID —
|
|
||||||
告诉docker将新容器的进程放到一个已经存在的容器的网络堆栈中,新容器进程有它自己的文件系统、进程列表和资源限制,但它会和那个已经存在的容器共享ip地址和端口,他们之间来可以通过环回接口通信。
|
|
||||||
* --net=none — 告诉docker将新容器放到自己的网络堆栈中,但是不要配置它的网络,
|
|
||||||
类似于vmware的host-only。这可以让你创建任何自定义的配置,本文最后一段将介绍 他们。
|
|
||||||
|
|
||||||
下面通过配置一个以--net=none启动的容器,使他达到跟平常一样具有访问网络的权限。来介绍docker是如何连接到容器中的。
|
|
||||||
|
|
||||||
启动一个/bin/bash 指定--net=none
|
|
||||||
```
|
|
||||||
$ sudo docker run -i -t --rm --net=none base /bin/bash
|
|
||||||
root@63f36fc01b5f:/#
|
|
||||||
```
|
|
||||||
再开启一个新的终端,查找这个容器的进程id,然后创建它的命名空间,后面的ip netns会用到
|
|
||||||
```
|
|
||||||
$ sudo docker inspect -f '{{.State.Pid}}' 63f36fc01b5f
|
|
||||||
2778
|
|
||||||
$ pid=2778
|
|
||||||
$ sudo mkdir -p /var/run/netns
|
|
||||||
$ sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
|
|
||||||
```
|
|
||||||
检查桥接网卡的ip和子网掩码
|
|
||||||
```
|
|
||||||
$ ip addr show docker0
|
|
||||||
21: docker0: ...
|
|
||||||
inet 172.17.42.1/16 scope global docker0
|
|
||||||
...
|
|
||||||
```
|
|
||||||
创建一对”peer“接口A和B,绑定A到网桥,并启用它
|
|
||||||
```
|
|
||||||
$ sudo ip link add A type veth peer name B
|
|
||||||
$ sudo brctl addif docker0 A
|
|
||||||
$ sudo ip link set A up
|
|
||||||
```
|
|
||||||
将B放到容器的网络命名空间,命名为eth0,配置一个空闲的ip
|
|
||||||
```
|
|
||||||
$ sudo ip link set B netns $pid
|
|
||||||
$ sudo ip netns exec $pid ip link set dev B name eth0
|
|
||||||
$ sudo ip netns exec $pid ip link set eth0 up
|
|
||||||
$ sudo ip netns exec $pid ip addr add 172.17.42.99/16 dev eth0
|
|
||||||
$ sudo ip netns exec $pid ip route add default via 172.17.42.1
|
|
||||||
```
|
|
||||||
自此,你又可以像平常一样使用网络了
|
|
||||||
当你退出shell后,docker清空容器,容器的eth0随网络命名空间一起被摧毁,A 接口也被自动从docker0取消注册。不用其他命令,所有东西都被清理掉了!
|
|
||||||
注意ip netns exec命令,它可以让我们像root一样配置网络命名空间。但在容器内部无法使用,因为统一的安全策略,docker限制容器进程配置自己的网络。使用ip netns exec 可以让我们不用设置--privileged=true就可以完成一些可能带来危险的操作。
|
|
||||||
|
@ -1,37 +1,43 @@
|
|||||||
##映射一个容器端口到宿主主机
|
##映射容器端口到宿主主机的实现
|
||||||
|
|
||||||
默认情况下,容器可以建立到外部网络的连接,但是外部网络无法连接到容器。所有到外部的连接,源地址都会被伪装成宿主主机的ip地址,iptables的 masquerading来做到这一点。
|
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。
|
||||||
|
### 容器访问外部实现
|
||||||
|
容器所有到外部网络的连接,源地址都会被NAT成本地系统的IP地址。这是使用`iptables`的源地址伪装操作实现的。
|
||||||
|
|
||||||
|
查看主机的NAT规则。
|
||||||
```
|
```
|
||||||
# 查看主机的masquerading规则
|
$ sudo iptables -t nat -nL
|
||||||
$ sudo iptables -t nat -L -n
|
|
||||||
...
|
...
|
||||||
Chain POSTROUTING (policy ACCEPT)
|
Chain POSTROUTING (policy ACCEPT)
|
||||||
target prot opt source destination
|
target prot opt source destination
|
||||||
MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
|
MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
其中,上述规则将所有源地址在`172.17.0.0/16`网段,目标地址为其他网段(外部网络)的流量动态伪装为从系统网卡发出。MASQUERADE跟传统SNAT的好处是它能动态从网卡获取地址。
|
||||||
|
|
||||||
当你希望容器接收外部连接时,你需要在docker run执行的时候就指定对应选项,第五章详细介绍了2种方法:
|
### 外部访问容器实现
|
||||||
* 指定-P --publish-all=true|false 选项会映射dockerfile
|
|
||||||
中expose的所有端口,主机端口在49000-49900中随机挑选。当你的另外一个容器需要学习这个端口时候,很不方便。
|
|
||||||
* 指定-p SPEC或则 --publish=SPEC,可以指定任意端口从主机映射容器内部
|
|
||||||
|
|
||||||
不管用那种办法,你可以通过查看iptable的 nat表来观察docker 在网络层做了什么操作。
|
容器允许外部访问,可以在`docker run`时候通过`-p`或`-P`参数来启用。
|
||||||
|
|
||||||
|
不管用那种办法,其实也是在本地的`iptable`的nat表中添加相应的规则。
|
||||||
|
|
||||||
|
使用`-P`时:
|
||||||
```
|
```
|
||||||
#使用-P时:
|
$ iptables -t nat -nL
|
||||||
$ iptables -t nat -L -n
|
|
||||||
...
|
...
|
||||||
Chain DOCKER (2 references)
|
Chain DOCKER (2 references)
|
||||||
target prot opt source destination
|
target prot opt source destination
|
||||||
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80
|
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:172.17.0.2:80
|
||||||
#使用-p 80:80时:
|
```
|
||||||
$ iptables -t nat -L -n
|
|
||||||
|
使用`-p 80:80`时:
|
||||||
|
```
|
||||||
|
$ iptables -t nat -nL
|
||||||
Chain DOCKER (2 references)
|
Chain DOCKER (2 references)
|
||||||
target prot opt source destination
|
target prot opt source destination
|
||||||
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
|
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.17.0.2:80
|
||||||
```
|
```
|
||||||
注意:
|
注意:
|
||||||
* 这里看到docker映射了0.0.0.0.它接受主机上的所有接口地址。可以通过-p IP:host_port:container_port 或则 -p
|
* 这里的规则映射了0.0.0.0,意味着将接受主机来自所有接口的流量。用户可以通过`-p IP:host_port:container_port`或`-p
|
||||||
IP::port 来指定主机上的ip、接口,制定更严格的规则。
|
IP::port`来指定允许访问容器的主机上的IP、接口等,以制定更严格的规则。
|
||||||
* 如果你希望永久改变绑定的主机ip地址,可以 在dcoker 配置中指定--ip=IP_ADDRESS. 记得重启服务。
|
* 如果希望永久绑定到某个固定的IP地址,可以在Docker 配置文件`/etc/default/docker`中指定`DOCKER_OPTS="--ip=IP_ADDRESS"`,之后重启Docker服务即可生效。
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
##创建一个点到点连接
|
##示例:创建一个点到点连接
|
||||||
默认Docker会将所有容器连接到由docker0提供的虚拟子网,你也可以使用自己创建的网桥。但如果你想要2个特殊的容器之间可以直连通信,而不用去配置复杂的主机网卡桥接。
|
默认情况下,Docker会将所有容器连接到由`docker0`提供的虚拟子网中。
|
||||||
|
|
||||||
解决办法很简单:创建一对接口,把2个容器放到这对接口中,配置成点到点链路类型。这2个容器就可以直接通信了。首先启动2个容器:
|
用户有时候需要2个容器之间可以直连通信,而不用通过主机网桥进行桥接。
|
||||||
|
|
||||||
|
解决办法很简单:创建一对“peer”接口,分别放到2个容器中,配置成点到点链路类型即可。
|
||||||
|
|
||||||
|
首先启动2个容器:
|
||||||
```
|
```
|
||||||
$ sudo docker run -i -t --rm --net=none base /bin/bash
|
$ sudo docker run -i -t --rm --net=none base /bin/bash
|
||||||
root@1f1f4c1f931a:/#
|
root@1f1f4c1f931a:/#
|
||||||
@ -9,7 +13,7 @@ $ sudo docker run -i -t --rm --net=none base /bin/bash
|
|||||||
root@12e343489d2f:/#
|
root@12e343489d2f:/#
|
||||||
```
|
```
|
||||||
|
|
||||||
找到他们的进程号,然后创建他们的 namespace entries
|
找到进程号,然后创建网络名字空间的跟踪文件。
|
||||||
```
|
```
|
||||||
$ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
|
$ sudo docker inspect -f '{{.State.Pid}}' 1f1f4c1f931a
|
||||||
2989
|
2989
|
||||||
@ -20,7 +24,7 @@ $ sudo ln -s /proc/2989/ns/net /var/run/netns/2989
|
|||||||
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004
|
$ sudo ln -s /proc/3004/ns/net /var/run/netns/3004
|
||||||
```
|
```
|
||||||
|
|
||||||
创建"peer"接口,然后配置路由
|
创建一对“peer”接口,然后配置路由
|
||||||
```
|
```
|
||||||
$ sudo ip link add A type veth peer name B
|
$ sudo ip link add A type veth peer name B
|
||||||
|
|
||||||
@ -34,7 +38,8 @@ $ sudo ip netns exec 3004 ip addr add 10.1.1.2/32 dev B
|
|||||||
$ sudo ip netns exec 3004 ip link set B up
|
$ sudo ip netns exec 3004 ip link set B up
|
||||||
$ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B
|
$ sudo ip netns exec 3004 ip route add 10.1.1.1/32 dev B
|
||||||
```
|
```
|
||||||
现在这2个容器就可以相互ping通,并成功建立连接。点到点链路不需要子网和子网掩码,使用`ip route`来连接单个ip地址到指定的网络接口。
|
现在这2个容器就可以相互ping通,并成功建立连接。点到点链路不需要子网和子网掩码。
|
||||||
如果没有特殊需要你不需要指定`--net=none`来创建点到点链路。
|
|
||||||
|
|
||||||
还有一个办法就是创建一个只跟主机通信的容器,除非有特殊需求,你可以仅用`--icc=false`来限制主机间的通信。
|
此外,也可以不指定`--net=none`来创建点到点链路。这样容器还可以通过原先的网络来通信。
|
||||||
|
|
||||||
|
利用类似的办法,可以创建一个只跟主机通信的容器。但是一般情况下,更推荐使用`--icc=false`来关闭容器之间的通信。
|
||||||
|
Loading…
Reference in New Issue
Block a user