cni 插件 flannel-vxlan 使用流程分析

共 2313字,需浏览 5分钟

 ·

2022-04-27 21:17

这里主要研究 flannel-vxlan ,flannel-vxlan 是 overlay 类型的网络。本次实操无需安装 Kubernetes,直接调用插件来配置容器网络。

CNI 插件的本质工作有两个:

  • 工作一:配置容器网络命名空间的网络
  • 工作二:路由各个网络命名空间的网络流量

工作一需要实现 CNI 相关的接口,从而可以通过外部对插件进行调用。工作二常常需要额外的守护进程来完成,在 Kubernetes 中一般以 DaemonSet 的形式部署,同时以 Kubernetes 的 etcd 作为数据存储的后端。

环境介绍

  • 节点0,10.211.55.2(用于部署 etcd)
  • 节点1,10.211.55.32
  • 节点2,10.211.55.57

事前准备

在节点0上部署 etcd 为网络插件提供存储服务,这里使用 Docker 部署,暴露端口为 2379,相关官网教程见 https://etcd.io/docs/v3.4/op-guide/container/ ,启动参数见 https://etcd.io/docs/v3.4/op-guide/configuration/。

docker run -p 2379:2379 quay.io/coreos/etcd:v3.3.1 /usr/local/bin/etcd --advertise-client-urls http://10.211.55.2:2379 --listen-client-urls http://0.0.0.0:2379

安装 etcdctl 工具,相关教程见 https://gist.github.com/sanjid133/fffaae1c7deb7c3d6c5f6bae549d6380,当然,也可以使用 docker exec 登录到 etcd 容器中使用它自带的 etcdctl。

安装 cni 基础网络插件至 /opt/cni/bin 下,插件仓库在 https://github.com/containernetworking/plugins 上,直接下载编译好的 release https://github.com/containernetworking/plugins/releases 然后解压到 /opt/cni/bin 下即可。

直接使用 https://www.cni.dev/docs/cnitool/ 或者自己编写如下程序调用 CNI 插件,这里采用第二种方式,该程序最终会被编译为 cnidemo

package main

import (
  "context"
  "flag"
  "fmt"
  "log"
  "os"
  "os/signal"
  "strconv"

  gocni "github.com/containerd/go-cni"
)

var (
  idF = flag.Int("id", 2, "")
  confFF = flag.String("conf""/etc/cni/net.d/11-flannel.conf""")
)

func init() {
  flag.Parse()
}

func main() {
  id := *idF
  netns := fmt.Sprintf("/var/run/netns/ns-%d", id)

  l, err := gocni.New(
    gocni.WithMinNetworkCount(2),
    gocni.WithPluginDir([]string{"/opt/cni/bin"}),
    gocni.WithInterfacePrefix("eth"))
  if err != nil {
    log.Fatalf("failed to initialize cni library: %v", err)
  }

  if err := l.Load(gocni.WithLoNetwork, gocni.WithConfListFile(*confFF)); err != nil {
    log.Fatalf("failed to load cni configuration: %v", err)
  }

  ctx := context.Background()
  defer func() {
    if err := l.Remove(ctx, strconv.Itoa(id), netns); err != nil {
      log.Fatalf("failed to teardown network: %v", err)
    }
  }()

  result, err := l.Setup(ctx, strconv.Itoa(id), netns)
  if err != nil {
    log.Fatalf("failed to setup network for namespace: %v", err)
  }

  for key, iff := range result.Interfaces {
    if len(iff.IPConfigs) > 0 {
      IP := iff.IPConfigs[0].IP.String()
      fmt.Printf("IP of the interface %s:%s\n", key, IP)
    }
  }

  ch := make(chan os.Signal, 1)
  signal.Notify(ch, os.Interrupt)
  <-ch
}

flannel-vxlan

flannel 网络插件分为两个部分,第一部分为 https://github.com/containernetworking/plugins 自带的 flannel ,用于完成工作一,通过调用 bridge 插件完成对容器命名空间网络的配置,而 https://github.com/flannel-io/flannel 用于完成工作二,使用 vxlan 实现容器跨节点通信。

手动部署的官网文件见 https://github.com/flannel-io/flannel/blob/master/Documentation/running.md

首先,利用 etcdctl 向 etcd 中添加相关的网络配置,注意这里使用的 etcd api 版本为 v2。

etcdctl --endpoints=http://10.211.55.2:2379 set /coreos.com/network/config '{ "Network": "10.5.0.0/16", "Backend": {"Type": "vxlan"}}'

在节点1和节点2上下载 https://github.com/flannel-io/flannel/releases 二进制程序并启动。

./flanneld-amd64 -etcd-endpoints http://10.211.55.2:2379

在节点1和节点2的 /etc/cni/net.d/ 下编写 flannel 配置文件 11-flannel.conf。此处的配置信息参考 https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml 中 ConfigMap 的 cni-conf.json 部分。

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

在 节点1 和 节点2 上分别创建网络命名空间 ns-2,ns-3。

ip netns add ns-x

使用自己编写的 cnidemo 调用 flannel 插件来配置 ns-2,ns-3。

# 节点1
./cnidemo -id 2 -conf /etc/cni/net.d/11-flannel.conf

# 节点2
./cnidemo -id 3 -conf /etc/cni/net.d/11-flannel.conf

程序会输出容器网络命名空间的 ip ,我这里是 10.5.67.4 和 10.5.7.2。可以在 ns-2 中启动一个 http server,在 ns-3 中测试是否可以访问。如果可以成功访问,则表示 flannel 网络插件正常运行了。

# 节点1
ip netns exec ns-2 python3 -m http.server 8080

# 节点2
ip netns exec ns-3 curl http://10.5.67.4:8080

分析

flannel 利用 etcd 来对数据进行存取,利用 etcdctl 插件它在 etcd 中存储的数据。

etcdctl --endpoints=http://10.211.55.2:2379 ls /coreos.com/network

输出如下:

/coreos.com/network/config
/coreos.com/network/subnets

第一个就是之前配置的内容,这里查看第二个 key 的数据:

etcdctl --endpoints=http://10.211.55.2:2379 ls /coreos.com/network/subnets

输出如下:

/coreos.com/network/subnets/10.5.67.0-24
/coreos.com/network/subnets/10.5.7.0-24

可以看出,这是当前两个节点在容器网络中的子网信息,挑选第一个进行查看:

etcdctl --endpoints=http://10.211.55.2:2379 get /coreos.com/network/subnets/10.5.67.0-24

输出如下:

{"PublicIP":"10.211.55.32","BackendType":"vxlan","BackendData":{"VtepMAC":"92:3a:42:4a:9a:a9"}}

由于 vxlan 构建的是一个二层 overlay 网络,所以这里 BackendData 数据记录的是 flannel 守护进程创建的网卡 flannel.1 的物理 MAC 地址。这个 flannel.1 是 VTEP(VXLAN Tunnel Endpoints),输入命令查看其相关信息:

ip -d link show flannel.1

输出如下:

flannel.1:  mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
   link/ether 92:3a:42:4a:9a:a9 brd ff:ff:ff:ff:ff:ff promiscuity 0
   vxlan id 1 local 10.211.55.32 dev enp0s5 srcport 0 0 dstport 8472 nolearning ageing 300 udpcsum addrgenmode none

在另一个节点节点2上查看转发表:

bridge fdb show dev flannel.1

输出如下:

92:3a:42:4a:9a:a9 dst 10.211.55.32 self permanent

原文链接:https://blog.schwarzeni.com/2021/05/02/CNI-%E6%8F%92%E4%BB%B6-flannel-vxlan-%E4%BD%BF%E7%94%A8%E5%AE%9E%E6%93%8D/

浏览 49
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报