Merge networks

This commit is contained in:
Baohua Yang
2026-01-02 16:55:39 -08:00
parent 61a71f3c25
commit 6e6d31d1d6
19 changed files with 177 additions and 1042 deletions

View File

@@ -1,3 +1,48 @@
# Docker 中的网络功能介绍
# 网络配置
Docker 允许通过外部访问容器或容器互联的方式来提供网络服务
Docker 启动时会自动在主机上创建一个 `docker0` 虚拟网桥实际上是 Linux 的一个 bridge可以理解为一个软件交换机它会在挂载到它的网口之间进行转发
同时Docker 随机分配一个本地未占用的私有网段 [RFC1918](https://datatracker.ietf.org/doc/html/rfc1918) 中定义)中的一个地址给 `docker0` 接口。比如典型的 `172.17.42.1`,掩码为 `255.255.0.0`。此后启动的容器内的网口也会自动分配一个同一网段(`172.17.0.0/16`)的地址。
当创建一个 Docker 容器的时候同时会创建了一对 `veth pair` 接口当数据包发送到一个接口时另外一个接口也可以收到相同的数据包这对接口一端在容器内 `eth0`另一端在本地并被挂载到 `docker0` 网桥名称以 `veth` 开头例如 `vethAQI2QT`通过这种方式主机可以跟容器通信容器之间也可以相互通信Docker 就创建了在主机和所有容器之间一个虚拟共享网络
![Docker 网络](./_images/network.png)
## 用户自定义网络
虽然默认的 `bridge` 网络可以满足大部分需求但为了更好地隔离容器或满足特定的网络需求我们推荐使用用户自定义网络
用户可以创建 `bridge``overlay` `macvlan` 等不同类型的自定义网络
### 创建一个自定义 bridge 网络
```bash
$ docker network create my-net
```
### 连接容器到自定义网络
在启动容器时可以使用 `--network` 选项来指定网络
```bash
$ docker run -it --rm --name busybox1 --network my-net busybox sh
$ docker run -it --rm --name busybox2 --network my-net busybox sh
```
`busybox1` 的终端中可以 `ping` `busybox2`
```bash
/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.083 ms
```
### 容器互联的废弃与替代
Docker 的早期版本中`--link` 选项被用来连接容器然而这个功能现在已经被废弃并且不推荐在生产环境中使用
**注意`--link` 是一个遗留功能它可能会在未来的版本中被移除我们强烈建议使用用户自定义网络来连接多个容器**
使用自定义网络容器之间可以通过容器名直接进行通信这比使用 `--link` 更加灵活和强大
接下来的部分将介绍在一些场景中Docker 所有的网络定制配置以及通过 Linux 命令来调整补充甚至替换 Docker 默认的网络配置

View File

@@ -1,67 +0,0 @@
# 容器互联
如果你之前有 `Docker` 使用经验你可能已经习惯了使用 `--link` 参数来使容器互联
随着 Docker 网络的完善强烈建议大家将容器加入自定义的 Docker 网络来连接多个容器而不是使用 `--link` 参数
## 新建网络
下面先创建一个新的 Docker 网络
```bash
$ docker network create -d bridge my-net
```
`-d` 参数指定 Docker 网络类型 `bridge` `overlay`其中 `overlay` 网络类型用于 [Swarm mode](../swarm_mode/)在本小节中你可以忽略它
## 连接容器
运行一个容器并连接到新建的 `my-net` 网络
```bash
$ docker run -it --rm --name busybox1 --network my-net busybox sh
```
打开新的终端再运行一个容器并加入到 `my-net` 网络
```bash
$ docker run -it --rm --name busybox2 --network my-net busybox sh
```
再打开一个新的终端查看容器信息
```bash
$ docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b47060aca56b busybox "sh" 11 minutes ago Up 11 minutes busybox2
8720575823ec busybox "sh" 16 minutes ago Up 16 minutes busybox1
```
下面通过 `ping` 来证明 `busybox1` 容器和 `busybox2` 容器建立了互联关系
`busybox1` 容器输入以下命令
```bash
/ # ping busybox2
PING busybox2 (172.19.0.3): 56 data bytes
64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.072 ms
64 bytes from 172.19.0.3: seq=1 ttl=64 time=0.118 ms
```
ping 来测试连接 `busybox2` 容器它会解析成 `172.19.0.3`
同理在 `busybox2` 容器执行 `ping busybox1`也会成功连接到
```bash
/ # ping busybox1
PING busybox1 (172.19.0.2): 56 data bytes
64 bytes from 172.19.0.2: seq=0 ttl=64 time=0.064 ms
64 bytes from 172.19.0.2: seq=1 ttl=64 time=0.143 ms
```
这样`busybox1` 容器和 `busybox2` 容器建立了互联关系
## Docker Compose
如果你有多个容器之间需要互相连接推荐使用 [Docker Compose](../compose)

View File

@@ -1,79 +1,57 @@
# 外部访问容器
# 映射容器端口到宿主主机的实现
容器可以运行一些网络应用要让外部也可以访问这些应用可以通过 `-P` `-p` 参数来指定端口映射
默认情况下容器可以主动访问到外部网络的连接但是外部网络无法访问到容器
当使用 `-P` 标记时Docker 会随机映射一个端口到内部容器开放的网络端口
## 容器访问外部实现
使用 `docker container ls` 可以看到本地主机的 32768 被映射到了容器的 80 端口此时访问本机的 32768 端口即可访问容器内 NGINX 默认页面
容器所有到外部网络的连接源地址都会被 NAT 成本地系统的 IP 地址这是使用 `iptables` 的源地址伪装操作实现的
查看主机的 NAT 规则
```bash
$ docker run -d -P nginx:alpine
$ docker container ls -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fae320d08268 nginx:alpine "/docker-entrypoint.…" 24 seconds ago Up 20 seconds 0.0.0.0:32768->80/tcp bold_mcnulty
$ sudo iptables -t nat -nL
...
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16
...
```
同样的可以通过 `docker logs` 命令来查看访问记录
其中上述规则将所有源地址在 `172.17.0.0/16` 网段目标地址为其他网段外部网络的流量动态伪装为从系统网卡发出MASQUERADE 跟传统 SNAT 的好处是它能动态从网卡获取地址
## 外部访问容器实现
容器允许外部访问可以在 `docker run` 时候通过 `-p` `-P` 参数来启用
不管用那种办法其实也是在本地的 `iptable` nat 表中添加相应的规则
使用 `-P`
```bash
$ docker logs fa
172.17.0.1 - - [25/Aug/2020:08:34:04 +0000] "GET / HTTP/1.1" 200 612 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0" "-"
$ iptables -t nat -nL
...
Chain DOCKER (2 references)
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
```
`-p` 则可以指定要映射的端口并且在一个指定端口上只可以绑定一个容器支持的格式有 `ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort`
## 映射所有接口地址
使用 `hostPort:containerPort` 格式本地的 80 端口映射到容器的 80 端口可以执行
使用 `-p 80:80`
```bash
$ docker run -d -p 80:80 nginx:alpine
```
此时默认会绑定本地所有接口上的所有地址
## 映射到指定地址的指定端口
可以使用 `ip:hostPort:containerPort` 格式指定映射使用一个特定地址比如 localhost 地址 127.0.0.1
```bash
$ docker run -d -p 127.0.0.1:80:80 nginx:alpine
```
## 映射到指定地址的任意端口
使用 `ip::containerPort` 绑定 localhost 的任意端口到容器的 80 端口本地主机会自动分配一个端口
```bash
$ docker run -d -p 127.0.0.1::80 nginx:alpine
```
还可以使用 `udp` 标记来指定 `udp` 端口
```bash
$ docker run -d -p 127.0.0.1:80:80/udp nginx:alpine
```
## 查看映射端口配置
使用 `docker port` 来查看当前映射的端口配置也可以查看到绑定的地址
```bash
$ docker port fa 80
0.0.0.0:32768
$ iptables -t nat -nL
Chain DOCKER (2 references)
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
```
注意
* 容器有自己的内部网络和 ip 地址使用 `docker inspect` 查看Docker 还可以有一个可变的网络配置
* `-p` 标记可以多次使用来绑定多个端口
* 这里的规则映射了 `0.0.0.0`意味着将接受主机来自所有接口的流量用户可以通过 `-p IP:host_port:container_port` `-p IP::port` 来指定允许访问容器的主机上的 IP接口等以制定更严格的规则
例如
* 如果希望永久绑定到某个固定的 IP 地址可以在 Docker 配置文件 `/etc/docker/daemon.json` 中添加如下内容
```bash
$ docker run -d \
-p 80:80 \
-p 443:443 \
nginx:alpine
```json
{
"ip": "0.0.0.0"
}
```