Docker 学习笔记:网络篇
本笔记承接容器资源限制部分,深入讲解 Docker 的原生网络模型,涵盖 none/host/bridge 三种网络、自定义网络、容器间通信(IP/DNS/joined 容器)以及容器与外部世界的双向访问。
13. Docker 网络概览
Docker 安装时会自动创建三个网络:
bash
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
a1b809382f0d bridge bridge local
6ad21ed9eaf1 host host local
4e31521b27c6 none null local
14. none 和 host 网络
14.1 none 网络
none 网络意味着容器只有 lo 回环接口,完全封闭。
bash
$ docker run -it --network=none busybox
/ # ifconfig
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
适用场景:对安全性要求极高且无需网络的应用,例如只生成随机密码的离线程序。
14.2 host 网络
使用 --network=host 时,容器与宿主机共享同一个网络命名空间,网络配置完全一致。
bash
$ docker run -it --network=host busybox
/ # ip a # 能看到宿主机所有网卡
/ # hostname
docker # 宿主机的主机名
优点 :性能最佳,无网络地址转换开销。
缺点 :端口冲突风险高,灵活性下降。
典型应用:需要直接配置宿主机网络的网络插件(如 Flannel)或以容器形式运行的监控代理。
15. bridge 网络(默认)
15.1 原理
Docker 在安装时创建一个名为 docker0 的 Linux bridge(相当于软件交换机),默认新建的容器都会连接到该网桥。
bash
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02420be905a5 no
创建容器后,会自动生成一对 veth pair 虚拟网卡:一端在容器内(eth0),另一端挂在 docker0 上(如 vethddb2744)。
bash
$ docker run -itd --name busybox1 busybox
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02420be905a5 no vethddb2744
容器内查看:
bash
$ docker exec -it busybox1 sh
/ # ip a
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
同时宿主机上会看到对应的另一端:
bash
$ ip a | grep vethddb2744
25: vethddb2744@if24: ...
docker0 网桥的 IP 为 172.17.0.1/16,容器自动从该子网获取 IP。
15.2 查看 bridge 网络详情
bash
$ docker network inspect bridge
"Subnet": "172.17.0.0/16",
"Gateway": "172.17.0.1"
16. 自定义网络(用户定义 bridge)
与默认 bridge 相比,自定义网络提供 内置 DNS 解析,支持容器名称直接通信。
16.1 创建自定义 bridge 网络
bash
# 自动分配子网
$ docker network create --driver bridge my_net
# 查看新建网桥
$ brctl show
bridge name bridge id STP enabled interfaces
br-89f7bc11b602 8000.0242194d039e no
docker0 8000.02420be905a5 no vethddb2744
16.2 指定子网与网关
bash
$ docker network create --driver bridge \
--subnet 172.22.16.0/24 \
--gateway 172.22.16.1 \
my_net2
宿主机上会生成同名网桥 br-<ID> 并配置网关 IP:
bash
$ ip a | grep br-ec761bc51778
27: br-ec761bc51778: <NO-CARRIER,...> mtu 1500 ...
inet 172.22.16.1/24 brd 172.22.16.255 scope global br-ec761bc51778
16.3 使用自定义网络并指定静态 IP
bash
$ docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
/ # ip a
30: eth0@if31: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
inet 172.22.16.8/24 ...
注意 :只有创建网络时指定了
--subnet才能使用--ip分配静态 IP。
17. 理解容器间的连通性
17.1 同一自定义网络内互通
bash
$ docker exec -it busybox2 sh
/ # ping -c3 172.22.16.8 # 同一 my_net2 中的另一个容器
64 bytes from 172.22.16.8: seq=0 ttl=64 time=0.197 ms
/ # ping -c3 172.22.16.1 # 网关
64 bytes from 172.22.16.1: seq=0 ttl=64 time=0.149 ms
同一网络中的容器与网关之间均可通信。
17.2 不同网络之间的隔离
默认 bridge 网络与自定义 my_net2 网络属于不同的网桥,Docker 通过 iptables 规则 DOCKER-ISOLATION 阻止了它们之间的双向流量。
bash
$ docker exec -it busybox2 sh
/ # ping -c3 172.17.0.2 # busybox1 的 IP
--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
17.3 将容器接入多个网络
bash
$ docker network connect my_net2 busybox1
此时 busybox1 会多出一块 eth1 网卡,获得 my_net2 的 IP,从而可以与 busybox2 通信。
18. 容器间通信的三种方式
18.1 通过 IP 通信
两个容器只要处于同一网络,即可直接通过 IP 互通。
18.2 通过 Docker DNS Server
仅限用户自定义网络 。容器可以用 --name 指定的名称直接相互访问。
bash
$ docker run -it --network=my_net2 --name bbox1 busybox
$ docker run -it --network=my_net2 --name bbox2 busybox
$ docker exec -it bbox2 sh
/ # ping -c3 bbox1
PING bbox1 (172.22.16.2): 56 data bytes
64 bytes from 172.22.16.2: seq=0 ttl=64 time=0.177 ms
默认 bridge 网络 不支持 DNS 名称解析。
18.3 joined 容器(共享网络栈)
通过 --network=container:目标容器名 让新容器与目标容器共享同一个网络命名空间。
bash
$ docker run -d --name web1 httpd
$ docker run -it --network=container:web1 busybox
/ # ip a # 与 web1 的 IP 和 MAC 完全相同
/ # wget 127.0.0.1 # 直接通过 localhost 访问 web1 的服务
适用场景:需要高效 loopback 通信,或监控其他容器的网络流量。
19. 容器访问外部世界
19.1 默认行为
容器无需额外配置即可访问外网(如 ping www.baidu.com),这是通过 NAT(网络地址转换) 实现的。
19.2 NAT 原理解析
在宿主机 iptables 的 NAT 表中存在类似规则:
text
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
当容器向外发包时,数据包经过 docker0 网桥,匹配该规则后被 MASQUERADE,即将 源 IP 替换为宿主机外网接口的 IP,从而能够访问外网并接收回复。
可以用 tcpdump 抓包观察:
bash
# 在宿主机两个窗口分别抓包
$ tcpdump -i docker0 -n icmp
$ tcpdump -i ens160 -n icmp
# 容器中 ping 外网
$ docker run -it busybox ping www.baidu.com
docker0上看到的源 IP 是容器 IP(如172.17.0.2)ens160上看到的源 IP 已经被替换为宿主机 IP(如192.168.108.30)
20. 外部世界访问容器
通过 端口映射 让外部流量到达容器内部服务。
20.1 动态端口映射
bash
$ docker run -d -p 80 httpd
$ docker port <容器ID>
80/tcp -> 0.0.0.0:32768
访问 http://<宿主机IP>:32768 即可访问容器内的 HTTP 服务。
20.2 指定固定端口
bash
$ docker run -d -p 8080:80 httpd
$ curl http://192.168.108.30:8080
<html><body><h1>It works!</h1></body></html>
每个映射的端口,宿主机都会启动一个 docker-proxy 进程负责将流量转发到容器。
bash
$ ps aux | grep docker-proxy
原理流程(以 0.0.0.0:8080->80/tcp 为例):
docker-proxy监听宿主机 8080 端口。- 外部请求到达宿主机 8080 端口。
docker-proxy将请求转发到容器的 IP 和 80 端口。- 容器处理请求并原路返回。
21. 知识点速查表
21.1 Docker 原生网络模式对比
| 网络模式 | 配置方式 | 网络隔离 | 性能 | 典型场景 |
|---|---|---|---|---|
| none | --network=none |
完全无网络(仅 lo) | 不适用 | 离线安全任务 |
| host | --network=host |
无(共享宿主机网络栈) | 最高 | 高性能网络、网络插件 |
| bridge | 默认 | 独立网络命名空间,通过 NAT 访问外网 | 较好 | 一般容器应用 |
| 自定义 bridge | --network=my_net |
同 bridge,但内建 DNS | 好 | 需要名称解析的多容器应用 |
21.2 容器间通信方式速查
| 方式 | 适用网络 | 关键命令/配置 |
|---|---|---|
| IP 直连 | 任意同一网络 | ping <容器IP> |
| 内置 DNS | 仅用户自定义网络 | --name 名称,直接 ping 容器名 |
| joined 容器 | 所有网络 | --network=container:<目标容器>,共享网络栈 |
21.3 容器与外部通信速查
| 方向 | 实现技术 | 关键命令 |
|---|---|---|
| 容器 → 外部 | NAT (MASQUERADE) | 无需配置,自动生效 |
| 外部 → 容器 | 端口映射 + docker-proxy | -p 宿主机端口:容器端口 |
21.4 常用网络管理命令
| 命令 | 功能 |
|---|---|
docker network ls |
列出所有网络 |
docker network inspect <网络名> |
查看网络详细信息(子网、网关、容器等) |
docker network create --driver bridge <网络名> |
创建自定义网络 |
docker network connect <网络名> <容器名> |
将容器接入指定网络 |
docker network disconnect <网络名> <容器名> |
将容器从网络断开 |
docker port <容器名> |
查看容器端口映射情况 |
brctl show |
查看宿主机 Linux bridge 信息(需安装 bridge-utils) |
本笔记至此覆盖 Docker 网络的单机场景,后续将进入存储卷与日志监控部分。