HiHuo
首页
博客
手册
工具
首页
博客
手册
工具
  • 手撸容器系统

    • 完整手撸容器技术文档系列
    • 01-容器本质与基础概念
    • 02-Namespace隔离机制
    • 03-CGroup资源控制
    • 04-Capabilities与安全机制
    • 05-容器网络原理
    • 06-网络模式与实现
    • 07-CNI插件开发
    • 08-RootFS与文件系统隔离
    • 09-OverlayFS镜像分层
    • 10-命令行手撸容器
    • 11-Go实现最小容器
    • 12-Go实现完整容器
    • 13-容器生命周期管理
    • 14-调试技术与工具
    • 15-OCI规范与标准化
    • 16-进阶场景与优化
    • 常见问题与故障排查
    • 参考资料与延伸阅读

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虚拟可扩展 LAN24位 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:基础网络实现

  1. 实现基本的 Bridge 网络
  2. 测试容器间通信
  3. 验证外网访问

验证步骤:

# 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:多网络模式

  1. 实现 Host 网络模式
  2. 实现 None 网络模式
  3. 测试不同模式的特点

验证步骤:

# 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. 实现网络命名空间隔离
  2. 测试网络配置独立性
  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 插件开发,这是容器网络的高级应用!

Prev
05-容器网络原理
Next
07-CNI插件开发