Docker 网络配置的使用

举报
yd_63294621 发表于 2026/10/30 07:25:36 2026/10/30
【摘要】 Docker 网络配置的使用容器不是孤岛。绝大多数线上事故里,容器「跑起来了但连不上」,最后都落在网络上:容器之间互相解析不到名字、端口映射没生效、跨主机通不了、macvlan 抢了宿主机流量。这篇把 Docker 网络从模型到实操梳理一遍,重点放在「怎么配」和「配错了怎么查」。 一、先理解模型:容器网络是怎么搭起来的Docker 的网络能力由 libnetwork 提供,遵循 CNM(C...

Docker 网络配置的使用

容器不是孤岛。绝大多数线上事故里,容器「跑起来了但连不上」,最后都落在网络上:容器之间互相解析不到名字、端口映射没生效、跨主机通不了、macvlan 抢了宿主机流量。这篇把 Docker 网络从模型到实操梳理一遍,重点放在「怎么配」和「配错了怎么查」。

一、先理解模型:容器网络是怎么搭起来的

Docker 的网络能力由 libnetwork 提供,遵循 CNM(Container Network Model)规范,三个核心概念:

  • Sandbox:一个网络命名空间(netns),装着容器的网卡、路由表、iptables 规则
  • Endpoint:虚拟网卡(veth),把 sandbox 接到某个网络上
  • Network:一组可以互相通信的 endpoint 集合,由驱动实现(bridge、overlay、macvlan……)

落到 Linux 内核层面,创建一个默认 bridge 容器时发生了这些事:

  1. 创建 netns,里面只有 lo
  2. 创建一对 veth:一端在宿主机 docker0 上(如 veth3f2a1b),一端在容器内改名 eth0
  3. 从 docker0 的网段给容器分配 IP,网关指向 docker0
  4. 宿主机上写 iptables NAT 规则,实现出网 SNAT 和端口映射 DNAT

所以容器出网、容器互联、外部访问,本质都是宿主机上的一张 iptables/nftables 规则表在起作用。理解这点,排障时就不会只盯着容器内部看。

二、六种网络驱动,什么时候用哪个

驱动 场景 特点
bridge 单机容器互联(默认) 独立网段,NAT 出网,需端口映射
host 追求极致网络性能 共享宿主网络栈,无隔离,端口直接占用
none 完全隔离 只有 lo,适合离线计算、自定义网络注入
overlay 跨主机通信(Swarm) VXLAN 封装,多主机二层打通
macvlan 容器要局域网真实 IP 容器像物理机一样出现在交换机上
ipvlan 类似 macvlan 但省 MAC L2/L3 模式,适合 MAC 表容量受限环境

单机场景 90% 用 bridge,而且不要用默认的 bridge,要自建——原因见第四节。

三、日常命令速查

# 查看现有网络
docker network ls

# 看细节:网段、网关、接了哪些容器
docker network inspect mynet

# 创建自定义 bridge 网络
docker network create \
  --driver bridge \
  --subnet 172.20.0.0/16 \
  --gateway 172.20.0.1 \
  mynet

# 运行时接入网络
docker run -d --name web --network mynet nginx:alpine

# 给已运行的容器追加网络(热插拔,不用重启)
docker network connect mynet api

# 断开
docker network disconnect mynet api

# 清理没有被使用的网络
docker network prune

docker network inspect 的输出里,Containers 字段是排查「谁在这个网段里」最快的手段,IPAM.Config 则告诉你网段有没有和公司内网冲突。

四、默认 bridge 的三个坑

默认 docker0 网络(172.17.0.0/16)看起来开箱即用,但生产上问题不少:

1. 只能靠 IP 互访,没有名字解析

默认 bridge 上,容器 A 想访问容器 B,只能写 172.17.0.2 这种地址。IP 会变,配置就废了。老办法 --link 早已废弃,不要再用。

2. 所有容器挤在一个网段

无法按业务划分网段,也无法做网络层面的隔离。

3. 网段冲突

172.17.0.0/16 和公司 VPN、云上 VPC 撞车是常见事故。默认网段可以改(/etc/docker/daemon.json 里的 bip),但改完要重启 daemon,影响所有容器。

{
  "bip": "10.20.0.1/24",
  "default-address-pools": [
    { "base": "10.201.0.0/16", "size": 24 }
  ]
}

五、自定义 bridge:单机场景的标准答案

docker network create --driver bridge --subnet 172.20.0.0/16 mynet

docker run -d --name web  --network mynet nginx:alpine
docker run -d --name api  --network mynet --network-alias backend myapp:1.0

# 验证:直接用容器名访问
docker run --rm --network mynet curlimages/curl \
  curl -s -o /dev/null -w "%{http_code}\n" http://web

自定义网络带来的关键能力:

  • 内嵌 DNS:Docker 在 127.0.0.11 跑了一个 DNS 服务,自动把容器名、--network-alias、--name 解析成容器 IP。容器里的 /etc/resolv.conf 会指向它。
  • 网络隔离:不同网络默认不通,前端网络和后端网络可以物理隔开。
  • 独立网段:可以精确规划,避开内网冲突。

注意一个细节:只有自定义网络才有名字解析,默认 bridge 没有。这是新手最容易踩的坑。

用 Compose 编排时

services:
  web:
    image: nginx:alpine
    networks: [frontend]
    ports: ["8080:80"]

  api:
    image: myapp:1.0
    networks: [frontend, backend]

  db:
    image: postgres:16-alpine
    networks: [backend]

networks:
  frontend:
  backend:
    internal: true   # 无外网出口,只能内部访问

internal: true 是个被低估的配置:数据库所在网络彻底断掉出网能力,即便被拿下也传不出数据。

六、端口映射还是 host 网络

# 映射到所有网卡
docker run -d -p 8080:80 nginx
# 只监听 127.0.0.1,不对公网暴露
docker run -d -p 127.0.0.1:8080:80 nginx
# 随机端口
docker run -d -P nginx

端口映射的实现是 iptables 的 DNAT 规则,加上 docker-proxy 进程兜底(用户态转发,用于某些边界场景)。这意味着:

  • 映射端口会绕过 UFW/firewalld 的常规规则,因为 Docker 直接往 nat 表的 DOCKER 链里插规则。想限制来源,得在 DOCKER-USER 链里写。
  • -p 8080:80 不写绑定地址时,默认监听 0.0.0.0,公网可直接访问。永远显式写 127.0.0.1: 或内网地址。

--network host 则完全跳过 NAT:容器直接用宿主机的网卡和端口,性能最好,但端口冲突、隔离性差,同一端口只能跑一个实例。

docker run -d --network host nginx
# 直接监听宿主机 80

七、overlay:跨主机组网

单机 bridge 出了宿主机就断了。跨主机需要 overlay,底层是 VXLAN(UDP 4789)。

# 初始化 Swarm(overlay 依赖 Swarm 的 KV 存储)
docker swarm init --advertise-addr 192.168.1.10

# 在另一台机器加入
docker swarm join --token SWMTKN-1-xxxx 192.168.1.10:2377

# 创建可被普通容器使用的 overlay 网络
docker network create -d overlay --attachable --subnet 10.0.9.0/24 crossnet

# 两台机器上的容器现在可以直接用名字互访
docker run -d --name svc-a --network crossnet nginx:alpine

关键点:

  • --attachable 必须加,否则只有 Swarm service 能用,docker run 接不上
  • 需要放通 4789/udp(VXLAN)和 7946/tcp+udp(控制面)
  • overlay 有封装开销,跨主机带宽敏感型业务要实测

不用 Swarm 也可以用第三方驱动(Calico、Flannel、Cilium),思路一样:把跨主机流量封装或路由过去。

八、macvlan:让容器成为局域网里的「一台机器」

有些场景容器必须拿局域网真实 IP——比如老系统靠 IP 白名单鉴权、设备发现依赖二层广播、需要被 DHCP 分配地址。

# 宿主机 eth0 所在网段 192.168.1.0/24
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 \
  lan

docker run -d --name nas-agent --network lan --ip 192.168.1.50 nginx:alpine

容器直接出现在交换机上,局域网其他机器能 ping 通 192.168.1.50,没有 NAT。

两个必须知道的限制:

  1. 宿主机默认 ping 不通 macvlan 容器。因为流量从宿主机 eth0 出去后,交换机认为目标 MAC 在别处,不会回环。解决办法是给宿主机再加一个 macvlan 子接口:
ip link add macv0 link eth0 type macvlan mode bridge
ip addr add 192.168.1.60/24 dev macv0
ip link set macv0 up
ip route add 192.168.1.50/32 dev macv0
  1. 很多云厂商和交换机限制单端口 MAC 数量(反 MAC 欺骗),超过就丢包。云上环境用之前先确认,否则换 ipvlan 的 L3 模式更稳。

九、出问题了怎么查

网络排障有个固定顺序:容器内 → 宿主机 → 链路上。

# 1. 看容器 IP、网关、接了哪些网络
docker inspect -f '{{json .NetworkSettings.Networks}}' web | jq

# 2. 进容器的网络命名空间看网卡和路由(容器里通常没 ip 命令)
PID=$(docker inspect -f '{{.State.Pid}}' web)
nsenter -t $PID -n ip addr
nsenter -t $PID -n ip route

# 3. 看 DNS 解析
nsenter -t $PID -n cat /etc/resolv.conf
docker exec web nslookup api

# 4. 抓包,确认包到没到、回没回
nsenter -t $PID -n tcpdump -i eth0 -nn port 5432

# 5. 看宿主机 NAT 规则和计数
iptables -t nat -L DOCKER -n -v
iptables -t filter -L DOCKER-USER -n -v

# 6. 看 veth 两端是不是都 UP
ip -br link | grep veth

常见症状对照表:

症状 大概率原因
容器名解析失败 用了默认 bridge;或两容器不在同一自定义网络
端口映射不生效 绑定到了 127.0.0.1;或宿主机防火墙拦了 DOCKER-USER
容器能出网但外部连不上 没做 -p;或安全组/防火墙未放通
跨主机不通 4789/udp、7946 未放通;overlay 没加 --attachable
时通时不通 网段与内网/VPN 冲突,或 conntrack 表满
宿主机 ping 不通容器 macvlan 回环限制

conntrack 表满值得单独提一句:高并发短连接场景下 nf_conntrack: table full, dropping packet 会让网络随机丢包,调大 net.netfilter.nf_conntrack_max 并缩短 nf_conntrack_tcp_timeout_time_wait 能缓解。

十、一份可以直接照抄的配置清单

  1. 不用默认 bridge,按业务自建网络,网段避开 172.17.0.0/16 和内网保留段
  2. 数据库等敏感服务单独放一个 internal: true 网络,不给外网出口
  3. 端口映射永远显式写绑定地址,公网服务前面挂反向代理,只暴露 80/443
  4. 需要限流的入口在 DOCKER-USER 链写规则,别指望 UFW 管住 Docker 的端口
  5. 生产跨主机优先考虑 Kubernetes + CNI,纯 Docker overlay 适合小规模或过渡期
  6. macvlan 上线前先确认交换机 MAC 限制,并在宿主机建好 macvlan 子接口
  7. 给关键容器配 --network-alias,避免服务名和容器名耦合
  8. 排障先 nsenter 进 netns,比在容器里装一堆工具快得多

小结

Docker 网络不复杂,复杂的是它把 Linux 网络栈的能力原样暴露了出来。记住三句话就够了:自定义 bridge 解决单机互联和名字解析,端口映射本质是 iptables DNAT,跨主机要靠 overlay 或 CNI。剩下的都是在这三条主线上做取舍。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。