Kubernetes之CNI详解

本文尝试从Kubernetes CNI 历史、工作原理及伪代码实现3个方面对CNI进行详细介绍;最后列举CNI常见开源实现及其优缺点。希望对您有用!

Kubernetes CNI历史

要深入了解Kubernetes的CNI(Container Network Interface)历史,需要从其早期网络模型、CNI规范的引入、主要CNI插件的发展,以及社区的演进等方面进行详细探讨。

1. 初期的Kubernetes网络模型

在Kubernetes的早期版本(1.0及之前),网络配置相对简单,主要依赖于kubenet等内置网络插件。这些插件提供了基本的网络连接功能,但存在一些限制,例如:

  • 缺乏灵活性:早期的网络插件通常是特定于某种网络实现的,缺乏灵活性和扩展性。

  • 复杂的配置:配置和管理这些网络插件相对复杂,需要较高的运维成本。

2. CNI规范的提出

为了解决上述问题,CoreOS等公司提出了CNI(Container Network Interface)规范。CNI的设计目标是定义一个标准的接口,使得不同的网络实现可以通过统一的方式集成到Kubernetes中。

CNI规范的核心设计原则包括:

  • 插件化:CNI本身只是一个接口规范,具体的网络实现由各类CNI插件提供。

  • 简单性:CNI接口尽量简单,只关注容器的网络创建和删除。

  • 灵活性:允许各种网络方案通过CNI接口集成,从而支持多种网络模式和需求。

3. CNI的引入与Kubernetes的集成

Kubernetes从1.5版本开始正式集成CNI支持。随着CNI的引入,Kubernetes的网络功能变得更加灵活和可扩展。CNI接口标准化之后,开发者和运维人员可以根据需要选择和配置合适的CNI插件,以满足不同的网络需求。

4. 主要的CNI插件发展

随着CNI的普及,出现了许多流行的CNI插件,每种插件都有其独特的功能和适用场景。以下是一些主要的CNI插件及其发展历程:

  • Flannel

    • 作为最早的CNI插件之一,Flannel由CoreOS开发,旨在提供简单的覆盖网络。

    • 其主要特点是易于配置,适合轻量级集群。

  • Calico

    • Calico最初由Tigera开发,提供网络策略、安全性和高性能网络功能。

    • 通过支持BGP(边界网关协议)等技术,Calico可以实现大规模集群的高效路由。

  • Weave

    • Weave由Weaveworks开发,强调简单性和易用性。

    • 它支持网络隔离和加密,适合对安全性有较高要求的应用。

  • Cilium

    • 由Isovalent开发的Cilium利用eBPF技术,实现高性能网络和强大的网络安全功能。

    • Cilium特别适用于需要复杂网络策略和可观测性的场景。

  • Contiv

    • Contiv由Cisco开发,提供多种网络模式(如覆盖网络和原生网络)。

    • 它适用于多样化的企业需求,支持复杂的网络拓扑和策略。

5. CNI的发展与社区支持

随着Kubernetes的快速发展,CNI规范也在不断演进和完善。Kubernetes社区和各大云提供商对CNI的支持和推动,促使其成为Kubernetes网络实现的主流方式。主要的发展包括:

  • 增强的可观测性:新的CNI插件和工具提供了更强的网络监控和诊断能力。

  • 性能优化:通过利用eBPF等新技术,CNI插件的性能不断提升,满足高性能应用的需求。

  • 增强的安全性:通过支持更复杂的网络策略和隔离机制,CNI插件的安全性得到了显著提升。

  • 多集群支持:一些CNI插件开始支持跨集群的网络连接和策略管理,适应多云和混合云的需求。

6. 未来的方向

CNI的未来发展方向包括:

  • 更强的集成与自动化:通过与Kubernetes其他组件的更紧密集成,实现更高程度的自动化管理。

  • 多租户支持:提供更完善的多租户隔离和管理机制,满足企业级应用需求。

  • 扩展的生态系统:更多的网络插件和工具将加入CNI生态系统,提供丰富的网络功能和选择。

总结

CNI的引入和发展极大地推动了Kubernetes网络的灵活性和可扩展性。通过标准化接口和插件化机制,CNI为Kubernetes提供了多样化的网络实现方式,满足了不同场景下的网络需求。随着技术的不断进步和社区的持续推动,CNI将在未来继续发挥重要作用,推动Kubernetes网络技术的发展。

Kubernetes CNI工作原理

Kubernetes中的CNI(Container Network Interface)是实现容器网络的标准接口。它提供了插件化的机制,使得各种网络方案可以通过统一的方式集成到Kubernetes中。下面是CNI的详细工作原理和与其他组件的交互逻辑。

基本组件和概念
  1. Kubelet:Kubernetes在每个节点上的代理,负责管理该节点上的Pod和容器。

  2. CRI(Container Runtime Interface):Kubernetes与容器运行时(如Docker、containerd)之间的接口。

  3. CNI插件:实现具体网络功能的插件,如Flannel、Calico、Weave等。

  4. IPAM(IP Address Management):IP地址管理模块,负责分配和管理Pod的IP地址。

  5. etcd:分布式键值存储,用于存储集群的配置信息和状态。

CNI工作流程
  1. Pod创建请求:用户通过Kubernetes API Server发送Pod创建请求。

  2. 调度器分配节点:Kubernetes调度器将Pod调度到适当的节点。

  3. Kubelet接收指令:节点上的Kubelet接收到创建Pod的指令。

  4. 调用CRI:Kubelet通过CRI调用容器运行时(如containerd)来创建容器。

  5. 调用CNI插件:在容器创建过程中,Kubelet调用CNI插件来配置网络。

CNI插件详细工作步骤
  1. CNI配置文件:每个节点上都有一个CNI配置文件(通常位于/etc/cni/net.d目录下),定义了CNI插件的类型和配置。

  2. 调用CNI插件:Kubelet根据配置文件调用相应的CNI插件。

  3. 创建网络接口:CNI插件在宿主机和容器网络命名空间中创建veth对。

  4. 分配IP地址:CNI插件调用IPAM模块分配IP地址。

  5. 设置路由和防火墙规则:CNI插件配置必要的路由和防火墙规则,以确保Pod之间及Pod与外部网络的通信。

  6. 返回结果:CNI插件将配置结果返回给Kubelet,Kubelet完成Pod的启动。

与其他组件的交互逻辑示意图
+---------------------------------------+
| Kubernetes Master                     |
|                                       |
| +-------------+   +---------------+   |
| | API Server  |   | Scheduler     |   |
| +-------------+   +---------------+   |
|                                       |
| +-----------------+   +-------------+ |
| | etcd            |   | Controller  | |
| +-----------------+   +-------------+ |
|                                       |
+-------------------------|-------------+
                          |
                          v
+---------------------------------------+
| Kubernetes Node                      |
|                                       |
| +----------------+                   |
| | Kubelet        |                   |
| |                |                   |
| | +------------+ |                   |
| | | CRI        | |                   |
| | |            | |                   |
| | | +--------+ | |                   |
| | | | runtime| | |                   |
| | | | (e.g., | | |                   |
| | | |Docker) | | |                   |
| | | +--------+ | |                   |
| | +------------+ |                   |
| +----------------+                   |
|          |                           |
|          v                           |
| +----------------+   +-------------+ |
| | CNI Plugin     |   | Pod Network | |
| | (e.g., Flannel,|   | Namespace   | |
| |  Calico, Weave)|   +-------------+ |
| +----------------+                   |
|                                       |
| +-----------------+                  |
| | IPAM            |                  |
| +-----------------+                  |
+---------------------------------------+
具体交互步骤
  1. Pod创建请求

  • 用户通过kubectl或其他方式向API Server发送Pod创建请求。

  • API Server将请求写入etcd。

调度器分配节点

  • 调度器读取etcd中的Pod信息,根据调度策略决定将Pod分配到哪个节点。

  • 调度器将决策结果写回etcd。

Kubelet接收指令

  • Kubelet监听etcd中的变化,发现新的Pod分配到本节点。

  • Kubelet通过CRI调用容器运行时(如containerd)来创建Pod容器。

调用CNI插件

  • 在容器创建过程中,Kubelet根据CNI配置文件调用相应的CNI插件。

  • CNI插件在宿主机和容器网络命名空间中创建veth对。

IP地址分配和网络配置

  • CNI插件通过IPAM模块为Pod分配IP地址。

  • CNI插件配置必要的路由和防火墙规则,确保Pod之间及Pod与外部网络的通信。

完成Pod创建

  • CNI插件将配置结果返回给Kubelet。

  • Kubelet完成Pod的启动,Pod开始运行。

总结

Kubernetes的CNI机制通过标准化接口和插件化设计,实现了灵活、可扩展的容器网络配置。Kubelet通过调用CNI插件来配置Pod的网络,CNI插件则负责具体的网络接口创建、IP地址分配、路由和防火墙规则设置。这个流程确保了Pod在Kubernetes集群中的正常通信和网络隔离。

Kubernetes CNI 伪代码实现

要实现一个简单的CNI插件,首先需要了解CNI插件的基本工作流程和要求。CNI插件通常是一个可执行文件,Kubelet会在创建或删除Pod时调用该文件。插件需要处理两个主要操作:ADDDEL

以下是一个用Go语言实现的CNI插件的伪代码示例。这个示例实现了一个非常简单的CNI插件,仅用于演示基本的CNI接口调用和网络配置流程。

1. 项目结构

假设项目结构如下:

my-cni-plugin/
├── main.go
├── config.go
└── net.go

2. config.go:配置文件读取

首先,我们需要一个结构来读取和解析CNI配置文件:

package main


import (
    "encoding/json"
    "io/ioutil"
)


type NetConf struct {
    CniVersion string `json:"cniVersion"`
    Name       string `json:"name"`
    Type       string `json:"type"`
    Ipam       struct {
        Type    string `json:"type"`
        Subnet  string `json:"subnet"`
        Gateway string `json:"gateway"`
    } `json:"ipam"`
}


func loadNetConf(bytes []byte) (*NetConf, error) {
    netConf := &NetConf{}
    if err := json.Unmarshal(bytes, netConf); err != nil {
        return nil, err
    }
    return netConf, nil
}

3. net.go:网络配置

然后,我们需要实现网络配置功能,包括创建veth对、分配IP地址、设置路由等:

package main


import (
    "net"
    "os/exec"


    "github.com/vishvananda/netlink"
)


func createVethPair(hostIfName, contIfName string, mtu int) error {
    veth := &netlink.Veth{
        LinkAttrs: netlink.LinkAttrs{
            Name:  hostIfName,
            MTU:   mtu,
        },
        PeerName: contIfName,
    }
    return netlink.LinkAdd(veth)
}


func setupContainerNetwork(netnsPath, contIfName, ip, gateway string) error {
    // Use nsenter to enter the container network namespace
    cmd := exec.Command("nsenter", "--net="+netnsPath, "ip", "addr", "add", ip, "dev", contIfName)
    if err := cmd.Run(); err != nil {
        return err
    }
    cmd = exec.Command("nsenter", "--net="+netnsPath, "ip", "link", "set", contIfName, "up")
    if err := cmd.Run(); err != nil {
        return err
    }
    cmd = exec.Command("nsenter", "--net="+netnsPath, "ip", "route", "add", "default", "via", gateway)
    return cmd.Run()
}

4. main.go:主程序

最后,主程序负责处理ADDDEL操作:

package main


import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "os"
)


func main() {
    if len(os.Args) < 2 {
        log.Fatalf("Usage: %s <config>", os.Args[0])
    }


    // Read the configuration from stdin
    stdin := os.Stdin
    bytes, err := ioutil.ReadAll(stdin)
    if err != nil {
        log.Fatalf("Failed to read stdin: %v", err)
    }


    // Load the network configuration
    netConf, err := loadNetConf(bytes)
    if err != nil {
        log.Fatalf("Failed to load net configuration: %v", err)
    }


    // Handle CNI commands
    cmd := os.Getenv("CNI_COMMAND")
    containerID := os.Getenv("CNI_CONTAINERID")
    netns := os.Getenv("CNI_NETNS")
    ifName := os.Getenv("CNI_IFNAME")
    // Note: In a real implementation, you should validate these environment variables


    switch cmd {
    case "ADD":
        err = handleAdd(containerID, netns, ifName, netConf)
    case "DEL":
        err = handleDel(containerID, netns, ifName, netConf)
    default:
        log.Fatalf("Unknown CNI_COMMAND: %s", cmd)
    }


    if err != nil {
        log.Fatalf("Error handling %s command: %v", cmd, err)
    }
}


func handleAdd(containerID, netns, ifName string, netConf *NetConf) error {
    hostIfName := fmt.Sprintf("veth%s", containerID[:5])
    contIfName := ifName


    // Create veth pair
    if err := createVethPair(hostIfName, contIfName, 1500); err != nil {
        return fmt.Errorf("failed to create veth pair: %v", err)
    }


    // Allocate IP address (for simplicity, using a hardcoded IP here)
    ip := "10.0.0.2/24"
    gateway := netConf.Ipam.Gateway


    // Setup container network namespace
    if err := setupContainerNetwork(netns, contIfName, ip, gateway); err != nil {
        return fmt.Errorf("failed to setup container network: %v", err)
    }


    // Output the result in CNI result format
    result := map[string]interface{}{
        "cniVersion": netConf.CniVersion,
        "interfaces": []map[string]string{
            {
                "name": ifName,
                "mac":  "00:00:00:00:00:01", // Example MAC address
            },
        },
        "ips": []map[string]string{
            {
                "address": ip,
                "gateway": gateway,
            },
        },
    }
    resultBytes, err := json.Marshal(result)
    if err != nil {
        return fmt.Errorf("failed to marshal result: %v", err)
    }


    fmt.Fprintln(os.Stdout, string(resultBytes))
    return nil
}


func handleDel(containerID, netns, ifName string, netConf *NetConf) error {
    // Here you should clean up the network resources allocated for the container
    // For simplicity, this example doesn't implement the cleanup logic
    return nil
}

解释

  • config.go:定义了一个NetConf结构,用于读取和解析CNI配置文件。

  • net.go:包含了创建veth对和设置容器网络的功能。

  • main.go:主程序,处理ADDDEL命令,并调用相应的网络配置函数。

运行和测试

要运行这个CNI插件,需要在Kubernetes节点上安装并配置CNI插件。以下是一个简单的测试步骤:

  1. 编译并安装CNI插件:

    go build -o my-cni-plugin main.go config.go net.go
    sudo mv my-cni-plugin /opt/cni/bin/
  2. 创建一个CNI配置文件(例如:/etc/cni/net.d/10-my-cni-plugin.conf):

    {
      "cniVersion": "0.4.0",
      "name": "my-cni",
      "type": "my-cni-plugin",
      "ipam": {
        "type": "host-local",
        "subnet": "10.0.0.0/24",
        "gateway": "10.0.0.1"
      }
    }
  3. 在Kubernetes集群中创建一个Pod,并观察CNI插件的执行情况。

这个简单的CNI插件示例仅用于演示基本原理,实际生产环境中的CNI插件需要处理更多的细节和错误情况。

Kubernetes CNI 常见开源实现及其优缺点

常见的开源CNI实现主要包括Flannel、Calico、Weave、Cilium和Multus等。每个CNI插件都有其独特的优势和特点,适用于不同的使用场景和需求。以下是这些CNI插件的详细介绍及其在计算机网络中的实现层次:

1. Flannel

优势和特点

  • 简单易用:Flannel非常易于安装和配置,适合初学者和中小型集群。

  • 多种后端支持:支持多种后端,包括VXLAN、host-gw、AWS VPC、GCE路由等,用户可以根据需要选择合适的后端。

  • 性能较好:在使用host-gw模式时,性能较好,因为数据包不需要经过额外的封装和解封装。

网络层次

  • 网络层(Layer 3):Flannel主要在网络层(第三层)工作,通过为每个节点分配一个子网,并使用各种隧道协议(如VXLAN)来实现跨节点的Pod通信。

2. Calico

优势和特点

  • 网络策略(Network Policy)支持:Calico提供强大的网络策略功能,可以精细地控制Pod之间的通信。

  • 高性能:使用纯IP路由,避免了封装和解封装的开销,具有高性能和低延迟的优势。

  • 集成BGP:支持使用BGP(边界网关协议)来实现跨节点的路由,有助于在大型集群中实现高效的网络拓扑。

  • 灵活性强:不仅支持容器网络,还支持虚拟机和裸机网络,使其适用于混合环境。

网络层次

  • 网络层(Layer 3):Calico主要在网络层工作,通过使用BGP和IP路由来实现跨节点的通信。

3. Weave

优势和特点

  • 简单安装:Weave提供了简单的安装和自动配置功能,易于上手。

  • 自动发现和管理:支持自动发现新节点和Pod,并自动管理网络拓扑。

  • 加密通信:支持加密通信,可以在不安全的网络环境中提供安全的Pod间通信。

  • DNS集成:提供内置的DNS服务,可以自动解析Pod名称,简化服务发现。

网络层次

  • 数据链路层(Layer 2)和网络层(Layer 3):Weave可以在数据链路层和网络层工作,通过使用基于MAC地址的转发机制和IP路由来实现Pod间通信。

4. Cilium

优势和特点

  • eBPF技术:基于Linux内核的eBPF(Extended Berkeley Packet Filter)技术,实现高性能的网络数据包处理和策略管理。

  • 安全性强:提供强大的网络安全策略和加密功能,可以精细控制网络访问。

  • 灵活性高:支持多种网络协议和架构,可以在容器、虚拟机和裸机环境中使用。

  • 观察性好:提供丰富的可观察性工具,帮助监控和调试网络流量和策略。

网络层次

  • 网络层(Layer 3)和传输层(Layer 4):Cilium在网络层和传输层工作,使用eBPF在内核中高效地处理数据包和应用网络策略。

5. Multus

优势和特点

  • 多网络支持:允许Pod连接到多个网络,使其能够支持多种网络需求,如管理网络和数据网络分离。

  • 兼容性好:与其他CNI插件兼容,可以作为一个元插件来调用其他CNI插件。

  • 灵活配置:提供灵活的配置选项,可以满足各种复杂的网络需求。

网络层次

  • 控制层:Multus本身不处理数据包的转发,而是作为一个元插件来协调和调用其他实际处理数据包的CNI插件。

总结

插件优势和特点网络层次
Flannel简单易用,多种后端支持,性能较好网络层(Layer 3)
Calico强大的网络策略,高性能,集成BGP,灵活性强网络层(Layer 3)
Weave简单安装,自动发现和管理,加密通信,DNS集成数据链路层(Layer 2)和网络层(Layer 3)
Cilium基于eBPF,高性能和安全性强,灵活性高,观察性好网络层(Layer 3)和传输层(Layer 4)
Multus多网络支持,兼容性好,灵活配置控制层(调用其他CNI插件)

每个CNI插件在不同的层次和功能上都有其优势和特点,选择合适的CNI插件取决于具体的使用场景和需求。

完。

希望对您有用!关注锅总,及时获得更多花里胡哨的运维实用操作!

9a21428d5b09714c1783a4a3907f304f.jpeg

锅总微信公众号

1ed5825dabafd630821c31bd25292456.png

锅总个人博客

https://gentlewok.blog.csdn.net/

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值