HiHuo
首页
博客
手册
工具
关于
首页
博客
手册
工具
关于
  • 网络架构师学习手册

    • 网络架构师学习教程
    • 基础篇

      • 第1章 网络模型与数据流转
      • 第2章 以太网与二层通信
      • 第3章 IP路由与三层转发
      • 第4章 TCP与可靠传输
      • 第5章 应用层协议
    • Linux网络栈

      • 第6章 数据包接收路径
      • 第7章 多核网络优化
      • 第8章 Netfilter与防火墙
      • 第9章 流量控制与QoS
    • 虚拟网络

      • 第10章 Network Namespace基础
      • 第11章 Bridge与互联
      • 第12章 VXLAN与Overlay网络
      • 第13章 OVS与SDN
    • Kubernetes网络

      • 第14章 CNI模型与实现
      • 第15章 kube-proxy与Service实现
      • 第16章 CoreDNS与服务发现
      • 第17章 NetworkPolicy与安全隔离
      • 第18章 Calico网络深度解析
      • 第19章 Cilium与eBPF网络
    • 网络架构

      • 第20章 网络设备与拓扑设计
      • 第21章 网络容量规划与计算
      • 第22章 负载均衡架构设计
      • 第23章 高可用网络架构
      • 第24章 网络安全架构
    • 性能调优

      • 第25章 系统级网络调优
      • 第26章 故障排查方法论
      • 第27章 生产环境案例分析
    • 前沿技术

      • 第28章 eBPF深度实践
      • 第29章 ServiceMesh与边车代理
      • 第30章 网络技术趋势与未来展望
    • 附录

      • 附录A:命令速查手册
      • 附录B:排错决策树
      • 附录C:学习资源
      • 附录D:技能图谱

第14章 CNI模型与实现

学习目标

  • 理解CNI(Container Network Interface)规范和工作原理
  • 掌握主流CNI插件的配置和使用
  • 能够开发自定义CNI插件
  • 了解CNI在Kubernetes网络中的作用

前置知识

  • 第10章:Network Namespace基础
  • 第11章:Linux Bridge与互联
  • 第12章:VXLAN与Overlay

14.1 CNI概述

14.1.1 什么是CNI

CNI(Container Network Interface)是一个用于配置容器网络的标准接口规范,定义了容器运行时与网络插件之间的通信协议。

核心特点:

  • 插件化架构,支持多种网络实现
  • 标准化的配置接口
  • 支持多网络接口
  • 与容器运行时解耦

14.1.2 CNI架构

┌─────────────────────────────────────────────────────────────┐
│                    CNI Architecture                        │
├─────────────────────────────────────────────────────────────┤
│  Container Runtime (containerd, CRI-O, Docker)            │
├─────────────────────────────────────────────────────────────┤
│  CNI Plugin Interface                                      │
├─────────────────────────────────────────────────────────────┤
│  CNI Plugins (bridge, host-local, flannel, calico, etc.)  │
├─────────────────────────────────────────────────────────────┤
│  Network Implementation (Linux Bridge, VXLAN, etc.)        │
└─────────────────────────────────────────────────────────────┘

14.1.3 CNI工作流程

  1. 容器创建:容器运行时创建网络命名空间
  2. 插件调用:运行时调用CNI插件配置网络
  3. 网络配置:插件创建网络接口和路由
  4. 容器销毁:运行时调用插件清理网络资源

14.2 CNI规范详解

14.2.1 CNI配置格式

基本配置结构:

{
  "cniVersion": "0.4.0",
  "name": "mynet",
  "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" }
    ]
  }
}

配置字段说明:

  • cniVersion:CNI规范版本
  • name:网络名称
  • type:插件类型
  • bridge:网桥名称
  • isGateway:是否作为网关
  • ipMasq:是否启用IP伪装
  • ipam:IP地址管理配置

14.2.2 CNI插件接口

ADD命令:

{
  "cniVersion": "0.4.0",
  "name": "mynet",
  "type": "bridge",
  "bridge": "cni0",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/16"
  }
}

DEL命令:

{
  "cniVersion": "0.4.0",
  "name": "mynet",
  "type": "bridge",
  "bridge": "cni0"
}

14.2.3 环境变量

CNI插件通过环境变量获取运行时信息:

# 容器网络命名空间路径
CNI_NETNS=/proc/12345/ns/net

# 容器网络接口名称
CNI_IFNAME=eth0

# 容器ID
CNI_CONTAINERID=container-123

# 配置数据
CNI_ARGS=key1=value1;key2=value2

# 配置路径
CNI_PATH=/opt/cni/bin

14.3 主流CNI插件

14.3.1 Bridge插件

功能: 创建Linux网桥,实现容器间通信

配置示例:

{
  "cniVersion": "0.4.0",
  "name": "bridge",
  "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" }
    ]
  }
}

工作原理:

  1. 创建Linux网桥
  2. 创建veth pair
  3. 将veth一端连接到网桥
  4. 将veth另一端移动到容器命名空间
  5. 配置IP地址和路由

14.3.2 Host-local IPAM

功能: 本地IP地址管理

配置示例:

{
  "type": "host-local",
  "subnet": "10.244.0.0/16",
  "rangeStart": "10.244.1.0",
  "rangeEnd": "10.244.1.255",
  "gateway": "10.244.0.1",
  "routes": [
    { "dst": "0.0.0.0/0", "gw": "10.244.0.1" }
  ]
}

14.3.3 Flannel插件

功能: 基于VXLAN的Overlay网络

配置示例:

{
  "name": "cbr0",
  "cniVersion": "0.3.1",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

14.4 实验:使用CNI插件

14.4.1 环境准备

安装CNI工具:

# 下载CNI插件
wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz

# 解压到CNI路径
sudo mkdir -p /opt/cni/bin
sudo tar -C /opt/cni/bin -xzf cni-plugins-linux-amd64-v1.1.1.tgz

# 验证安装
ls /opt/cni/bin/

14.4.2 实验1:Bridge插件

步骤1:创建网络命名空间

# 创建命名空间
sudo ip netns add test-ns

# 查看命名空间
ip netns list

步骤2:创建CNI配置

# 创建配置目录
sudo mkdir -p /etc/cni/net.d

# 创建Bridge配置
sudo cat > /etc/cni/net.d/10-bridge.conf << EOF
{
  "cniVersion": "0.4.0",
  "name": "bridge",
  "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" }
    ]
  }
}
EOF

步骤3:调用CNI插件

# 设置环境变量
export CNI_NETNS=/proc/$(ip netns exec test-ns sh -c 'echo $$')/ns/net
export CNI_IFNAME=eth0
export CNI_CONTAINERID=test-container
export CNI_PATH=/opt/cni/bin

# 调用ADD命令
echo '{"cniVersion": "0.4.0", "name": "bridge", "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"}]}}' | sudo CNI_COMMAND=ADD CNI_NETNS=$CNI_NETNS CNI_IFNAME=$CNI_IFNAME CNI_CONTAINERID=$CNI_CONTAINERID CNI_PATH=$CNI_PATH /opt/cni/bin/bridge

步骤4:验证配置

# 查看网桥
ip link show cni0

# 查看命名空间中的接口
ip netns exec test-ns ip addr show

# 查看路由
ip netns exec test-ns ip route show

14.4.3 实验2:多网络接口

步骤1:创建第二个网络

# 创建第二个网络配置
sudo cat > /etc/cni/net.d/20-macvlan.conf << EOF
{
  "cniVersion": "0.4.0",
  "name": "macvlan",
  "type": "macvlan",
  "master": "eth0",
  "mode": "bridge",
  "ipam": {
    "type": "host-local",
    "subnet": "192.168.1.0/24",
    "rangeStart": "192.168.1.100",
    "rangeEnd": "192.168.1.200"
  }
}
EOF

步骤2:添加第二个接口

# 调用macvlan插件
echo '{"cniVersion": "0.4.0", "name": "macvlan", "type": "macvlan", "master": "eth0", "mode": "bridge", "ipam": {"type": "host-local", "subnet": "192.168.1.0/24", "rangeStart": "192.168.1.100", "rangeEnd": "192.168.1.200"}}' | sudo CNI_COMMAND=ADD CNI_NETNS=$CNI_NETNS CNI_IFNAME=eth1 CNI_CONTAINERID=test-container CNI_PATH=$CNI_PATH /opt/cni/bin/macvlan

步骤3:验证多接口

# 查看所有接口
ip netns exec test-ns ip addr show

# 测试连通性
ip netns exec test-ns ping -c 3 192.168.1.1

14.5 开发自定义CNI插件

14.5.1 插件结构

基本插件结构:

package main

import (
    "encoding/json"
    "fmt"
    "os"
    "github.com/containernetworking/cni/pkg/skel"
    "github.com/containernetworking/cni/pkg/version"
)

type NetConf struct {
    CNIVersion string `json:"cniVersion"`
    Name       string `json:"name"`
    Type       string `json:"type"`
    Bridge     string `json:"bridge"`
}

func cmdAdd(args *skel.CmdArgs) error {
    // 解析配置
    conf := NetConf{}
    if err := json.Unmarshal(args.StdinData, &conf); err != nil {
        return err
    }
    
    // 实现ADD逻辑
    fmt.Printf("Adding network %s\n", conf.Name)
    
    return nil
}

func cmdDel(args *skel.CmdArgs) error {
    // 实现DEL逻辑
    fmt.Printf("Deleting network\n")
    
    return nil
}

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

14.5.2 编译和测试

编译插件:

# 创建Go模块
go mod init my-cni-plugin

# 安装依赖
go get github.com/containernetworking/cni/pkg/skel
go get github.com/containernetworking/cni/pkg/version

# 编译
go build -o my-cni-plugin

# 安装到CNI路径
sudo cp my-cni-plugin /opt/cni/bin/

测试插件:

# 创建测试配置
sudo cat > /etc/cni/net.d/30-my-plugin.conf << EOF
{
  "cniVersion": "0.4.0",
  "name": "my-plugin",
  "type": "my-cni-plugin",
  "bridge": "my-bridge"
}
EOF

# 测试ADD命令
echo '{"cniVersion": "0.4.0", "name": "my-plugin", "type": "my-cni-plugin", "bridge": "my-bridge"}' | sudo CNI_COMMAND=ADD CNI_NETNS=$CNI_NETNS CNI_IFNAME=eth0 CNI_CONTAINERID=test-container CNI_PATH=$CNI_PATH /opt/cni/bin/my-cni-plugin

14.6 CNI在Kubernetes中的应用

14.6.1 Kubelet CNI配置

Kubelet配置:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cniConfDir: /etc/cni/net.d
cniBinDir: /opt/cni/bin
cniCacheDir: /var/lib/cni/cache

14.6.2 多网络支持

NetworkAttachmentDefinition:

apiVersion: "k8s.cni.cncf.io/v1"
kind: NetworkAttachmentDefinition
metadata:
  name: macvlan-conf
spec:
  config: |
    {
      "cniVersion": "0.4.0",
      "name": "macvlan",
      "type": "macvlan",
      "master": "eth0",
      "mode": "bridge",
      "ipam": {
        "type": "host-local",
        "subnet": "192.168.1.0/24"
      }
    }

Pod使用多网络:

apiVersion: v1
kind: Pod
metadata:
  name: multi-net-pod
  annotations:
    k8s.v1.cni.cncf.io/networks: macvlan-conf
spec:
  containers:
  - name: app
    image: nginx

14.7 故障排查

14.7.1 常见问题诊断

问题1:CNI插件调用失败

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

# 检查插件权限
ls -la /opt/cni/bin/

# 查看Kubelet日志
journalctl -u kubelet -f

问题2:网络接口创建失败

# 检查命名空间
ip netns list

# 检查网桥状态
ip link show cni0

# 查看CNI日志
tail -f /var/log/cni.log

问题3:IP地址分配失败

# 检查IPAM状态
cat /var/lib/cni/networks/bridge/last_reserved_ip.0

# 检查子网配置
ip route show

14.7.2 调试工具

# 使用CNI调试工具
CNI_COMMAND=ADD CNI_NETNS=/proc/12345/ns/net CNI_IFNAME=eth0 CNI_CONTAINERID=test CNI_PATH=/opt/cni/bin /opt/cni/bin/bridge < config.json

# 查看CNI缓存
ls -la /var/lib/cni/cache/

# 清理CNI状态
rm -rf /var/lib/cni/cache/*

14.8 排错清单

14.8.1 CNI配置检查

  • [ ] CNI配置文件格式是否正确
  • [ ] 插件是否存在于CNI路径
  • [ ] 插件是否有执行权限
  • [ ] 网络命名空间是否存在
  • [ ] IPAM配置是否正确

14.8.2 网络连通性检查

  • [ ] 网桥是否创建成功
  • [ ] veth pair是否正确创建
  • [ ] IP地址是否分配成功
  • [ ] 路由表是否正确
  • [ ] 防火墙规则是否阻止流量

14.8.3 性能问题检查

  • [ ] 插件执行时间是否过长
  • [ ] 网络接口数量是否过多
  • [ ] IP地址池是否耗尽
  • [ ] 网桥转发性能是否正常
  • [ ] 内存使用是否正常

14.9 延伸阅读

  • CNI Specification
  • CNI Plugins
  • Kubernetes Network Plugins
  • Multus CNI

下一章:第15章 kube-proxy与Service

返回目录:README

Next
第15章 kube-proxy与Service实现