容器网络CNI实战:从零搭建网络插件

容器网络CNI实战:从零搭建网络插件

一、CNI概述

CNI(Container Network Interface)是容器网络的标准化接口,定义了容器网络配置和管理的规范。

1.1 CNI架构

复制代码
┌─────────────────────┐
│     Container       │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│      CNI Plugin     │
│  (bridge, macvlan, │
│   flannel, calico)  │
└──────────┬──────────┘
           │
           ▼
┌─────────────────────┐
│      Network        │
│  (veth, bridge,    │
│   route, iptables)  │
└─────────────────────┘

1.2 CNI规范

CNI插件需要支持以下操作:

  • ADD:将容器添加到网络
  • DEL:从网络中移除容器
  • CHECK:检查网络状态
  • VERSION:返回版本信息

二、CNI配置文件

2.1 配置文件结构

json 复制代码
{
  "cniVersion": "0.4.0",
  "name": "my-network",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/16",
    "routes": [
      { "dst": "0.0.0.0/0" }
    ]
  }
}

2.2 配置参数说明

参数 说明 必填
cniVersion CNI版本
name 网络名称
type 插件类型
bridge 网桥名称
isGateway 是否作为网关
ipMasq 是否启用IP伪装
ipam IP地址管理配置

三、Bridge插件实战

3.1 安装CNI工具

bash 复制代码
# 下载CNI插件
mkdir -p /opt/cni/bin
cd /opt/cni/bin
wget https://github.com/containernetworking/plugins/releases/download/v1.3.0/cni-plugins-linux-amd64-v1.3.0.tgz
tar -xzf cni-plugins-linux-amd64-v1.3.0.tgz

3.2 创建配置文件

bash 复制代码
mkdir -p /etc/cni/net.d
cat > /etc/cni/net.d/10-bridge.conf <<EOF
{
  "cniVersion": "0.4.0",
  "name": "bridge-network",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.100.0.0/16",
    "gateway": "10.100.0.1",
    "routes": [
      { "dst": "0.0.0.0/0" }
    ]
  }
}
EOF

3.3 手动调用CNI插件

bash 复制代码
# 创建网络命名空间
ip netns add test-namespace

# 创建veth对
ip link add veth0 type veth peer name veth0-br

# 将veth一端加入网桥
ip link set veth0-br master cni0

# 将veth另一端加入命名空间
ip link set veth0 netns test-namespace

# 调用CNI ADD命令
cat > /tmp/cni-args.json <<EOF
{
  "containerid": "test-container",
  "netns": "/var/run/netns/test-namespace",
  "ifname": "eth0",
  "args": {
    "ignoreUnknown": true
  }
}
EOF

./bridge < /tmp/cni-args.json

3.4 Go语言调用CNI

go 复制代码
package main

import (
    "fmt"
    "os"
    
    "github.com/containernetworking/cni/pkg/invoke"
    "github.com/containernetworking/cni/pkg/types"
    "github.com/containernetworking/cni/pkg/types/current"
)

func main() {
    netConf := []byte(`{
        "cniVersion": "0.4.0",
        "name": "test-network",
        "type": "bridge",
        "ipam": {
            "type": "host-local",
            "subnet": "10.200.0.0/16"
        }
    }`)
    
    result, err := invoke.ExecPlugin(
        "/opt/cni/bin/bridge",
        netConf,
        []string{
            "CNI_COMMAND=ADD",
            "CNI_CONTAINERID=test-container",
            "CNI_NETNS=/var/run/netns/test",
            "CNI_IFNAME=eth0",
            "CNI_PATH=/opt/cni/bin",
        },
    )
    
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
    
    fmt.Println(string(result))
}

四、Flannel网络方案

4.1 Flannel架构

复制代码
┌─────────────────┐      VXLAN      ┌─────────────────┐
│   Node A        │ ──────────────> │   Node B        │
│  ┌───────────┐  │                │  ┌───────────┐  │
│  │ Container │  │                │  │ Container │  │
│  └─────┬─────┘  │                │  └─────┬─────┘  │
│        │        │                │        │        │
│  ┌─────┴─────┐  │                │  ┌─────┴─────┐  │
│  │ flannel0  │  │                │  │ flannel0  │  │
│  └─────┬─────┘  │                │  └─────┬─────┘  │
│        │        │                │        │        │
│  ┌─────┴─────┐  │                │  ┌─────┴─────┐  │
│  │   eth0    │  │────────────────│  │   eth0    │  │
│  └───────────┘  │                │  └───────────┘  │
└─────────────────┘                └─────────────────┘

4.2 安装Flannel

yaml 复制代码
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

4.3 Flannel配置

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "flannel",
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

五、Calico网络方案

5.1 Calico架构

复制代码
┌─────────────────────────────────────────────────────────────┐
│                      Felix Agent                           │
│  (管理路由、iptables规则)                                  │
└─────────────────────────────────────────────────────────────┘
                              │
          ┌───────────────────┼───────────────────┐
          ▼                   ▼                   ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│   BGP Router    │ │   IPAM          │ │   Policy Engine │
│  (路由分发)      │ │  (IP分配)        │ │  (网络策略)      │
└─────────────────┘ └─────────────────┘ └─────────────────┘

5.2 安装Calico

yaml 复制代码
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

5.3 Calico网络策略

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-http
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: web
  ingress:
    - from:
        - ipBlock:
            cidr: 10.0.0.0/8
      ports:
        - protocol: TCP
          port: 80

六、自定义CNI插件开发

6.1 插件结构

go 复制代码
package main

import (
    "fmt"
    "os"
    
    "github.com/containernetworking/cni/pkg/skel"
    "github.com/containernetworking/cni/pkg/types"
    "github.com/containernetworking/cni/pkg/types/current"
    "github.com/containernetworking/cni/pkg/version"
)

func cmdAdd(args *skel.CmdArgs) error {
    // 解析配置
    conf, err := parseConfig(args.StdinData)
    if err != nil {
        return fmt.Errorf("failed to parse config: %v", err)
    }
    
    // 创建网络接口
    iface, err := setupInterface(args)
    if err != nil {
        return fmt.Errorf("failed to setup interface: %v", err)
    }
    
    // 配置IP地址
    result, err := assignIP(conf, iface)
    if err != nil {
        return fmt.Errorf("failed to assign IP: %v", err)
    }
    
    return types.PrintResult(result, conf.CNIVersion)
}

func cmdDel(args *skel.CmdArgs) error {
    // 清理网络接口
    return teardownInterface(args)
}

func main() {
    skel.PluginMain(cmdAdd, cmdDel, version.All)
}

6.2 网络配置解析

go 复制代码
type NetConf struct {
    types.NetConf
    Bridge   string `json:"bridge"`
    VlanID   int    `json:"vlanID"`
    MTU      int    `json:"mtu"`
}

func parseConfig(data []byte) (*NetConf, error) {
    conf := &NetConf{}
    if err := json.Unmarshal(data, conf); err != nil {
        return nil, fmt.Errorf("failed to unmarshal config: %v", err)
    }
    
    // 设置默认值
    if conf.Bridge == "" {
        conf.Bridge = "cni0"
    }
    if conf.MTU == 0 {
        conf.MTU = 1500
    }
    
    return conf, nil
}

6.3 接口创建

go 复制代码
func setupInterface(args *skel.CmdArgs) (*current.Interface, error) {
    // 创建veth对
    hostVeth, contVeth, err := netlink.VethAdd(args.Netns, args.IfName)
    if err != nil {
        return nil, fmt.Errorf("failed to create veth: %v", err)
    }
    
    // 将host端加入网桥
    bridge, err := netlink.LinkByName(conf.Bridge)
    if err != nil {
        return nil, fmt.Errorf("failed to find bridge: %v", err)
    }
    
    if err := netlink.LinkSetMaster(hostVeth, bridge); err != nil {
        return nil, fmt.Errorf("failed to add to bridge: %v", err)
    }
    
    return &current.Interface{
        Name:    contVeth.Name,
        Mac:     contVeth.HardwareAddr.String(),
        Sandbox: args.Netns,
    }, nil
}

七、网络诊断与调试

7.1 常用命令

bash 复制代码
# 查看网络命名空间
ip netns list

# 进入命名空间执行命令
ip netns exec test-namespace ip addr

# 查看路由表
ip route show

# 查看iptables规则
iptables -t nat -L

# 查看网桥信息
brctl show

# 查看CNI配置
cat /etc/cni/net.d/*.conf

7.2 网络连通性测试

bash 复制代码
# 测试Pod间通信
kubectl exec -it pod1 -- ping pod2-ip

# 测试Pod到外部网络
kubectl exec -it pod1 -- ping 8.8.8.8

# 检查DNS解析
kubectl exec -it pod1 -- nslookup kubernetes.default

八、性能优化

8.1 调整MTU

json 复制代码
{
  "cniVersion": "0.4.0",
  "name": "optimized-network",
  "type": "bridge",
  "mtu": 9001,
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/16"
  }
}

8.2 使用高性能驱动

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-flannel-cfg
data:
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "host-gw"
      }
    }

8.3 禁用不必要的功能

json 复制代码
{
  "cniVersion": "0.4.0",
  "name": "minimal-network",
  "type": "bridge",
  "ipMasq": false,
  "ipam": {
    "type": "host-local",
    "subnet": "10.200.0.0/16"
  }
}

九、最佳实践总结

9.1 插件选择建议

场景 推荐插件 原因
单节点 bridge 简单高效
多节点 flannel 易于部署
大规模集群 calico 高性能、灵活策略
网络隔离要求高 calico 强大的网络策略

9.2 配置建议

  • 子网规划:根据集群规模合理分配CIDR
  • MTU设置:跨节点通信建议使用Jumbo Frame
  • IPAM选择:host-local适合小规模,dhcp适合大规模
  • 安全策略:生产环境建议启用网络策略

9.3 监控指标

  • 网络延迟:Pod间通信延迟
  • 带宽利用率:各节点网络使用情况
  • 丢包率:网络传输质量
  • 连接数:容器网络连接状态

通过合理选择和配置CNI插件,可以构建高效、可靠的容器网络环境。

相关推荐
Mahir081 小时前
Spring 事务深度解析:核心原理与 12 种事务失效场景全解
java·spring·面试·事务失效
SL_staff1 小时前
从Zoom/腾讯会议迁移到私有化会议系统:数据迁移完整方案
java·架构
笨蛋不要掉眼泪1 小时前
Java并发编程:内存可见性与synchronized同步机制
java·开发语言·并发
用户3959924940061 小时前
Java开发者接入大模型API实战:从0到聊天机器人
java
2301_803934611 小时前
SQL如何进行分组后字符串拼接_使用GROUP_CONCAT或STRING_AGG
jvm·数据库·python
JAVA面经实录9171 小时前
Java 多线程完整版学习文档(无遗漏终版)
java·面试
考虑考虑2 小时前
JDK26中的LazyConstant
java·后端·java ee
Devin~Y2 小时前
互联网大厂 Java 面试实录:JVM、Spring Boot、MyBatis、Redis、Kafka、Spring AI、K8s 全链路追问小Y
java·jvm·spring boot·redis·kafka·mybatis·spring security
摇滚侠2 小时前
SpringCloud 面试题 真正的 offer 偏方 Java 基础 Java 高级
java·spring·spring cloud