56 lines
2.9 KiB
Markdown
56 lines
2.9 KiB
Markdown
## 容器访问控制
|
||
容器的访问控制,主要通过 Linux 上的 `iptables` 防火墙来进行管理和实现。`iptables` 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。
|
||
|
||
### 容器访问外部网络
|
||
容器要想访问外部网络,需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。
|
||
|
||
```bash
|
||
$sysctl net.ipv4.ip_forward
|
||
net.ipv4.ip_forward = 1
|
||
```
|
||
如果为 0,说明没有开启转发,则需要手动打开。
|
||
```bash
|
||
$sysctl -w net.ipv4.ip_forward=1
|
||
```
|
||
如果在启动 Docker 服务的时候设定 `--ip-forward=true`, Docker 就会自动设定系统的 `ip_forward` 参数为 1。
|
||
|
||
### 容器之间访问
|
||
容器之间相互访问,需要两方面的支持。
|
||
* 容器的网络拓扑是否已经互联。默认情况下,所有容器都会被连接到 `docker0` 网桥上。
|
||
* 本地系统的防火墙软件 -- `iptables` 是否允许通过。
|
||
|
||
#### 访问所有端口
|
||
当启动 Docker 服务(即 dockerd)的时候,默认会添加一条转发策略到本地主机 iptables 的 FORWARD 链上。策略为通过(`ACCEPT`)还是禁止(`DROP`)取决于配置`--icc=true`(缺省值)还是 `--icc=false`。当然,如果手动指定 `--iptables=false` 则不会添加 `iptables` 规则。
|
||
|
||
可见,默认情况下,不同容器之间是允许网络互通的。如果为了安全考虑,可以在 `/etc/docker/daemon.json` 文件中配置 `{"icc": false}` 来禁止它(Ubuntu 14.04 等使用 upstart 的系统在文件 `/etc/default/docker` 中配置 `DOCKER_OPTS=--icc=false`)。
|
||
|
||
#### 访问指定端口
|
||
在通过 `-icc=false` 关闭网络访问后,还可以通过 `--link=CONTAINER_NAME:ALIAS` 选项来访问容器的开放端口。
|
||
|
||
例如,在启动 Docker 服务时,可以同时使用 `icc=false --iptables=true` 参数来关闭允许相互的网络访问,并让 Docker 可以修改系统中的 `iptables` 规则。
|
||
|
||
此时,系统中的 `iptables` 规则可能是类似
|
||
```bash
|
||
$ 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` 中为 两个容器分别添加一条 `ACCEPT` 规则,允许相互访问开放的端口(取决于 `Dockerfile` 中的 `EXPOSE` 指令)。
|
||
|
||
当添加了 `--link=CONTAINER_NAME:ALIAS` 选项后,添加了 `iptables` 规则。
|
||
```bash
|
||
$ 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` 参数指定的名字。主机名则不会被识别。
|