@@ -3,32 +3,28 @@
## 目录
- Docker 基础网络介绍
- [ 外部访问容器 ](#<span id="jump">外部访问容器</span> )
- [ 容器互联 ](#<span id="jump">容器互联</span> )
- [ 配置DNS ](#<span id="jump">配置DNS</span> )
- 外部访问容器
- 容器互联
- 配置DNS
- Docker的网络模式
- [ Bridge 模式 ](#<span id="jump">Bridge模式</span> )
- [ Host 模式 ](#<span id="jump">Host 模式</span> )
- [ None 模式 ](#<span id="jump">None模式</span> )
- [ Container 模式 ](#<span id="jump">Container 模式</span> )
- Bridge 模式
- Host 模式
- None 模式
- Container 模式
- Docker高级网络配置
- [ 快速配置指南 ](#<span id="jump">快速配置指南</span> )
- [ 容器访问控制 ](#<span id="jump">容器访问控制</span> )
- [ 端口映射实现 ](#<span id="jump">端口映射实现</span> )
- [ 配置docker0网桥 ](#<span id="jump">配置 docker0 网桥</span> )
- [ 自定义网桥 ](#<span id="jump">自定义网桥</span> )
- [ 工具和示例 ](#<span id="jump">工具和示例</span> )
- [ 编辑网络配置文件 ](#<span id="jump">编辑网络配置文件</span> )
- [ 实例:创建一个点到点连接 ](#<span id="jump">实例:创建一个点到点连接</span> )
- 快速配置指南
- 容器访问控制
- 端口映射实现
- 配置docker0网桥
- 自定义网桥
- 工具和示例
- 编辑网络配置文件
- 实例:创建一个点到点连接
# Docker 基础网络介绍
- [外部访问容器 ](#<span id="jump">外部访问容器</span> )
- [容器互联 ](#<span id="jump">容器互联</span> )
- [配置DNS ](#<span id="jump">配置DNS</span> )
## <span id="jump">外部访问容器</span>
容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过`-P` 或`-p` 参数来指定端口映射。
@@ -217,11 +213,6 @@ nameserver 8.8.8.8
# Docker的网络模式
- [Bridge 模式 ](#<span id="jump">Bridge模式</span> )
- [Host 模式 ](#<span id="jump">Host 模式</span> )
- [None 模式 ](#<span id="jump">None模式</span> )
- [Container 模式 ](#<span id="jump">Container 模式</span> )
可以通过`docker network ls` 查看网络,默认创建三种网络。
```
@@ -249,35 +240,31 @@ f4f1b3cf1b7f none null local
> busybox 被称为嵌入式 Linux 的瑞士军刀,整合了很多小的 unix 下的通用功能到一个小的可执行文件中。


然后宿主机通过 `ip addr` 查看信息如下:


通过以上的比较可以发现,证实了之前所说的:守护进程会创建一对对等虚拟设备接口 `veth pair` ,将其中一个接口设置为容器的 `eth0` 接口(容器的网卡),另一个接口放置在宿主机的命名空间中,以类似 `vethxxx` 这样的名字命名。
同时,守护进程还会从网桥 `docker0` 的私有地址空间中分配一个 IP 地址和子网给该容器,并设置 docker0 的 IP 地址为容器的默认网关。也可以安装 `yum install -y bridge-utils` 以后,通过 `brctl show` 命令查看网桥信息。


对于每个容器的 IP 地址和 Gateway 信息,可以通过 `docker inspect 容器名称|ID` 进行查看,在 `NetworkSettings` 节点中可以看到详细信息。


可以通过 `docker network inspect bridge` 查看所有 `bridge` 网络模式下的容器,在 `Containers` 节点中可以看到容器名称。


> 关于 `bridge` 网络模式的使用,只需要在创建容器时通过参数 `--net bridge` 或者 `--network bridge` 指定即可,当然这也是创建容器默认使用的网络模式,也就是说这个参数是可以省略的。
> 关于 `bridge` 网络模式的使用,只需要在创建容器时通过参数 `--net bridge` 或者 `--network bridge` 指定即可,当然这也是创建容器默认使用的网络模式,也就是说这个参数是可以省略的。


bridge模式是 `docker ` 的默认网络模式,不写`– net` 参数, 就是bridge模式。使用`docker run -p` 时,`docker ` 实际是在`iptables` 做了`DNAT` 规则,实现端口转发功能。可以使用`iptables -t nat -vnL` 查看。`bridge` 模式如下图所示:

演示:
bridge模式是 `docker ` 的默认网络模式,不写`– net` 参数, 就是bridge模式。使用`docker run -p` 时,`docker ` 实际是在`iptables` 做了`DNAT` 规则,实现端口转发功能。可以使用`iptables -t nat -vnL` 查看。演示:
```
$ docker run -tid --net=bridge --name docker_bri1 \
@@ -299,25 +286,23 @@ $ route – n
- 采用 host 网络模式的 Docker Container, 可以直接使用宿主机的 IP 地址与外界进行通信,若宿主机的 eth0 是一个公有 IP, 那么容器也拥有这个公有 IP。同时容器内服务的端口也可以使用宿主机的端口, 无需额外进行 NAT 转换;
- host 网络模式可以让容器共享宿主机网络栈,这样的好处是外部主机与容器直接通信,但是容器的网络缺少隔离性。


比如基于 ` host` 网络模式创建了一个基于 ` busybox` 镜像构建的容器 ` bbox02`,查看 ` ip addr`:


然后宿主机通过 ` ip addr` 查看信息如下:


对,你没有看错,返回信息一模一样,也可以肯定没有截错图,不信接着往下看。可以通过 ` docker network inspect host` 查看所有 ` host` 网络模式下的容器,在 ` Containers` 节点中可以看到容器名称。


如果启动容器的时候使用` host`模式,那么这个容器将不会获得一个独立的` Network Namespace`,而是和宿主机共用一个` Network Namespace`。容器将不会虚拟出自己的网卡,配置自己的` IP`等,而是使用宿主机的` IP`和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。 ` Host`模式如下图所 示:

演示:
如果启动容器的时候使用` host`模式,那么这个容器将不会获得一个独立的` Network Namespace`,而是和宿主机共用一个` Network Namespace`。容器将不会虚拟出自己的网卡,配置自己的` IP`等,而是使用宿主机的` IP`和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。 演 示:
` ``
$ docker run -tid --net=host --name docker_host1 ubuntu-base:v3
@@ -335,19 +320,15 @@ $ route – n
- none 网络模式是指禁用网络功能,只有 lo 接口 local 的简写,代表 127.0.0.1,即 localhost 本地环回接口。在创建容器时通过参数 ` --net none` 或者 ` --network none` 指定;
- none 网络模式即不为 Docker Container 创建任何的网络环境,容器内部就只能使用 loopback 网络设备,不会再有其他的网络资源。可以说 none 模式为 Docke Container 做了极少的网络设定,但是俗话说得好“少即是多”,在没有网络配置的情况下,作为 Docker 开发者,才能在这基础做其他无限多可能的网络定制开发。这也恰巧体现了 Docker 设计理念的开放。
比如基于 ` none` 网络模式创建了一个基于 ` busybox` 镜像构建的容器 ` bbox03`,查看 ` ip addr`:
比如基于 ` none` 网络模式创建了一个基于 ` busybox` 镜像构建的容器 ` bbox03`,查看 ` ip addr`:


可以通过 ` docker network inspect none` 查看所有 ` none` 网络模式下的容器,在 ` Containers` 节点中可以看到容器名称。


使用` none`模式,` Docker` 容器拥有自己的 ` Network Namespace`,但是,并不为` Docker` 容器进行任何网络配置。也就是说,这个 ` Docker` 容器没有网卡、IP、路由等信息。需要自己为 ` Docker` 容器添加网卡、配置 IP 等。 ` None`模式示意图:

演示:
使用` none`模式,` Docker` 容器拥有自己的 ` Network Namespace`,但是,并不为` Docker` 容器进行任何网络配置。也就是说,这个 ` Docker` 容器没有网卡、IP、路由等信息。需要自己为 ` Docker` 容器添加网卡、配置 IP 等。演示:
` ``
$ docker run -tid --net=none --name \
@@ -364,35 +345,33 @@ $ route -n
- Container 网络模式是 Docker 中一种较为特别的网络的模式。在创建容器时通过参数 ` --net container:已运行的容器名称|ID` 或者 ` --network container:已运行的容器名称|ID` 指定;
- 处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信。


**Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 IP, 而是和一个指定的容器共享 IP、端口范围等**。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。
比如基于容器 ` bbox01` 创建了 ` container` 网络模式的容器 ` bbox04`,查看 ` ip addr`:


容器 ` bbox01` 的 ` ip addr` 信息如下:


宿主机的 ` ip addr` 信息如下:


通过以上测试可以发现, Docker 守护进程只创建了一对对等虚拟设备接口用于连接 bbox01 容器和宿主机,而 bbox04 容器则直接使用了 bbox01 容器的网卡信息。
这个时候如果将 bbox01 容器停止,会发现 bbox04 容器就只剩下 lo 接口了。


然后 bbox01 容器重启以后, bbox04 容器也重启一下,就又可以获取到网卡信息了。


这个模式指定新创建的容器和已经存在的一个容器共享一个` Network Namespace`,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的` IP`,而是和一个指定的容器共享` IP`、端口范围等。同样, 两个容器除了网络方面, 其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。 ` Container`模式示意图:

演示:
这个模式指定新创建的容器和已经存在的一个容器共享一个` Network Namespace`,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的` IP`,而是和一个指定的容器共享` IP`、端口范围等。同样, 两个容器除了网络方面, 其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。 演示:
` ``
$ docker run -tid --net=container:docker_bri1 \
@@ -409,15 +388,6 @@ $ route -n
# 高级网络配置
- [快速配置指南](#<span id="jump">快速配置指南</span>)
- [容器访问控制](#<span id="jump">容器访问控制</span>)
- [端口映射实现](#<span id="jump">端口映射实现</span>)
- [配置docker0网桥](#<span id="jump">配置 docker0 网桥</span>)
- [自定义网桥](#<span id="jump">自定义网桥</span>)
- [工具和示例](#<span id="jump">工具和示例</span>)
- [编辑网络配置文件](#<span id="jump">编辑网络配置文件</span>)
- [实例:创建一个点到点连接](#<span id="jump">实例:创建一个点到点连接</span>)
## <span id="jump">快速配置指南</span>
下面是一个跟 Docker 网络相关的命令列表。
@@ -446,8 +416,6 @@ $ route -n
- `-P or --publish-all=true|false` 映射容器所有端口到宿主主机
## <span id="jump">容器访问控制</span>
容器的访问控制,主要通过 Linux 上的 `iptables` 防火墙来进行管理和实现。`iptables` 是 Linux 上默认的防火墙软件,在大部分发行版中都自带。
@@ -456,8 +424,6 @@ $ route -n
容器要想访问外部网络, 需要本地系统的转发支持。在Linux 系统中,检查转发是否打开。
```
$sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
@@ -465,8 +431,6 @@ net.ipv4.ip_forward = 1
如果为 0, 说明没有开启转发, 则需要手动打开。
```
$sysctl -w net.ipv4.ip_forward=1
```
@@ -494,8 +458,6 @@ $sysctl -w net.ipv4.ip_forward=1
此时,系统中的 `iptables` 规则可能是类似
```
$ sudo iptables -nL
...
@@ -509,8 +471,6 @@ DROP all -- 0.0.0.0/0 0.0.0.0/0
当添加了 `--link=CONTAINER_NAME:ALIAS` 选项后,添加了 `iptables` 规则。
```
$ sudo iptables -nL
...
@@ -523,8 +483,6 @@ DROP all -- 0.0.0.0/0 0.0.0.0/0
**注意 ** : `--link=CONTAINER_NAME:ALIAS` 中的 `CONTAINER_NAME` 目前必须是 Docker 分配的名字,或使用 `--name` 参数指定的名字。主机名则不会被识别。
## <span id="jump">端口映射实现</span>
默认情况下,容器可以主动访问到外部网络的连接,但是外部网络无法访问到容器。
@@ -556,8 +514,6 @@ MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
使用 `-P` 时:
```
$ iptables -t nat -nL
...
@@ -568,8 +524,6 @@ DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:49153 to:1
使用 `-p 80:80` 时:
```
$ iptables -t nat -nL
Chain DOCKER (2 references)
@@ -582,16 +536,12 @@ DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 to:172.
- 这里的规则映射了 `0.0.0.0` ,意味着将接受主机来自所有接口的流量。用户可以通过 `-p IP:host_port:container_port` 或 `-p IP::port` 来指定允许访问容器的主机上的 IP、接口等, 以制定更严格的规则。
- 如果希望永久绑定到某个固定的 IP 地址,可以在 Docker 配置文件 `/etc/docker/daemon.json` 中添加如下内容。
```
{
"ip": "0.0.0.0"
}
```
## <span id="jump">配置 docker0 网桥</span>
Docker 服务默认会创建一个 `docker0` 网桥(其上有一个 `docker0` 内部接口),它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。
@@ -605,8 +555,6 @@ Docker 默认指定了 `docker0` 接口 的 IP 地址和子网掩码,让主机
由于目前 Docker 网桥是 Linux 网桥,用户可以使用 `brctl show` 来查看网桥和端口连接信息。
```
$ sudo brctl show
bridge name bridge id STP enabled interfaces
@@ -618,8 +566,6 @@ docker0 8000.3a1d7362b4ee no veth65f9
每次创建一个新容器的时候, Docker 从可用的地址段中选择一个空闲的 IP 地址分配给容器的 eth0 端口。使用本地主机上 `docker0` 接口的 IP 作为所有容器的默认网关。
```
$ sudo docker run -i -t --rm base /bin/bash
$ ip addr show eth0
@@ -634,8 +580,6 @@ default via 172.17.42.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.3
```
## <span id="jump">自定义网桥</span>
除了默认的 `docker0` 网桥,用户也可以指定网桥来连接各个容器。
@@ -644,8 +588,6 @@ default via 172.17.42.1 dev eth0
如果服务已经运行,那需要先停止服务,并删除旧的网桥。
```
$ sudo systemctl stop docker
$ sudo ip link set dev docker0 down
@@ -654,8 +596,6 @@ $ sudo brctl delbr docker0
然后创建一个网桥 `bridge0` 。
```
$ sudo brctl addbr bridge0
$ sudo ip addr add 192.168.5.1/24 dev bridge0
@@ -664,8 +604,6 @@ $ sudo ip link set dev bridge0 up
查看确认网桥创建并启动。
```
$ ip addr show bridge0
4: bridge0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state UP group default
@@ -676,8 +614,6 @@ $ ip addr show bridge0
在 Docker 配置文件 `/etc/docker/daemon.json` 中添加如下内容,即可将 Docker 默认桥接到创建的网桥上。
```
{
"bridge": "bridge0",
@@ -690,8 +626,6 @@ $ ip addr show bridge0
可以继续用 `brctl show` 命令查看桥接的信息。另外,在容器中可以使用 `ip addr` 和 `ip route` 命令来查看 IP 地址配置和路由信息。
## <span id="jump">工具和示例</span>
在介绍自定义网络拓扑之前,你可能会对一些外部工具和例子感兴趣: