06-网络模式与实现
学习目标
- 深入理解各种容器网络模式的特点和适用场景
- 掌握 Bridge、Host、Macvlan、IPvlan 等网络模式
- 了解 Overlay 网络和跨节点通信
- 掌握网络性能优化技术
- 能够进行网络问题调试和故障排查
前置知识
- 容器网络基础原理
- Linux 网络配置
- 网络协议基础
- 性能调优概念
一、容器网络模式概览
1.1 网络模式分类
graph TD
A[容器网络模式] --> B[单机模式]
A --> C[跨节点模式]
B --> B1[Bridge 模式]
B --> B2[Host 模式]
B --> B3[Macvlan 模式]
B --> B4[IPvlan 模式]
B --> B5[None 模式]
C --> C1[Overlay 网络]
C --> C2[Underlay 网络]
C --> C3[混合网络]
1.2 网络模式对比
模式 | 隔离性 | 性能 | 复杂度 | 适用场景 |
---|---|---|---|---|
Bridge | 高 | 中 | 低 | 开发测试,单机部署 |
Host | 无 | 高 | 低 | 高性能应用 |
Macvlan | 中 | 高 | 中 | 需要独立 MAC 地址 |
IPvlan | 中 | 高 | 中 | 节省 MAC 地址 |
Overlay | 高 | 中 | 高 | 跨节点通信 |
None | 无 | 高 | 低 | 自定义网络 |
二、Bridge 模式详解
2.1 Bridge 模式原理
Bridge 模式是 Docker 的默认网络模式:
graph TD
A[容器1] --> B[veth pair]
C[容器2] --> D[veth pair]
E[容器3] --> F[veth pair]
B --> G[docker0 Bridge]
D --> G
F --> G
G --> H[iptables NAT]
H --> I[宿主机网卡]
I --> J[外部网络]
2.2 Bridge 模式特性
- 网络隔离:每个容器有独立的 Network Namespace
- IP 分配:自动分配私有 IP 地址
- 端口映射:通过 iptables 实现端口映射
- 服务发现:支持容器间通过容器名通信
2.3 Bridge 模式实战
2.3.1 创建自定义 Bridge 网络
# 1. 创建自定义 Bridge 网络
docker network create --driver bridge \
--subnet=172.20.0.0/16 \
--ip-range=172.20.240.0/20 \
--gateway=172.20.0.1 \
my-bridge-network
# 2. 查看网络信息
docker network ls
docker network inspect my-bridge-network
# 3. 运行容器并连接到自定义网络
docker run -d --name web1 --network my-bridge-network nginx
docker run -d --name web2 --network my-bridge-network nginx
# 4. 测试容器间通信
docker exec web1 ping web2
docker exec web2 ping web1
2.3.2 端口映射配置
# 1. 运行容器并映射端口
docker run -d --name web-server \
-p 8080:80 \
--network my-bridge-network \
nginx
# 2. 测试端口映射
curl http://localhost:8080
# 3. 查看端口映射规则
sudo iptables -t nat -L DOCKER
三、Host 模式详解
3.1 Host 模式原理
Host 模式让容器直接使用宿主机的网络栈:
graph TD
A[容器进程] --> B[宿主机网络栈]
B --> C[宿主机网卡]
C --> D[外部网络]
E[其他容器] --> F[独立网络栈]
F --> G[虚拟网卡]
G --> H[Bridge]
3.2 Host 模式特性
- 无网络隔离:容器与宿主机共享网络栈
- 高性能:无虚拟化开销
- 端口冲突:容器端口与宿主机端口冲突
- 安全风险:容器可以访问宿主机网络
3.3 Host 模式实战
# 1. 运行 Host 模式容器
docker run -d --name web-host \
--network host \
nginx
# 2. 查看网络接口
docker exec web-host ip addr show
# 输出: 显示宿主机所有网络接口
# 3. 测试网络性能
docker exec web-host iperf3 -s &
iperf3 -c localhost
# 4. 查看端口占用
docker exec web-host netstat -tlnp
四、Macvlan 模式详解
4.1 Macvlan 原理
Macvlan 让容器获得独立的 MAC 地址:
graph TD
A[宿主机网卡] --> B[Macvlan 接口1]
A --> C[Macvlan 接口2]
A --> D[Macvlan 接口3]
B --> E[容器1]
C --> F[容器2]
D --> G[容器3]
H[交换机] --> A
H --> I[其他设备]
4.2 Macvlan 模式类型
模式 | 说明 | 特点 |
---|---|---|
Bridge | 默认模式 | 容器间可以通信 |
Private | 私有模式 | 容器间不能通信 |
VEPA | 虚拟以太网端口聚合 | 需要支持 VEPA 的交换机 |
Passthru | 直通模式 | 容器直接使用物理网卡 |
4.3 Macvlan 实战演示
4.3.1 创建 Macvlan 网络
# 1. 创建 Macvlan 网络
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
macvlan-net
# 2. 运行容器
docker run -d --name macvlan-container \
--network macvlan-net \
nginx
# 3. 查看容器网络配置
docker exec macvlan-container ip addr show
# 输出: 显示独立的 MAC 地址和 IP 地址
# 4. 测试网络连通性
docker exec macvlan-container ping 192.168.1.1
4.3.2 Macvlan 高级配置
# 1. 创建 Macvlan 子接口
sudo ip link add macvlan0 link eth0 type macvlan mode bridge
# 2. 配置 IP 地址
sudo ip addr add 192.168.1.100/24 dev macvlan0
sudo ip link set macvlan0 up
# 3. 创建 Network Namespace
sudo ip netns add macvlan-ns
# 4. 将 Macvlan 接口移到 Namespace
sudo ip link set macvlan0 netns macvlan-ns
# 5. 在 Namespace 中配置网络
sudo ip netns exec macvlan-ns ip link set lo up
sudo ip netns exec macvlan-ns ip route add default via 192.168.1.1
五、IPvlan 模式详解
5.1 IPvlan 原理
IPvlan 让多个容器共享同一个 MAC 地址:
graph TD
A[宿主机网卡] --> B[IPvlan 接口1]
A --> C[IPvlan 接口2]
A --> D[IPvlan 接口3]
B --> E[容器1 - 独立IP]
C --> F[容器2 - 独立IP]
D --> G[容器3 - 独立IP]
H[交换机] --> A
H --> I[其他设备]
5.2 IPvlan 模式类型
模式 | 说明 | 特点 |
---|---|---|
L2 | 二层模式 | 容器共享 MAC 地址 |
L3 | 三层模式 | 容器有独立路由表 |
5.3 IPvlan 实战演示
# 1. 创建 IPvlan 网络
docker network create -d ipvlan \
--subnet=192.168.2.0/24 \
--gateway=192.168.2.1 \
-o parent=eth0 \
-o ipvlan_mode=l2 \
ipvlan-net
# 2. 运行容器
docker run -d --name ipvlan-container \
--network ipvlan-net \
nginx
# 3. 查看网络配置
docker exec ipvlan-container ip addr show
# 输出: 显示共享 MAC 地址和独立 IP 地址
# 4. 测试连通性
docker exec ipvlan-container ping 192.168.2.1
六、Overlay 网络详解
6.1 Overlay 网络原理
Overlay 网络实现跨节点的容器通信:
graph TD
A[节点1] --> B[容器1]
A --> C[容器2]
D[节点2] --> E[容器3]
D --> F[容器4]
B --> G[Overlay 网络]
C --> G
E --> G
F --> G
G --> H[VXLAN/Geneve 隧道]
H --> I[物理网络]
6.2 Overlay 网络技术
技术 | 说明 | 特点 |
---|---|---|
VXLAN | 虚拟可扩展 LAN | 24位 VNI,支持 1600万网络 |
Geneve | 通用网络虚拟化封装 | 可扩展头部,支持元数据 |
GRE | 通用路由封装 | 简单,但扩展性差 |
6.3 Overlay 网络实战
6.3.1 创建 Overlay 网络
# 1. 初始化 Swarm 集群
docker swarm init
# 2. 创建 Overlay 网络
docker network create -d overlay \
--subnet=10.0.0.0/24 \
--attachable \
overlay-net
# 3. 在节点1运行服务
docker service create --name web-service \
--network overlay-net \
--replicas 2 \
nginx
# 4. 查看服务状态
docker service ls
docker service ps web-service
6.3.2 跨节点通信测试
# 1. 在节点1运行测试容器
docker run -it --rm \
--network overlay-net \
alpine sh
# 2. 在容器中测试跨节点通信
ping web-service
nslookup web-service
# 3. 查看 Overlay 网络信息
docker network inspect overlay-net
七、网络性能优化
7.1 性能优化技术
graph TD
A[网络性能优化] --> B[硬件优化]
A --> C[软件优化]
A --> D[协议优化]
B --> B1[网卡调优]
B --> B2[CPU 绑定]
B --> B3[内存优化]
C --> C1[内核参数调优]
C --> C2[网络栈优化]
C --> C3[中断处理优化]
D --> D1[TCP 调优]
D --> D2[UDP 调优]
D --> D3[协议栈优化]
7.2 内核参数调优
# 1. 网络缓冲区调优
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.wmem_max = 134217728' >> /etc/sysctl.conf
echo 'net.core.rmem_default = 262144' >> /etc/sysctl.conf
echo 'net.core.wmem_default = 262144' >> /etc/sysctl.conf
# 2. TCP 参数调优
echo 'net.ipv4.tcp_rmem = 4096 87380 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_wmem = 4096 65536 134217728' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_congestion_control = bbr' >> /etc/sysctl.conf
# 3. 网络队列调优
echo 'net.core.netdev_max_backlog = 5000' >> /etc/sysctl.conf
echo 'net.core.netdev_budget = 600' >> /etc/sysctl.conf
# 4. 应用配置
sysctl -p
7.3 网卡调优
# 1. 启用 GRO (Generic Receive Offload)
ethtool -K eth0 gro on
# 2. 启用 LRO (Large Receive Offload)
ethtool -K eth0 lro on
# 3. 调整队列长度
ethtool -G eth0 rx 4096 tx 4096
# 4. 启用多队列
ethtool -L eth0 combined 8
# 5. 查看网卡统计信息
ethtool -S eth0
7.4 容器网络性能测试
# 1. 安装测试工具
apt-get update && apt-get install -y iperf3
# 2. 启动服务端
docker run -d --name iperf-server \
--network my-bridge-network \
-p 5201:5201 \
networkstatic/iperf3 -s
# 3. 启动客户端
docker run -it --rm \
--network my-bridge-network \
networkstatic/iperf3 -c iperf-server
# 4. 测试不同网络模式性能
# Bridge 模式
docker run -it --rm --network bridge networkstatic/iperf3 -c iperf-server
# Host 模式
docker run -it --rm --network host networkstatic/iperf3 -c localhost
八、网络调试与故障排查
8.1 常用调试工具
8.1.1 网络连通性测试
# 1. ping 测试
ping -c 4 8.8.8.8
ping -c 4 container-ip
# 2. telnet 测试端口
telnet container-ip 80
telnet host-ip 8080
# 3. nc 测试端口
nc -zv container-ip 80
nc -zv host-ip 8080
# 4. curl 测试 HTTP
curl -v http://container-ip:80
curl -v http://host-ip:8080
8.1.2 网络抓包分析
# 1. tcpdump 抓包
tcpdump -i any -n host container-ip
tcpdump -i any -n port 80
tcpdump -i any -n icmp
# 2. wireshark 分析
# 将 tcpdump 输出保存到文件
tcpdump -i any -w capture.pcap
# 使用 wireshark 打开 capture.pcap
# 3. 容器内抓包
docker exec container-name tcpdump -i eth0 -n
8.1.3 网络配置检查
# 1. 检查网络接口
ip addr show
ip link show
# 2. 检查路由表
ip route show
ip route get 8.8.8.8
# 3. 检查 ARP 表
ip neigh show
arp -a
# 4. 检查 iptables 规则
iptables -t nat -L -n
iptables -t filter -L -n
8.2 常见问题排查
8.2.1 容器无法访问外网
# 1. 检查 IP 转发
sysctl net.ipv4.ip_forward
# 应该返回 1
# 2. 检查 NAT 规则
iptables -t nat -L POSTROUTING
# 应该有 MASQUERADE 规则
# 3. 检查 DNS 配置
cat /etc/resolv.conf
nslookup google.com
# 4. 检查路由表
ip route show
8.2.2 容器间无法通信
# 1. 检查网络模式
docker network ls
docker network inspect network-name
# 2. 检查容器网络配置
docker exec container-name ip addr show
docker exec container-name ip route show
# 3. 检查 Bridge 配置
brctl show
bridge fdb show
# 4. 检查防火墙规则
iptables -L FORWARD
8.2.3 端口映射不生效
# 1. 检查端口映射配置
docker port container-name
# 2. 检查 iptables 规则
iptables -t nat -L DOCKER
iptables -t filter -L DOCKER
# 3. 检查端口占用
netstat -tlnp | grep port
lsof -i :port
# 4. 检查容器内服务
docker exec container-name netstat -tlnp
九、验证检查清单
基础理解
- [ ] 理解各种网络模式的特点和适用场景
- [ ] 掌握 Bridge、Host、Macvlan、IPvlan 模式
- [ ] 了解 Overlay 网络和跨节点通信
- [ ] 理解网络性能优化原理
实践能力
- [ ] 能够配置和测试各种网络模式
- [ ] 能够进行网络性能优化
- [ ] 能够进行网络问题调试
- [ ] 能够排查网络故障
高级技能
- [ ] 掌握网络性能调优技术
- [ ] 能够设计复杂的网络架构
- [ ] 能够进行网络安全配置
- [ ] 理解网络监控和运维
实战实现
完整的网络实现
根据实际开发经验,以下是完整的容器网络实现代码:
1. 网络管理器
type NetworkManager struct {
bridgeName string
subnet *net.IPNet
gateway net.IP
ipam *IPAM
containers map[string]*ContainerNetwork
mu sync.RWMutex
}
type ContainerNetwork struct {
ID string
IP net.IP
HostVeth string
ContVeth string
Bridge string
CreatedAt time.Time
}
type IPAM struct {
Subnet *net.IPNet
Gateway net.IP
Allocated map[string]bool
file string
mu sync.Mutex
}
2. IPAM 实现
func NewIPAM(stateFile, cidr string) (*IPAM, error) {
ip, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
return nil, err
}
i := &IPAM{
Subnet: ipNet,
Gateway: ip,
Allocated: make(map[string]bool),
file: stateFile,
}
// 加载已分配的 IP
_ = i.load()
return i, nil
}
func (i *IPAM) Allocate() (net.IP, error) {
i.mu.Lock()
defer i.mu.Unlock()
start := binaryInc(i.Gateway)
for ip := start; i.Subnet.Contains(ip); ip = binaryInc(ip) {
if !i.Allocated[ip.String()] {
i.Allocated[ip.String()] = true
i.save()
return ip, nil
}
}
return nil, fmt.Errorf("no available IP in %s", i.Subnet.String())
}
func (i *IPAM) Release(ip net.IP) {
i.mu.Lock()
defer i.mu.Unlock()
delete(i.Allocated, ip.String())
i.save()
}
func binaryInc(ip net.IP) net.IP {
res := make(net.IP, len(ip))
copy(res, ip)
for j := len(res) - 1; j >= 0; j-- {
res[j]++
if res[j] != 0 {
break
}
}
return res
}
3. 网络创建
func (nm *NetworkManager) CreateContainerNetwork(containerID string) (*ContainerNetwork, error) {
nm.mu.Lock()
defer nm.mu.Unlock()
// 分配 IP
ip, err := nm.ipam.Allocate()
if err != nil {
return nil, err
}
// 创建 veth 对
hostVeth, contVeth, err := createVethPair(containerID)
if err != nil {
nm.ipam.Release(ip)
return nil, err
}
// 配置网络
if err := nm.configureContainerNetwork(hostVeth, contVeth, ip); err != nil {
nm.ipam.Release(ip)
_ = netlink.LinkDel(hostVeth)
return nil, err
}
cn := &ContainerNetwork{
ID: containerID,
IP: ip,
HostVeth: hostVeth,
ContVeth: contVeth,
Bridge: nm.bridgeName,
CreatedAt: time.Now(),
}
nm.containers[containerID] = cn
return cn, nil
}
4. veth 对创建
func createVethPair(containerID string) (string, string, error) {
hostVeth := fmt.Sprintf("vethh-%s", containerID[:8])
contVeth := fmt.Sprintf("vethc-%s", containerID[:8])
// 创建 veth 对
link := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: hostVeth,
},
PeerName: contVeth,
}
if err := netlink.LinkAdd(link); err != nil {
return "", "", fmt.Errorf("create veth pair: %w", err)
}
// 启动 host 端
if err := netlink.LinkSetUp(link); err != nil {
_ = netlink.LinkDel(link)
return "", "", fmt.Errorf("bring up host veth: %w", err)
}
return hostVeth, contVeth, nil
}
5. 网络配置
func (nm *NetworkManager) configureContainerNetwork(hostVeth, contVeth string, ip net.IP) error {
// 1. 将 host veth 添加到 bridge
hostLink, err := netlink.LinkByName(hostVeth)
if err != nil {
return err
}
bridgeLink, err := netlink.LinkByName(nm.bridgeName)
if err != nil {
return err
}
if err := netlink.LinkSetMaster(hostLink, bridgeLink); err != nil {
return fmt.Errorf("add veth to bridge: %w", err)
}
// 2. 配置容器端网络
contLink, err := netlink.LinkByName(contVeth)
if err != nil {
return err
}
// 设置 IP 地址
addr := &netlink.Addr{
IPNet: &net.IPNet{
IP: ip,
Mask: nm.subnet.Mask,
},
}
if err := netlink.AddrAdd(contLink, addr); err != nil {
return fmt.Errorf("set container IP: %w", err)
}
// 启动容器端
if err := netlink.LinkSetUp(contLink); err != nil {
return fmt.Errorf("bring up container veth: %w", err)
}
// 3. 设置默认路由
route := &netlink.Route{
Dst: &net.IPNet{IP: net.IPv4zero, Mask: net.CIDRMask(0, 32)},
Gw: nm.gateway,
LinkIndex: contLink.Attrs().Index,
}
if err := netlink.RouteAdd(route); err != nil {
return fmt.Errorf("add default route: %w", err)
}
return nil
}
多网络模式支持
1. 网络模式枚举
type NetworkMode string
const (
NetworkModeBridge NetworkMode = "bridge"
NetworkModeHost NetworkMode = "host"
NetworkModeNone NetworkMode = "none"
NetworkModeMacvlan NetworkMode = "macvlan"
)
2. 网络模式实现
func (nm *NetworkManager) SetupNetwork(mode NetworkMode, containerID string) (*ContainerNetwork, error) {
switch mode {
case NetworkModeBridge:
return nm.CreateContainerNetwork(containerID)
case NetworkModeHost:
return nm.setupHostNetwork(containerID)
case NetworkModeNone:
return nm.setupNoneNetwork(containerID)
case NetworkModeMacvlan:
return nm.setupMacvlanNetwork(containerID)
default:
return nil, fmt.Errorf("unsupported network mode: %s", mode)
}
}
func (nm *NetworkManager) setupHostNetwork(containerID string) (*ContainerNetwork, error) {
// Host 模式:直接使用宿主机网络
return &ContainerNetwork{
ID: containerID,
IP: nil, // 使用宿主机 IP
HostVeth: "",
ContVeth: "",
Bridge: "host",
CreatedAt: time.Now(),
}, nil
}
func (nm *NetworkManager) setupNoneNetwork(containerID string) (*ContainerNetwork, error) {
// None 模式:无网络配置
return &ContainerNetwork{
ID: containerID,
IP: nil,
HostVeth: "",
ContVeth: "",
Bridge: "none",
CreatedAt: time.Now(),
}, nil
}
网络清理
func (nm *NetworkManager) CleanupContainerNetwork(containerID string) error {
nm.mu.Lock()
defer nm.mu.Unlock()
cn, exists := nm.containers[containerID]
if !exists {
return fmt.Errorf("container %s not found", containerID)
}
// 释放 IP
if cn.IP != nil {
nm.ipam.Release(cn.IP)
}
// 删除 veth 对
if cn.HostVeth != "" {
if link, err := netlink.LinkByName(cn.HostVeth); err == nil {
_ = netlink.LinkDel(link)
}
}
delete(nm.containers, containerID)
return nil
}
实战练习
练习 1:基础网络实现
- 实现基本的 Bridge 网络
- 测试容器间通信
- 验证外网访问
验证步骤:
# 1. 编译程序
go build -o toyctr main.go
# 2. 启动第一个容器
sudo ./toyctr -cmd /bin/sh -args "-c 'sleep 600'" &
CONTAINER1_PID=$!
# 3. 启动第二个容器
sudo ./toyctr -cmd /bin/sh -args "-c 'sleep 600'" &
CONTAINER2_PID=$!
# 4. 测试容器间通信
sudo nsenter -t $CONTAINER1_PID -n ping -c 1 10.22.0.3
# 5. 测试外网访问
sudo nsenter -t $CONTAINER1_PID -n ping -c 1 8.8.8.8
练习 2:多网络模式
- 实现 Host 网络模式
- 实现 None 网络模式
- 测试不同模式的特点
验证步骤:
# 1. 测试 Host 模式
sudo ./toyctr -netmode host -cmd /bin/sh -args "-c 'ip addr show'"
# 2. 测试 None 模式
sudo ./toyctr -netmode none -cmd /bin/sh -args "-c 'ip addr show'"
# 3. 对比网络接口
# Host 模式应该看到所有宿主机接口
# None 模式应该只看到 lo 接口
练习 3:网络隔离
- 实现网络命名空间隔离
- 测试网络配置独立性
- 验证防火墙规则
验证步骤:
# 1. 在容器内配置网络
sudo nsenter -t $CONTAINER1_PID -n ip addr add 192.168.1.100/24 dev lo
# 2. 在宿主机检查
ip addr show | grep 192.168.1.100
# 应该看不到这个 IP
# 3. 在另一个容器检查
sudo nsenter -t $CONTAINER2_PID -n ip addr show | grep 192.168.1.100
# 也应该看不到
性能优化
1. 网络性能优化
- 使用 SR-IOV 技术
- 配置网络缓冲区大小
- 启用网络加速功能
2. 资源管理
- 限制网络带宽
- 监控网络使用情况
- 自动清理网络资源
3. 安全加固
- 配置网络策略
- 启用网络加密
- 监控网络流量
相关链接
- 05-容器网络原理 - 网络基础原理
- 07-CNI插件开发 - 网络插件开发
- 14-调试技术与工具 - 调试技术详解
下一步:让我们学习 CNI 插件开发,这是容器网络的高级应用!