0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Docker容器网络模式全解析

马哥Linux运维 来源:马哥Linux运维 2026-02-26 16:39 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

Docker网络模式详解

一、概述

1.1 背景介绍

容器网络是Docker使用中最容易出问题的部分。容器之间怎么通信、容器怎么访问外网、外部怎么访问容器内的服务——这三个问题搞不清楚,排查网络故障就是抓瞎。

Docker网络基于Linux内核的Network Namespace、veth pair、iptables和bridge实现。每个容器有自己独立的网络命名空间,通过veth pair连接到宿主机的网桥(docker0),再通过iptables NAT规则访问外网。理解这个数据包流向,网络问题排查就有了方向。

Docker提供了bridge、host、none、container、overlay、macvlan六种网络模式,每种模式的隔离级别、性能、适用场景都不同。单机环境用bridge和host就够了,跨主机通信需要overlay或macvlan。

1.2 技术特点

bridge模式:默认模式,通过docker0网桥和veth pair实现容器间通信,通过iptables NAT实现外网访问。隔离性好,有约5%-10%的网络性能损耗

host模式:容器直接使用宿主机网络栈,没有NAT开销,网络性能和宿主机一致。但失去了网络隔离性

none模式:容器没有网络接口(只有lo),完全隔离。适合不需要网络的批处理任务或安全敏感场景

container模式:多个容器共享同一个网络命名空间,通过localhost通信。Kubernetes的Pod网络就是基于这个原理

overlay模式:基于VXLAN的跨主机容器网络,Docker Swarm和部分K8s网络插件使用

macvlan模式:容器直接获得物理网络的IP地址,像一台独立的物理机。适合需要直接接入物理网络的场景

1.3 适用场景

bridge模式:大多数单机容器部署场景,开发测试环境

host模式:对网络性能要求高的应用(Nginx反向代理、高频交易系统),需要监听大量端口的应用

none模式:安全隔离要求高的计算任务,不需要网络的数据处理容器

container模式:Sidecar模式(日志收集、监控代理),需要共享网络的紧耦合容器

overlay模式:Docker Swarm集群中的跨主机服务通信

macvlan模式:需要容器拥有独立MAC地址和IP的场景,传统网络架构迁移

1.4 环境要求

组件 版本要求 说明
Docker Engine 20.10+(推荐24.0+) 基本网络功能所有版本都支持
Linux内核 3.10+(推荐5.4+) overlay需要4.0+内核的VXLAN支持
iptables 1.4+ bridge模式的NAT依赖iptables
bridge-utils 任意版本 调试用,brctl命令查看网桥信息
iproute2 任意版本 调试用,ip命令查看网络配置
tcpdump 任意版本 抓包分析用

二、详细步骤

2.1 准备工作

2.1.1 系统检查

# 检查内核网络模块
lsmod | grep -E"bridge|vxlan|macvlan|overlay"

# 检查IP转发是否开启
sysctl net.ipv4.ip_forward
# 必须为1

# 检查iptables
iptables -L -n
iptables -t nat -L -n

# 检查docker0网桥
ip addr show docker0
brctl show docker0

# 安装网络调试工具
sudo apt install -y bridge-utils tcpdump iproute2 net-tools # Debian/Ubuntu
sudo yum install -y bridge-utils tcpdump iproute net-tools  # CentOS/RHEL

2.1.2 查看当前Docker网络

# 查看所有Docker网络
docker network ls

# 默认会有三个网络:
# bridge - 默认bridge网络
# host  - host网络
# none  - 无网络

# 查看bridge网络详情
docker network inspect bridge

# 查看网络中的容器
docker network inspect bridge --format='{{range .Containers}}{{.Name}}: {{.IPv4Address}}{{"
"}}{{end}}'

2.2 核心配置

2.2.1 Bridge模式详解

Bridge是Docker默认的网络模式。Docker启动时会创建一个docker0虚拟网桥,每个容器通过veth pair连接到docker0,容器之间通过网桥二层转发通信,访问外网通过iptables MASQUERADE做源地址转换。

数据包流向

容器eth0 → veth pair → docker0网桥 → iptables NAT → 宿主机eth0 → 外网
# 创建自定义bridge网络(推荐,比默认bridge功能更多)
docker network create 
 --driver bridge 
 --subnet 172.20.0.0/24 
 --gateway 172.20.0.1 
 --opt"com.docker.network.bridge.name"="br-mynet"
 --opt"com.docker.network.bridge.enable_icc"="true"
 --opt"com.docker.network.bridge.enable_ip_masquerade"="true"
 mynet

# 查看创建的网桥
brctl show
ip addr show br-mynet

# 在自定义网络中运行容器
docker run -d --name web1 --network mynet nginx:1.24-alpine
docker run -d --name web2 --network mynet nginx:1.24-alpine

# 自定义网络支持容器名DNS解析(默认bridge不支持)
dockerexecweb1 ping -c 3 web2
# 能ping通,通过Docker内置DNS解析容器名

# 指定容器IP
docker run -d --name web3 --network mynet --ip 172.20.0.100 nginx:1.24-alpine

# 查看容器网络配置
dockerexecweb1 ip addr
dockerexecweb1 ip route
dockerexecweb1 cat /etc/resolv.conf

默认bridge和自定义bridge的区别

特性 默认bridge 自定义bridge
容器名DNS解析 不支持(只能用IP) 支持(推荐)
容器间隔离 同网络内全部互通 同网络内互通,不同网络隔离
热插拔 不支持 支持(docker network connect/disconnect)
自定义子网 不方便 创建时指定

注意:生产环境不要用默认bridge网络,用自定义bridge。默认bridge不支持容器名DNS解析,容器重启后IP可能变化,用IP通信会断。

2.2.2 Host模式详解

Host模式下容器直接使用宿主机的网络命名空间,没有网络隔离,也没有NAT转换开销。容器内看到的网络接口和宿主机完全一样。

# 使用host网络运行容器
docker run -d --name nginx-host --network host nginx:1.24-alpine

# 不需要-p端口映射,Nginx直接监听宿主机的80端口
curl http://localhost:80

# 查看容器网络(和宿主机一样)
dockerexecnginx-host ip addr
# 输出和宿主机的 ip addr 完全一致

# 查看端口占用
ss -tlnp | grep 80
# 能看到nginx进程直接监听在宿主机上

Host模式的性能对比

# 用iperf3测试bridge和host模式的网络吞吐量差异

# 启动iperf3服务端(bridge模式)
docker run -d --name iperf-bridge -p 5201:5201 networkstatic/iperf3 -s

# 启动iperf3服务端(host模式)
docker run -d --name iperf-host --network host networkstatic/iperf3 -s

# 测试bridge模式吞吐量
docker run --rm networkstatic/iperf3 -c <宿主机IP> -p 5201
# 典型结果:约30-40 Gbps(取决于硬件)

# 测试host模式吞吐量
docker run --rm --network host networkstatic/iperf3 -c 127.0.0.1 -p 5201
# 典型结果:约45-50 Gbps
# host模式比bridge模式吞吐量高约15%-25%

警告:host模式下容器端口直接占用宿主机端口,多个容器不能监听同一端口。而且容器能看到宿主机所有网络接口和连接,安全隔离性为零。

2.2.3 None模式详解

None模式下容器只有lo回环接口,没有任何外部网络连接。适合不需要网络的计算任务,或者需要完全自定义网络的场景。

# 使用none网络运行容器
docker run -d --name isolated --network none alpine sleep 3600

# 查看容器网络接口(只有lo)
dockerexecisolated ip addr
# 输出:
# 1: lo:  mtu 65536
#   inet 127.0.0.1/8 scope host lo

# 验证无法访问外网
dockerexecisolated ping -c 1 8.8.8.8
# ping: sendto: Network is unreachable

# 适用场景:数据加密/解密处理
docker run --rm --network none 
 -v /data/input:/input:ro 
 -v /data/output:/output 
 crypto-tool encrypt /input/data.bin /output/data.enc

2.2.4 Container模式详解

Container模式让一个容器共享另一个容器的网络命名空间。两个容器通过localhost通信,共享IP地址和端口空间。Kubernetes的Pod就是基于这个原理——Pod内所有容器共享同一个网络命名空间。

# 先启动一个基础容器
docker run -d --name base-container -p 8080:80 nginx:1.24-alpine

# 启动第二个容器,共享base-container的网络
docker run -d --name sidecar --network container:base-container alpine sleep 3600

# sidecar可以通过localhost访问nginx
dockerexecsidecar wget -qO- http://localhost:80
# 返回Nginx默认页面

# 两个容器的网络接口完全一样
dockerexecbase-container ip addr
dockerexecsidecar ip addr
# 输出一致

# 典型应用:日志收集sidecar
docker run -d --name app -p 8080:8080 myapp:1.0
docker run -d --namelog-collector 
 --network container:app 
 -v /data/logs:/logs 
 fluentd:v1.16
# log-collector通过localhost收集app的日志

2.2.5 Overlay模式详解

Overlay网络基于VXLAN隧道实现跨主机容器通信。数据包在源主机封装VXLAN头部,通过UDP 4789端口发送到目标主机,目标主机解封装后转发给目标容器。

# 初始化Docker Swarm(overlay网络需要Swarm模式)
docker swarm init --advertise-addr 192.168.1.10

# 在其他节点加入Swarm
# docker swarm join --token  192.168.1.10:2377

# 创建overlay网络
docker network create 
 --driver overlay 
 --subnet 10.10.0.0/24 
 --gateway 10.10.0.1 
 --attachable 
 my-overlay

# --attachable 允许非Swarm服务的独立容器也能加入这个网络

# 在overlay网络中部署服务
docker service create 
 --name web 
 --network my-overlay 
 --replicas 3 
 -p 80:80 
 nginx:1.24-alpine

# 验证跨主机通信
docker service ps web
# 三个副本分布在不同节点上,通过overlay网络互通

注意:overlay网络有约10%-15%的性能损耗(VXLAN封装/解封装开销)。对延迟敏感的应用(如Redis集群),建议用macvlan或host模式。

2.2.6 Macvlan模式详解

Macvlan让容器直接获得物理网络的IP地址,每个容器有独立的MAC地址,在网络上表现得像一台独立的物理机。不经过NAT,网络性能接近原生。

# 创建macvlan网络
# 需要知道宿主机的物理网卡名和所在网段
docker network create 
 --driver macvlan 
 --subnet 192.168.1.0/24 
 --gateway 192.168.1.1 
 --opt parent=eth0 
 my-macvlan

# 运行容器(指定IP)
docker run -d --name db 
 --network my-macvlan 
 --ip 192.168.1.200 
 mysql:8.0.35

# 容器直接拥有192.168.1.200这个IP
# 同网段的其他机器可以直接访问192.168.1.200:3306

# 查看容器MAC地址
dockerexecdb ip link show eth0
# 每个容器有独立的MAC地址

注意:macvlan模式下,容器和宿主机之间默认无法通信(这是macvlan的设计限制)。如果需要宿主机访问容器,需要在宿主机上创建macvlan子接口:

# 在宿主机上创建macvlan子接口
ip link add macvlan-host link eth0typemacvlan mode bridge
ip addr add 192.168.1.201/24 dev macvlan-host
ip linksetmacvlan-host up
# 现在宿主机可以通过192.168.1.201访问macvlan网络中的容器

2.2.7 容器网络互联

# 将容器连接到多个网络
docker network create frontend --subnet 172.20.0.0/24
docker network create backend --subnet 172.21.0.0/24

# Nginx连接到frontend
docker run -d --name nginx --network frontend -p 80:80 nginx:1.24-alpine

# App连接到frontend和backend
docker run -d --name app --network frontend myapp:1.0
docker network connect backend app

# MySQL只连接到backend
docker run -d --name mysql --network backend mysql:8.0.35

# 网络拓扑:
# 外部 → Nginx(frontend) → App(frontend+backend) → MySQL(backend)
# Nginx无法直接访问MySQL(不在同一网络)
# App可以同时访问Nginx和MySQL

# 断开容器的网络连接
docker network disconnect frontend app

2.3 启动和验证

2.3.1 端口映射详解

# 映射到宿主机所有接口
docker run -d -p 8080:80 nginx:1.24-alpine
# 等价于 -p 0.0.0.080

# 映射到指定接口(安全,只监听内网)
docker run -d -p 192.168.1.1080 nginx:1.24-alpine

# 映射到随机端口
docker run -d -p 80 nginx:1.24-alpine
docker port 
# 查看分配的随机端口

# UDP端口映射
docker run -d -p 53:53/udp dns-server:1.0

# 映射多个端口
docker run -d -p 80:80 -p 443:443 nginx:1.24-alpine

# 映射端口范围
docker run -d -p 8000-8010:8000-8010 myapp:1.0

# 查看端口映射对应的iptables规则
sudo iptables -t nat -L DOCKER -n

2.3.2 功能验证

# 验证bridge网络容器间通信
docker network create testnet
docker run -d --name server --network testnet nginx:1.24-alpine
docker run --rm --network testnet alpine wget -qO- http://server:80
# 预期返回Nginx默认页面

# 验证DNS解析
docker run --rm --network testnet alpine nslookup server
# 预期解析到server容器的IP

# 验证外网访问
docker run --rm alpine ping -c 3 8.8.8.8
docker run --rm alpine wget -qO- http://ifconfig.me
# 预期返回宿主机的公网IP

# 验证端口映射
docker run -d --name web -p 8080:80 nginx:1.24-alpine
curl -I http://localhost:8080
# 预期返回 HTTP/1.1 200 OK

# 清理
docker rm -f server web
docker network rm testnet

三、示例代码和配置

3.1 完整配置示例

3.1.1 生产环境网络规划配置

// 文件路径:/etc/docker/daemon.json
// 网络相关配置
{
"bip":"172.17.0.1/24",
"default-address-pools": [
  {
  "base":"172.20.0.0/16",
  "size":24
  },
  {
  "base":"172.21.0.0/16",
  "size":24
  }
 ],
"dns": ["223.5.5.5","8.8.8.8"],
"dns-search": ["example.com"],
"ip-forward":true,
"iptables":true,
"ip-masq":true,
"userland-proxy":false,
"fixed-cidr":"172.17.0.0/25"
}

参数说明

bip:docker0网桥的IP和子网,默认172.17.0.1/16。生产环境改成/24,避免分配太大的网段

default-address-pools:自定义网络的地址池。docker network create时从这里分配子网。配两个池做冗余

userland-proxy:设为false用iptables做端口映射。默认的docker-proxy是用户态进程,每个端口映射都fork一个进程,高并发下CPU开销大

fixed-cidr:限制容器IP分配范围,172.17.0.0/25表示只分配172.17.0.1-172.17.0.126

3.1.2 网络排查脚本

#!/bin/bash
# 文件名:docker-network-diag.sh
# Docker网络诊断脚本

CONTAINER_NAME=${1:-""}

if[ -z"$CONTAINER_NAME"];then
 echo"Usage:$0"
 exit1
fi

echo"========== 容器基本信息 =========="
docker inspect --format='容器ID: {{.Id}}'$CONTAINER_NAME
docker inspect --format='状态: {{.State.Status}}'$CONTAINER_NAME
docker inspect --format='PID: {{.State.Pid}}'$CONTAINER_NAME

echo""
echo"========== 网络配置 =========="
docker inspect --format='{{range $net, $config := .NetworkSettings.Networks}}网络: {{$net}} IP: {{$config.IPAddress}} 网关: {{$config.Gateway}} MAC: {{$config.MacAddress}}{{"
"}}{{end}}'$CONTAINER_NAME

echo""
echo"========== 端口映射 =========="
docker port$CONTAINER_NAME2>/dev/null ||echo"无端口映射"

echo""
echo"========== DNS配置 =========="
dockerexec$CONTAINER_NAMEcat /etc/resolv.conf 2>/dev/null

echo""
echo"========== 路由表 =========="
dockerexec$CONTAINER_NAMEip route 2>/dev/null

echo""
echo"========== 网络接口 =========="
dockerexec$CONTAINER_NAMEip addr 2>/dev/null

echo""
echo"========== 连接测试 =========="
echo"--- 外网连通性 ---"
dockerexec$CONTAINER_NAMEping -c 2 -W 3 8.8.8.8 2>/dev/null &&echo"外网: OK"||echo"外网: FAIL"
echo"--- DNS解析 ---"
dockerexec$CONTAINER_NAMEnslookup www.baidu.com 2>/dev/null &&echo"DNS: OK"||echo"DNS: FAIL"

echo""
echo"========== 宿主机iptables NAT规则 =========="
sudo iptables -t nat -L DOCKER -n 2>/dev/null | head -20

echo""
echo"========== 宿主机veth接口 =========="
PID=$(docker inspect --format='{{.State.Pid}}'$CONTAINER_NAME)
if["$PID"!="0"];then
  VETH_INDEX=$(sudo nsenter -t$PID-n ip link show eth0 2>/dev/null | head -1 | awk -F:'{print $1}'| awk -F@'{print $2}'| tr -d'if')
 if[ -n"$VETH_INDEX"];then
    ip link show | grep"^${VETH_INDEX}:"| awk'{print "veth接口: "$2}'
 fi
fi

3.2 实际应用案例

案例一:微服务网络隔离架构

场景描述:一个典型的Web应用包含Nginx、App、MySQL、Redis四个服务。通过Docker网络实现前后端隔离——Nginx和App在前端网络,App和数据库在后端网络,Nginx无法直接访问数据库。

实现代码

#!/bin/bash
# 创建隔离网络
docker network create frontend --subnet 172.20.0.0/24
docker network create backend --subnet 172.21.0.0/24

# 启动MySQL(只在backend网络)
docker run -d 
 --name mysql 
 --network backend 
 --ip 172.21.0.10 
 --restart=unless-stopped 
 --memory=2g 
 -e MYSQL_ROOT_PASSWORD='DbP@ss123!'
 -e MYSQL_DATABASE=myapp 
 -v /data/mysql/data:/var/lib/mysql 
 mysql:8.0.35

# 启动Redis(只在backend网络)
docker run -d 
 --name redis 
 --network backend 
 --ip 172.21.0.11 
 --restart=unless-stopped 
 --memory=1g 
 redis:7.2-alpine

# 启动App(连接frontend和backend)
docker run -d 
 --name app 
 --network frontend 
 --restart=unless-stopped 
 --memory=1g 
 -e DB_HOST=172.21.0.10 
 -e REDIS_HOST=172.21.0.11 
 myapp:1.0

# 将App也连接到backend网络
docker network connect backend app

# 启动Nginx(只在frontend网络)
docker run -d 
 --name nginx 
 --network frontend 
 --restart=unless-stopped 
 -p 80:80 -p 443:443 
 -v /data/nginx/conf.d:/etc/nginx/conf.d:ro 
 nginx:1.24-alpine

# 验证网络隔离
echo"--- Nginx访问App(应该成功)---"
dockerexecnginx wget -qO- --timeout=3 http://app:8080/health

echo"--- Nginx访问MySQL(应该失败)---"
dockerexecnginx ping -c 1 -W 2 172.21.0.10 ||echo"隔离生效:Nginx无法访问MySQL"

echo"--- App访问MySQL(应该成功)---"
dockerexecapp ping -c 1 -W 2 172.21.0.10 &&echo"App可以访问MySQL"

运行结果

--- Nginx访问App(应该成功)---
{"status":"UP"}
--- Nginx访问MySQL(应该失败)---
PING 172.21.0.10: 1 data bytes
ping: sendto: Network is unreachable
隔离生效:Nginx无法访问MySQL
--- App访问MySQL(应该成功)---
PING 172.21.0.10: 1 data bytes
64 bytes from 172.21.0.10: seq=0 ttl=64 time=0.089 ms
App可以访问MySQL

案例二:使用Macvlan让容器直接接入物理网络

场景描述:公司有一套传统的监控系统,通过SNMP轮询固定IP获取设备状态。现在要把监控Agent容器化,但监控系统不支持NAT后的地址,需要容器拥有物理网络的真实IP。

实现步骤

# 1. 确认宿主机网络信息
ip addr show eth0
# 假设:IP=192.168.1.100/24, 网关=192.168.1.1

# 2. 开启网卡混杂模式(macvlan需要)
sudo ip linkseteth0 promisc on

# 3. 创建macvlan网络
docker network create 
 --driver macvlan 
 --subnet 192.168.1.0/24 
 --gateway 192.168.1.1 
 --ip-range 192.168.1.200/29 
 --opt parent=eth0 
 physical-net

# --ip-range 限制Docker只分配192.168.1.200-192.168.1.207
# 避免和DHCP分配的地址冲突

# 4. 运行监控Agent容器
docker run -d 
 --name monitor-agent 
 --network physical-net 
 --ip 192.168.1.200 
 --restart=unless-stopped 
 monitor-agent:1.0

# 5. 验证:从其他物理机直接访问容器IP
# 在192.168.1.50这台机器上:
ping 192.168.1.200
# 能ping通,容器就像一台独立的物理机

# 6. 解决宿主机无法访问容器的问题
sudo ip link add macvlan-shim link eth0typemacvlan mode bridge
sudo ip addr add 192.168.1.201/32 dev macvlan-shim
sudo ip linksetmacvlan-shim up
sudo ip route add 192.168.1.200/32 dev macvlan-shim

四、最佳实践和注意事项

4.1 最佳实践

4.1.1 性能优化

关闭userland-proxy:daemon.json中设置"userland-proxy": false,用iptables替代docker-proxy做端口映射。docker-proxy是用户态进程,每个端口映射fork一个进程,100个端口映射就是100个进程。iptables在内核态处理,零进程开销,高并发下吞吐量提升约20%:

{
"userland-proxy":false
}

高性能场景用host网络:Nginx反向代理、HAProxy负载均衡这类网络密集型应用,bridge模式的NAT转换有5%-10%的性能损耗。切换到host模式后,Nginx的QPS从12000提升到14000(测试环境4核8GB):

docker run -d --name nginx --network host 
 -v /data/nginx/nginx.conf:/etc/nginx/nginx.conf:ro 
 nginx:1.24-alpine

调大conntrack表:bridge模式依赖iptables的连接跟踪(conntrack),默认nf_conntrack_max=65536,高并发场景下会满,导致新连接被丢弃。生产环境建议调到100万:

sysctl -w net.netfilter.nf_conntrack_max=1048576
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=600
# 写入 /etc/sysctl.d/docker-network.conf 持久化

4.1.2 安全加固

网络隔离:不同安全级别的服务放在不同的Docker网络中。数据库和缓存放在backend网络,Web服务放在frontend网络,只有应用层同时连接两个网络。这样即使Web容器被攻破,攻击者也无法直接访问数据库:

docker network create --internal backend-secure
# --internal 禁止该网络访问外网,数据库不需要外网访问

限制容器间通信(ICC):默认同一bridge网络内的容器可以互相通信。如果不需要容器间通信,关闭ICC:

docker network create --opt"com.docker.network.bridge.enable_icc"="false"isolated-net
# ICC关闭后,容器间只能通过端口映射通信

端口映射绑定内网IP:不要把端口映射到0.0.0.0,绑定到内网IP。我见过把MySQL 3306映射到0.0.0.0,结果被外网扫描到暴力破解的:

#  危险:监听所有接口
docker run -d -p 3306:3306 mysql:8.0.35

#  安全:只监听内网
docker run -d -p 192.168.1.103306 mysql:8.0.35

4.1.3 高可用配置

DNS轮询负载均衡:自定义bridge网络支持同名容器的DNS轮询。多个容器用相同的网络别名,Docker DNS会轮询返回不同IP:

docker network create mynet
docker run -d --name app1 --network mynet --network-alias app myapp:1.0
docker run -d --name app2 --network mynet --network-alias app myapp:1.0
docker run -d --name app3 --network mynet --network-alias app myapp:1.0
# 访问 app 这个名字会轮询到app1/app2/app3

overlay网络跨主机高可用:Docker Swarm的overlay网络自动处理节点故障,服务副本会在健康节点上重新调度

网络故障自愈:配置容器restart策略,网络闪断导致容器异常退出时自动重启

4.2 注意事项

4.2.1 配置注意事项

警告:Docker网络地址段不能和宿主机所在网段、公司内网网段冲突。我遇到过Docker默认的172.17.0.0/16和公司办公网段冲突,导致开发机无法访问172.17开头的内网服务器。修改daemon.json的bip和default-address-pools避免冲突。

注意iptables规则持久化:Docker重启会重建iptables规则,但如果手动修改了iptables规则(比如加了防火墙规则),Docker重启后可能覆盖。建议用firewalld的docker zone管理防火墙规则

注意IPv6支持:Docker默认不启用IPv6。如果需要IPv6,在daemon.json中配置"ipv6": true和"fixed-cidr-v6": "fd00::/80"

注意容器重启后IP变化:默认bridge网络不保证容器IP不变。用自定义网络+容器名DNS解析,或者用--ip指定固定IP

4.2.2 常见错误

错误现象 原因分析 解决方案
容器无法访问外网 ip_forward未开启或iptables NAT规则丢失 sysctl -w net.ipv4.ip_forward=1 ,重启Docker重建规则
端口映射不生效 防火墙阻断或端口被占用 检查firewalld/iptables规则,ss -tlnp检查端口占用
容器间ping不通 不在同一Docker网络 docker network connect 将容器加入同一网络
DNS解析失败 使用了默认bridge网络(不支持DNS) 改用自定义bridge网络
conntrack表满导致丢包 nf_conntrack_max太小 调大到1048576,dmesg中搜索"nf_conntrack: table full"
macvlan容器和宿主机不通 macvlan的设计限制 在宿主机创建macvlan子接口

4.2.3 兼容性问题

版本兼容:overlay网络需要Docker 1.12+和Swarm模式。独立容器加入overlay需要--attachable参数(Docker 17.06+)

平台兼容:macvlan在虚拟机环境中可能不工作(取决于虚拟化平台是否允许混杂模式)。AWS/阿里云等云平台通常不支持macvlan

内核兼容:VXLAN需要内核4.0+,ipvlan需要内核4.2+。CentOS 7默认内核3.10不支持这些特性,需要升级内核

五、故障排查和监控

5.1 故障排查

5.1.1 日志查看

# 查看Docker网络相关日志
sudo journalctl -u docker.service | grep -i -E"network|bridge|iptables"

# 查看容器网络事件
docker events --filter'type=network'

# 查看iptables规则(NAT表)
sudo iptables -t nat -L -n -v

# 查看iptables规则(filter表)
sudo iptables -L DOCKER -n -v
sudo iptables -L DOCKER-ISOLATION-STAGE-1 -n -v

# 查看conntrack连接跟踪表
sudo conntrack -L | head -20
sudo conntrack -C # 当前连接数

5.1.2 常见问题排查

问题一:容器无法访问外网

# 第一步:检查IP转发
sysctl net.ipv4.ip_forward
# 如果为0,开启:
sudo sysctl -w net.ipv4.ip_forward=1

# 第二步:检查iptables MASQUERADE规则
sudo iptables -t nat -L POSTROUTING -n | grep MASQUERADE
# 应该有类似:MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0

# 第三步:检查容器DNS
dockerexec cat /etc/resolv.conf
# nameserver应该指向Docker内置DNS 127.0.0.11

# 第四步:分步测试
dockerexec ping -c 1 172.17.0.1  # 网关
dockerexec ping -c 1 8.8.8.8    # 外网IP
dockerexec nslookup www.baidu.com  # DNS解析

解决方案

ip_forward为0:开启并写入sysctl.conf持久化

MASQUERADE规则缺失:systemctl restart docker重建

DNS不通:在daemon.json中配置"dns": ["223.5.5.5", "8.8.8.8"]

问题二:端口映射后外部无法访问

# 检查端口映射是否生效
docker port 

# 检查宿主机端口是否在监听
ss -tlnp | grep 

# 检查防火墙规则
sudo firewall-cmd --list-all
sudo iptables -L INPUT -n | grep 

# 检查Docker的iptables规则
sudo iptables -t nat -L DOCKER -n | grep 
sudo iptables -L DOCKER -n | grep 

# 检查是否有docker-proxy进程(如果userland-proxy=true)
ps aux | grep docker-proxy

解决方案

防火墙阻断:firewall-cmd --add-port=8080/tcp --permanent && firewall-cmd --reload

iptables规则丢失:重启Docker或手动重建

端口被其他进程占用:ss -tlnp | grep 找到占用进程

问题三:容器间网络延迟高

症状:同一宿主机上的容器间通信延迟从0.1ms突然升高到5-10ms

排查

# 检查网桥状态
brctl show
brctl showstp docker0

# 检查veth接口是否有错误
ip -s link show | grep -A 5 veth

# 检查conntrack表是否接近满
sudo sysctl net.netfilter.nf_conntrack_count
sudo sysctl net.netfilter.nf_conntrack_max
# 如果count接近max,说明conntrack表快满了

# 抓包分析
sudo tcpdump -i docker0 -nn -c 100

解决:conntrack表满导致丢包重传,调大nf_conntrack_max;veth接口错误计数增长说明网络栈有问题,检查内核日志

5.1.3 调试模式

# 使用nsenter进入容器网络命名空间(不需要容器内有调试工具)
PID=$(docker inspect --format='{{.State.Pid}}')
sudo nsenter -t$PID-n ip addr
sudo nsenter -t$PID-n ss -tlnp
sudo nsenter -t$PID-n iptables -L -n
sudo nsenter -t$PID-n tcpdump -i eth0 -nn -c 50

# 在docker0网桥上抓包
sudo tcpdump -i docker0 -nn -w /tmp/docker0.pcap

# 在veth接口上抓包(找到容器对应的veth)
VETH=$(ip link show | grep"$(docker inspect --format='{{.State.Pid}}' )"| awk'{print $2}'| tr -d':')
sudo tcpdump -i$VETH-nn -c 50

# 跟踪iptables规则匹配(调试NAT问题)
sudo iptables -t nat -L -n -v --line-numbers
# 观察各规则的pkts和bytes计数器变化

# 使用nicolaka/netshoot调试容器(自带各种网络工具)
docker run --rm -it --network container: nicolaka/netshoot
# 进入后可以用 tcpdump, iperf3, nslookup, curl, ss 等工具

5.2 性能监控

5.2.1 关键指标监控

# 查看容器网络IO
docker stats --no-stream --format"table {{.Name}}	{{.NetIO}}"

# 查看网桥流量
cat /sys/class/net/docker0/statistics/rx_bytes
cat /sys/class/net/docker0/statistics/tx_bytes

# 查看conntrack使用率
echo"$(cat /proc/sys/net/netfilter/nf_conntrack_count)/$(cat /proc/sys/net/netfilter/nf_conntrack_max)"| bc -l

# 查看veth接口错误计数
ip -s link show | grep -A 6 veth

# 查看iptables规则计数
sudo iptables -t nat -L -n -v | grep DOCKER

5.2.2 监控指标说明

指标名称 正常范围 告警阈值 说明
conntrack使用率 <60% >80% 超过80%开始丢包
容器网络收发错误 0 >0 有错误说明网络栈异常
docker0网桥流量 视业务而定 突增50%以上 流量突增可能是攻击或异常
DNS解析延迟 <5ms >50ms Docker内置DNS通常很快
端口映射连接数 视业务而定 接近conntrack_max 连接数过多需要扩容
veth接口丢包率 0% >0.01% 丢包说明网络拥塞或配置问题

5.2.3 Prometheus监控配置

# Prometheus告警规则:docker-network-alerts.yml
groups:
-name:docker_network_alerts
 rules:
  -alert:ConntrackTableNearlyFull
   expr:node_nf_conntrack_entries/node_nf_conntrack_entries_limit>0.8
   for:5m
   labels:
    severity:critical
   annotations:
    summary:"conntrack表使用率超过80%"
    description:"当前使用率{{ $value | humanizePercentage }},即将导致新连接被丢弃"

  -alert:ContainerNetworkErrors
   expr:rate(container_network_receive_errors_total{name!=""}[5m])>0
   for:2m
   labels:
    severity:warning
   annotations:
    summary:"容器{{ $labels.name }}网络接收错误"
    description:"错误率{{ $value }}/s"

  -alert:HighNetworkTraffic
   expr:rate(container_network_receive_bytes_total{name!=""}[5m])>100000000
   for:5m
   labels:
    severity:warning
   annotations:
    summary:"容器{{ $labels.name }}网络流量异常"
    description:"接收流量{{ $value | humanize }}B/s,超过100MB/s"

5.3 备份与恢复

5.3.1 备份策略

#!/bin/bash
# Docker网络配置备份脚本
BACKUP_DIR="/backup/docker-network/$(date +%Y%m%d)"
mkdir -p${BACKUP_DIR}

# 备份所有自定义网络配置
fornetin$(docker network ls --filter'type=custom'-q);do
  NET_NAME=$(docker network inspect --format='{{.Name}}'$net)
  docker network inspect$net>${BACKUP_DIR}/${NET_NAME}.json
done

# 备份iptables规则
sudo iptables-save >${BACKUP_DIR}/iptables-rules.txt
sudo ip6tables-save >${BACKUP_DIR}/ip6tables-rules.txt

# 备份sysctl网络参数
sysctl -a 2>/dev/null | grep -E"net.(ipv4|bridge|netfilter)">${BACKUP_DIR}/sysctl-network.txt

# 备份daemon.json
cp /etc/docker/daemon.json${BACKUP_DIR}/

echo"Network backup completed:${BACKUP_DIR}"

5.3.2 恢复流程

恢复daemon.json:cp daemon.json /etc/docker/ && systemctl restart docker

恢复sysctl参数:cp sysctl-network.txt /etc/sysctl.d/docker-network.conf && sysctl --system

重建自定义网络:根据备份的JSON文件中的subnet、gateway等参数重新创建

验证网络连通性:启动测试容器验证各网络的连通性和隔离性

六、总结

6.1 技术要点回顾

bridge模式:默认模式,通过docker0网桥+veth pair+iptables NAT实现。生产环境用自定义bridge,支持容器名DNS解析

host模式:直接使用宿主机网络栈,零NAT开销,适合网络密集型应用。代价是失去网络隔离

网络隔离:通过多个自定义网络实现服务间隔离,前端网络和后端网络分离,最小化攻击面

性能调优:关闭userland-proxy、调大conntrack表、高性能场景用host模式

排查思路:ip_forward → iptables规则 → DNS解析 → conntrack表,按这个顺序排查覆盖90%的网络问题

6.2 进阶学习方向

容器网络接口(CNI):Kubernetes使用CNI标准管理容器网络,理解CNI插件机制是进入K8s网络的基础

学习资源:CNI规范文档、Flannel/Calico源码

实践建议:手动配置CNI插件,理解网络创建和删除的生命周期

eBPF网络:Cilium等新一代容器网络方案用eBPF替代iptables,性能更好,可观测性更强

学习资源:Cilium官方文档

实践建议:在测试环境部署Cilium,对比iptables方案的性能差异

Service Mesh:Istio/Linkerd在容器网络之上提供流量管理、熔断、链路追踪等能力

学习资源:Istio官方教程

6.3 参考资料

Docker网络官方文档- 各网络驱动的详细说明

Linux网络命名空间- 理解容器网络隔离的内核基础

iptables教程- 理解Docker的NAT规则

nicolaka/netshoot- 容器网络调试工具集

附录

A. 命令速查表

# 网络管理
docker network ls               # 查看所有网络
docker network create --subnet X mynet    # 创建自定义网络
docker network rm mynet            # 删除网络
docker network inspect mynet         # 查看网络详情
docker network connect mynet container    # 容器加入网络
docker network disconnect mynet container   # 容器离开网络
docker network prune             # 清理未使用的网络

# 容器网络操作
docker run --network host ...         # host模式运行
docker run --network none ...         # 无网络运行
docker run --network container:other ...   # 共享网络运行
docker run -p 8080:80 ...           # 端口映射
docker run --ip 172.20.0.100 --network mynet # 指定IP
docker port container             # 查看端口映射

# 网络调试
dockerexeccontainer ip addr         # 查看容器网络
dockerexeccontainer ping target       # 连通性测试
dockerexeccontainer nslookup name      # DNS测试
sudo tcpdump -i docker0 -nn          # 网桥抓包
sudo nsenter -t PID -n ip addr        # 进入网络命名空间

B. 网络模式对比表

特性 bridge host none container overlay macvlan
网络隔离 完全隔离 共享
性能损耗 5-10% 0% N/A 0% 10-15% <2%
端口映射 需要-p 不需要 N/A 不需要 需要-p 不需要
跨主机通信 不支持 不支持 不支持 不支持 支持 支持(同网段)
DNS解析 自定义网络支持 用宿主机 共享 支持
适用场景 通用 高性能 安全隔离 Sidecar Swarm集群 物理网络接入

C. 术语表

术语 英文 解释
网络命名空间 Network Namespace Linux内核特性,为进程提供独立的网络栈(接口、路由表、iptables规则)
veth pair Virtual Ethernet Pair 虚拟以太网对,一端在容器内(eth0),一端在宿主机(vethXXX),数据从一端进另一端出
网桥 Bridge 二层网络设备,连接多个网络接口,实现同网段内的数据转发。docker0就是一个Linux网桥
NAT Network Address Translation 网络地址转换,Docker用MASQUERADE规则将容器IP转换为宿主机IP访问外网
VXLAN Virtual Extensible LAN 虚拟可扩展局域网,overlay网络的底层隧道协议,用UDP 4789端口封装二层帧
conntrack Connection Tracking iptables的连接跟踪机制,记录每个网络连接的状态,NAT依赖此机制
ICC Inter-Container Communication 容器间通信,可以在网络级别开启或关闭
macvlan MAC VLAN 在一个物理网卡上创建多个虚拟网卡,每个有独立的MAC地址和IP

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 网络
    +关注

    关注

    14

    文章

    8378

    浏览量

    95700
  • 容器
    +关注

    关注

    0

    文章

    541

    浏览量

    23057
  • Docker
    +关注

    关注

    0

    文章

    540

    浏览量

    14469

原文标题:从网络隔离到服务互通:Docker 网络模式全解析

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    ARM平台实现Docker容器技术

    T113-i工业核心板在支持Docker后,其性价比还将进一步提升!图2基于T113-i平台实现Docker容器技术 如下为基于志T113-i工业平台,演示
    发表于 07-17 11:05

    ARM平台实现Docker容器技术

    性价比志T113-i工业核心板在支持Docker后,其性价比还将进一步提升! 图2基于T113-i平台实现Docker容器技术 如下为基于
    发表于 07-25 14:36

    如何在Docker中创建容器

    Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的、可移植的、自给自足的容器。开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机)、bare metal
    发表于 01-03 15:58

    docker的四种网络模式

    docker网络模式
    发表于 10-16 08:11

    理解Docker容器并畅玩docker

    ,完全不影响其他容器的正常运作)。这样描述,还是不大明白,我们可以实际操作一下。先打开两个命令行,在其中一个命令行执行以下命令:docker run -it --name a1_rm alpine命令解析
    发表于 11-05 09:54

    Docker容器管理命令(二)

    1、Docker容器管理命令的使用方法批量删除docker 容器docker cp命令docker
    发表于 04-21 11:31

    详解docker的四种网络模式

    使用none模式Docker容器拥有自己的Network Namespace,但是,并不为Docker容器进行任何
    的头像 发表于 01-21 09:21 7409次阅读

    docker的4种网络模式

    Docker 使用 Linux 桥接,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个
    的头像 发表于 08-14 11:50 3004次阅读

    docker的4种网络模式配置

    Docker 使用 Linux 桥接,在宿主机虚拟一个 Docker 容器网桥(docker0),Docker 启动一个
    的头像 发表于 10-10 10:37 2517次阅读

    Docker容器的四种网络模式

    Docker 在安装后自动提供 3 种网络,可以使用 docker network ls 命令查看。
    的头像 发表于 10-17 14:53 2717次阅读

    Docker容器网络的数据链路是什么

    单主机容器网络可能存在多个docker,分属于不同的bridge,它们之间有通信的需求。
    的头像 发表于 02-15 09:56 1986次阅读
    <b class='flag-5'>Docker</b><b class='flag-5'>容器</b><b class='flag-5'>网络</b>的数据链路是什么

    docker容器删除后数据还在吗

    的数据是否还会保留,这是一个需要深入分析和理解的问题。 本文将详细探讨Docker容器删除后数据的存储机制,从容器使用的存储驱动、数据卷、挂载以及网络等方面进行讲解,以帮助读者全面理解
    的头像 发表于 11-23 09:32 3588次阅读

    docker容器容器之间通信

    Docker容器之间的通信方式、通信过程以及常见的通信模式。 一、Docker容器之间的通信方式 在Do
    的头像 发表于 11-23 09:36 2671次阅读

    docker进入容器的方法有哪些

    Docker是一种流行的容器化平台,它能够快速构建、交付和运行应用程序。在使用Docker时,我们经常需要进入容器进行调试、管理和运行命令等操作。本文将详细介绍
    的头像 发表于 11-23 09:45 1.4w次阅读

    docker容器有几种状态

    Docker 容器的各种状态及其含义。 Created(已创建):当我们使用 docker create 命令创建一个容器时,它会进入已创建状态。在这个状态下,
    的头像 发表于 11-23 09:50 4018次阅读