Docker 网络是容器通信的基础,它提供了灵活的网络模型,使容器能够相互通信以及与外部网络交互。
1、核心概念
Docker 网络的核心目标是提供隔离和连通性。它利用 Linux 的 网络命名空间(Network Namespaces 为每个容器提供独立的网络栈(包括网卡、路由表、iptables 规则等),从而实现网络隔离。同时,通过虚拟网桥、veth pair 等设备和技术,容器之间及容器与主机之间能够建立通信渠道。
- 网络命名空间(Network Namespace) :提供了网络的隔离,每个容器(除
host
模式外)都拥有独立的命名空间,包括自己独立的网卡、路由表、ARP 表等。 - 虚拟以太设备对(veth pair) :总是成对出现,像一根虚拟的网线,一端放在容器的网络命名空间内(通常命名为
eth0
),另一端连接到虚拟网桥 (如docker0
)上,从而实现容器与网桥的连接。 - 虚拟网桥(Virtual Bridge) :类似于物理交换机,
docker0
网桥负责在连接到它的多个容器(veth端点)之间转发数据帧。 - iptables :Docker 大量使用
iptables
规则来实现端口映射(DNAT) 、容器访问外部网络(SNAT/MASQUERADE) 以及网络访问控制。
2、默认网络
当你安装 Docker 后,它会自动创建三个默认网络:
bash
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a1b2c3d4e5f6 bridge bridge local
f1e2d3c4b5a6 host host local
1234567890ab none null local
新创建的容器默认会连接到 bridge 网络,除非你用 --network 指定。
3、各种网络模式详解
3.1 Bridge 网络(默认)
这是最常用、最简单的网络模式。
特点:
- 每个容器分配独立 IP 地址(默认在 172.17.0.0/16 网段)
- 容器通过网桥相互通信
- 通过
NAT
实现与外部网络通信(容器内部访问外部) - 支持端口映射(将容器端口映射到宿主机)(外部访问容器内部)
工作原理:
- Docker 守护进程会创建一个名为
docker0
的虚拟网桥。 - 每创建一个新容器(使用
bridge
模式),Docker 会创建一对veth
虚拟设备接口,一端放在容器内(命名为eth0
),另一端连接到docker0
网桥上。 - 容器内的
eth0
接口会从网桥的 IP 地址段中获得一个私有 IP 地址(如172.17.0.2
)。 - 容器通过
docker0
网桥与外界通信。docker0
网桥作为 NAT 设备,通过宿主机的物理网卡进行流量转发。
示例:端口映射(Port Publishing)
默认的 bridge
网络内的容器可以互相通过 IP 地址通信,但无法通过容器名通信,且外部无法直接访问。要让外部访问,必须映射端口。
bash
# 运行一个 Nginx 容器,将容器的 80 端口映射到宿主机的 8080 端口
docker run -d --name web -p 8080:80 nginx:alpine
# 现在,你可以通过宿主机的 IP 和 8080 端口访问容器中的 Nginx
# 例如:http://localhost:8080 或 http://<host-ip>:8080
示例:创建自定义 Bridge 网络
自定义的 Bridge 网络比默认的更好,它提供自动 DNS 解析(容器可以通过容器名互相访问)和更好的隔离性。
bash
# 1. 创建一个名为 my-net 的自定义桥接网络
docker network create my-net
# 2. 运行两个容器,并连接到 my-net 网络
docker run -d --name web-app --network my-net nginx:alpine
docker run -it --name redis --network my-net redis:alpine redis-cli
# 3. 在 redis 容器中,你可以直接通过容器名 "web-app" ping 通另一个容器
# redis-alpine:/data# ping web-app
# PING web-app (172.21.0.2): 56 data bytes
# 64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.191 ms
2.2 Host 网络
host 网络让容器直接使用宿主机的网络栈,容器的网络配置与 host 完全一样,没有网络隔离。
特点:
- 容器共享宿主机的 IP 和端口空间
- 性能最好(无网络转发开销)
- 缺乏网络隔离,端口可能冲突
- 不支持端口映射(直接使用宿主机端口)
bash
# 使用 host 网络运行 Nginx
docker run -d --name nginx-host --network host nginx:alpine
# 此时,Nginx 直接监听了宿主机的 80 端口。
# 访问 http://<host-ip> 即可,无需使用 -p 参数进行端口映射。
**注意:**如果宿主机上已经有进程占用了 80 端口,容器启动会失败。
2.3 None 网络
容器没有任何网络接口。
特点:
- 容器没有网络连接
- 仅能访问自身
- 适用于不需要网络的场景
bash
docker run -it --rm --network none alpine:latest /bin/sh
# 在容器内执行 `ifconfig`,只会看到 lo(回环)接口。
3、容器间通信
3.1 同一网络内的容器通信
同一网络中的容器可以通过容器名或 IP 地址相互通信:
bash
# 创建网络
docker network create my-network
# 启动两个容器在同一网络
docker run -d --name service1 --network my-network nginx
docker run -d --name service2 --network my-network nginx
# 从 service1 访问 service2
docker exec -it service1 ping service2
3.2 不同网络的容器通信
不同网络的容器默认无法通信,需要通过以下方式实现:
- 将容器连接到两个网络
- 使用端口映射通过宿主机中转
- 使用专用的代理容器
bash
# 将容器连接到第二个网络,此时该容器就会有和需要通信容器相同网络的网卡
docker network connect another-network service1
3.3 端口映射(容器与外部通信)
端口映射允许外部访问容器内的服务:
bash
# 将容器的 80 端口映射到宿主机的 8080 端口
docker run -d -p 8080:80 --name web nginx
# 映射到指定 IP 的端口
docker run -d -p 192.168.1.100:8080:80 --name web nginx
# 随机映射端口(32768-60999)
docker run -d -P --name web nginx
4、网络故障排查
4.1 常用网络排查命令
bash
# 查看容器网络详情
docker inspect -f '{{json .NetworkSettings}}' <container> | jq
# 查看容器IP地址
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>
# 在容器内执行网络命令
docker exec -it <container> ping <host>
docker exec -it <container> curl <url>
docker exec -it <container> netstat -tulpn
# 查看网络连接情况
docker network inspect <network>
# 查看Docker网络相关的iptables规则
iptables -L -n | grep docker
4.2 常见网络问题及解决
- 容器无法访问外部网络
- 检查 DNS 配置:
cat /etc/resolv.conf
- 检查防火墙规则
- 重启 Docker 服务:
systemctl restart
docker
- 检查 DNS 配置:
- 容器间无法通信
- 确认容器在同一网络:
docker network inspect <network>
- 检查容器是否正常运行:
docker ps
- 检查容器内服务是否监听正确的地址(0.0.0.0 而非 127.0.0.1)
- 确认容器在同一网络:
- 外部无法访问容器服务
- 检查端口映射是否正确:
docker port <container>
- 检查容器内服务是否正常运行
- 检查宿主机防火墙是否允许该端口
- 检查端口映射是否正确:
5、核心命令总结
- docker network ls: 列出所有网络。
- docker network create : 创建网络。
- docker network inspect : 查看网络详细信息(包括连接的容器、IP 段等)。
- docker network connect : 将运行中的容器连接到指定网络。
- docker network disconnect : 从网络断开容器。