当前位置: 首页 > 工具软件 > cni > 使用案例 >

关于kubernetes的CNI插件说明

刘棋
2023-12-01
https://github.com/containernetworking/cni/blob/spec-v0.4.0/SPEC.md
https://kubernetes.io/zh/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/

# CNI官方文档: https://www.cni.dev/docs/spec/
# CNI插件遵守容器网络API接口(Container Network Interface,CNI)规范,设计上偏重互操作性
# CNI是由CNCF定义的通用标准API,是容器平台 docker、kubernetes、mesos 均采用的容器网络解决方案 ...
# CNI插件是一系列实现了CNI API接口的网络插件 ...
# CNI插件负责将网络接口插入容器的网络名称空间(如veth对的一端)并在宿主机进行任何必要的更改(如将该veth的另一端连到bridge)
# 并且通常还会通过调用IPAM类型的CNI插件在该容器内将IP分配给接口并设置与IP地址管理部分一致的路由 ...
# CNI是容器管理组件与各种网络插件之间的桥梁,Kubelet 通过这种标准接口的方式来调用各种不同的网络插件以实现对POD的网络配置 ...
# 其设计思想是在启动infra容器后由 kubelet 读取CNI配置并调用相应CNI插件,为容器的 Network Namespace 配置符合预期的网络栈
# 通过给 Kubelet 传递 --network-plugin=cni 选项可以选择CNI插件
# CNI插件支持两个命令: add 与 del (配置网络、解除网络) 
# Kubernetes 目前遵循CNI的 v0.4.0 规范

# 集群中POD内的容器的网络是属于该POD的Pause容器的,容器的网络创建流程如下
#   1. kubelet 创建 Pause 容器生成 network namespace
#   2. kubelet 调用 CNI driver
#   3. CNI driver 根据配置调用具体的CNI插件
#   4. CNI插件为 Pause 容器配置网络 ...
#   5. POD内的其他的容器Join到 Pause 容器的网络

# -------------------------------------------------------- kubelet Args ...

# CNI插件以二进制可执行文件的形式被 kubelet 调用
kubelet --network-plugin=cni --cni-conf-dir /etc/cni/net.d --cni-bin-dir /opt/cni/bin
# --network-plugin  要为 kubelet/Pod 生命周期中的各种事件调用的网络插件的名称
# --cni-bin-dir     由Kubelet探测此路径下具体的CNI插件进行后续的传参调用,用于实现配置POD网络 ...
# --cni-conf-dir    由Kubelet读取这里的CNI配置进行POD的网络设置,配置信息中引用的任何CNI插件都位于 --cni-bin-dir 中
#                   若该路径内有多个CNI配置文件,则使用按文件名的典顺序排列后的第一个文件作为配置文件
#                   CNI配置文件以Json形式定义,不同版本的CNI、不同的CNI插件有着不同的配置结构 ...
#                   配置文件内可有多个CNI插件的配置,当这些CNI插件的配置以数组形式记录时 kubelet 会对所有的插件按序链式调用 ...
#                   并且当所有组件均调用成功才视为网络配置完成,过程中若出现 error 则立即进行 del 的回滚操作来保证原子性
#                   目前流行的CNI插件: flannel、cannel、calico、weave、Macvlan、Contiv、Terway
# 
# 注:
# 名为 flannel 的CNI插件是开源网络方案 flannel 的调用器
# 这是 flannel 网络方案为适配CNI架构的产物,为便于区分通常将CNI插件中的 flannel 称为 flanenl CNI

# -------------------------------------------------------- Example
#
#                                         flanneld (本地Node的POD-CIDR等网络信息)
#  Apiserver <-> etcd                                  \ 
#       ↓                                               \ 
#  kubelet(读取/etc/cni/net.d/xxx.conf) -> 传入ENV参数&执行CNI插件(flannel) -> POD(设置 Network-NameSpace) -> 

# 1.通过Apiserver将POD信息写入etcd,管控组件如Scheduler将其调度到某个具体的Node上
# 2.Kubelet在Watch到该POD的创建时在本地执行若干创建操作,执行到关于POD网络的配置时先读取 --cni-conf-dir 中CNI的Json配置信息
# 3.CNI配置文件内声明了使用的CNI插件及其相关参数,此时 kubelet 按该声明去 --cni-bin-dir 调用这个具体的CNI插件 ...
# 4.kubelet 在调用CNI插件时会通过标准输入以环境变量的形式传递容器运行时等信息 ...
# 5.主要传递的容器运行时参数为:
#   (1) Network Namespace 的路径
#   (2) Network interface Name
#   (3) 容器ID
# 6.此时CNI插件进入POD的 Network Namespace 进行具体的网络配置工作
# 7.同时会将配置结果(以Json格式输出,描述结果和状态)返回给 Kubelet
# 7.配置完成后 Kubelet 也就完成了整个POD的创建过程 ...

# -------------------------------------------------------- CNI插件的类型

# CNI插件按功能可分为三种类型: main、ipam、meta

main
# 用来创建具体的网络设备,如 bridge(桥设备)、ipvlan、loopback(lo设备)、macvlan、vlan、ptp(Veth Pair)、vlan、host-device
# 如 Flannel、Weave 等项目都属于 "网桥" 类型的CNI插件,所以在具体的实现中它们往往会调用 bridge 这个二进制文件

ipam (IP Address Management)
# 负责分配IP地址,是对所有CNI插件共有的IP管理部分的抽象,官方提供了 dhcp、host-local 两种类型
# 比如 dhcp 这个文件会向DHCP服务器发起请求、host-local 文件则会使用预先配置的IP地址段进行分配 ...
# 这种类型的插件在执行 add 命令时会分配一个IP给调用者,执行del命令时会将调用者指定的IP回收到IP池
# host-local 插件通过在配置文件中指定的 subnet 进行网络划分
# host-local 插件在本地通过指定目录( 默认为 /var/lib/cni/networks )记录当前的 IP Pool 数据
# host-local 插件将IP分配并告知调用者时还能告知DNS、路由等配置信息,这些信息通过配置文件和对应的 resolv 文件记录
# host-local 的应用范围较广,kubenet、bridge、ptp、ipvlan 等CNI插件都被用来和 host-local 配合进行IP管理

meta
# 由CNI社区维护的内置CNI插件,如 flannel 就是专门为 Flannel 项目提供的CNI插件
# 该类型不能作为独立的插件使用,需调用其他插件如 flannel,或配合其他main类型插件使用,常见的有: bandwidth、portmap ...
# tuning 是通过 sysctl 调整网络设备参数的二进制文件,portmap 是通过 iptables 配置端口映射的二进制文件
# bandwidth 是使用 Token Bucket Filter (TBF) 来进行限流的二进制文件 ...

# 注:
# kubernetes通过CNI维护一个网桥来代替 docker0,这个CNI网桥默认名为 "cni0"
# 需注意CNI网桥只接管所有CNI插件负责的(既由kubernetes创建的容器),而docker的 docker0 桥与其无关 ...
# kubernetes之所以要设置这个与 "docker0" 网桥功能相同的 "cni0" 网桥,主要原因有两点:
#   1.K8S项目并未使用Docker的网络模型,所以它不希望也不具备配置 docker0 的能力
#   2.这还与K8S如何配置POD、也就是infra容器(Pause)Network Namespace 相关 ...

# -------------------------------------------------------- CNI插件 ...

Download CNI ...
# 下载CNI插件: https://github.com/containernetworking/plugins/releases
# 解压后放在各节点 /opt/cni/bin 路径下

# ls -l /opt/cni/bin/           # 查看自带的CNI插件 ( 配置文件中所对应的二进制CNI插件存放的路径 )
# 总用量 44828
# -rwxr-xr-x 1 root root 3890407 6月  6 22:06 bridge        # 创建网桥,并添加主机和容器到该网桥
# -rwxr-xr-x 1 root root 9921982 6月  6 22:06 dhcp          # 在主机上运行守护程序,代表容器发出DHCP请求
# -rwxr-xr-x 1 root root 2814104 6月  6 22:06 flannel       # 用于对开源网络方案 "flannel" 进行调用 (该CNI插件已经被内置)
# -rwxr-xr-x 1 root root 2991965 6月  6 22:06 host-local    # 
# -rwxr-xr-x 1 root root 3475802 6月  6 22:06 ipvlan        # 与macvlan类似,但对内核要求更高,它们的MAC地址相同但IP不同
# -rwxr-xr-x 1 root root 3026388 6月  6 22:06 loopback      #
# -rwxr-xr-x 1 root root 3520724 6月  6 22:06 macvlan       # macvlan是Linux内核特性,用于给一个物理网络接口 "parent" 配置虚拟化接口
# -rwxr-xr-x 1 root root 3470464 6月  6 22:06 portmap       # 基于iptables的portmapping插件,将端口从主机的地址空间映射到容器
# -rwxr-xr-x 1 root root 3877986 6月  6 22:06 ptp           # 
# -rwxr-xr-x 1 root root 2605279 6月  6 22:06 sample        # 
# -rwxr-xr-x 1 root root 2808402 6月  6 22:06 tuning        # 调整现有接口的 sysctl 参数

CNI 与 NetworkPolicy

# POD默认是 "Accept All" 状态,即接收来自任何发送方请求或向任何接收方发送请求
# POD被 NetworkPolicy 关联后则会进入 "Deny All" 状态,既不允许被外界访问、也不允许对外界发起访问
# NetworkPolicy 定义的规则其实是白名单,凡是支持 NetworkPolicy 的CNI插件都维护着一个 NetworkPolicy Controller
# 通过控制循环的方式对 NetworkPolicy 对象的CRUD进行响应,然后由这个CNI插件在宿主机生成 iptables 规则 ...

CNI文档 https://www.cni.dev/docs/spec/

// https://github.com/containernetworking/cni/blob/spec-v0.4.0/SPEC.md

// -------------------------------------------------------- /etc/cni/net.d/01-example.conf
{
  "name": "k8s-pod-network",    
  // 即 Network Name,这在整个管理域中是唯一的,表想要创建的容器网络
  // 此处即 NetworkList 中仅仅只有 k8s-pod-network 这一个 Network
  "cniVersion": "0.3.0",
  // 指定插件使用的CNI语义版本
  "plugins": [
  // 标准CNI网络配置词典的列表
    {
      "type": "calico",
      // 插件类型,也代表CNI插件的名称
      "log_level": "info",
      "datastore_type": "kubernetes",
      "nodename": "127.0.0.1",
      "ipam": {
      // 是IPAM类型的CNI插件的 dictionary 配置值 ( Dictionary with IPAM specific values )
        "type": "host-local",
        // 在ipam配置段下的type属性特指IPAM类型的CNI插件的名字 ...
        "subnet": "usePodCidr"
        // 每个CNI插件都有自己的IP管理方法(简称IPAM),最简单的(内置在Kubernetes中的方法)假定将固定地址集静态分配给每个节点
        // 诸如 Calico 之类的更高级的解决方案为用户提供了更多控制权,并允许使用更细粒度的动态IPAM ...
      },
      "policy": {
        "type": "k8s"
      },
      "kubernetes": {
        "kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
      }
    },
    {
      "type": "portmap",        
      "capabilities": {
        "portMappings": true
      }    
      // CNI网络插件支持 hostPort。可使用官方 portmap 插件(由CNI插件团队提供)或使用自己的带有 portMapping 功能的插件
      // portmap 用于在宿主机配置iptables规则,进行 SNAT、DNAT 和端口转发 ...
    },
    {
      "type": "bandwidth",
      "capabilities": {
        "bandwidth": true
      }
      // CNI网络插件还支持POD入口和出口流量的整形,可使用CNI插件团队提供的 bandwidth 插件
      // 若要启用流量整形,必须将 bandwidth 插件添加到CNI的这个Json配置中,并在资源声明的注解中进行配置使其生效
    }
  ]
}

// -------------------------------------------------------- /etc/cni/net.d/02-example.conf

{
  "cniVersion": "0.3.1",
  "name": "mynet",
  "type": "ipvlan",
  "master": "foo0",
  "ipam": {
    "type": "host-local",
    "resolvConf": "/home/here.resolv", 
    // 交付的IP对应的dns (将IP分配并告知调用者时还可告知DNS、路由等信息,通过配置文件和对应的resolv文件记录)
    "dataDir": "/home/cni/network",
    // 本地IP池的数据库目录 (通过此路径记录当前的 IP Pool 数据)
    "ranges": [
    // 交付的IP所属的网段、网关信息
      [
        {
          "subnet": "10.1.2.0/24",
          "rangeStart": "10.1.2.9",
          "rangeEnd": "10.1.2.20",
          "gateway": "10.1.2.30"
        },
        {
          "subnet": "10.1.4.0/24"
        }
      ],
      [
        {
          "subnet": "11.1.2.0/24",
          "rangeStart": "11.1.2.9",
          "rangeEnd": "11.1.2.20",
          "gateway": "11.1.2.30"
        }
      ]
    ]
  }
}

// -------------------------------------------------------- /etc/cni/net.d/03-example.conf

{
  "cniVersion": "0.3.0",
  "name": "mynet",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "cni0",
      "isGateway": true,  
      "ipMasq": true,
      // 可选(若插件支持),为 Network 在宿主机创建 IP Masquerade,若需将宿主作为网关,为了能路由到POD时此字段是必须
      "ipam": {                 
        "type": "host-local",
        "subnet": "10.22.0.0/16",
        "routes": [
          { 
            "dst": "0.0.0.0/0" 
          }
        ]
      }
    }
  ]
}

// -------------------------------------------------------- /etc/cni/net.d/04-example.conf

{
  "cniVersion": "0.4.0",
  "name": "dbnet",
  "type": "bridge",
  "bridge": "cni0",
  "ipam": {
    "type": "host-local",
    "subnet": "10.1.0.0/16",
    "gateway": "10.1.0.1"
  },
  "dns": {
  // 具有DNS特定值的字典
    "nameservers": [ "10.1.0.1" ]
    // nameservers (字符串列表,可选): 此网络知道的DNS名称服务器的优先顺序列表
    // domain(字符串,可选): 用于短主机名查找的本地域
    // search(字符串列表,可选): 用于短主机名查找的优先顺序搜索域列表。domain大多数解析器将优先选择该方法
    // options (字符串列表,可选): 可以传递给解析器的选项列表
  }
}

// -------------------------------------------------------- /etc/cni/net.d/05-example.conf


{
  "cniVersion": "0.4.0",
  "name": "pci",
  "type": "ovs",
  "bridge": "ovs0",
  "vxlanID": 42,
  "ipam": {
    "type": "dhcp",
    "routes": [
      { "dst": "10.3.0.0/16" }, 
      { "dst": "10.4.0.0/16" } 
    ]
  },
  // args may be ignored by plugins,为容器运行时提供的其他参数
  // 例如可通过将标签添加到下方的标签字段中,将其传递给CNI插件 ...
  "args": {
    "labels" : {
        "appVersion" : "1.0"
    }
  }
}

// -------------------------------------------------------- /etc/cni/net.d/06-example.conf

{
  "cniVersion": "0.4.0",
  "name": "wan",
  "type": "macvlan",
  "ipam": {
    "type": "dhcp",
    "routes": [
      { 
        "dst": "10.0.0.0/8",
        "gw": "10.0.0.1" 
      } 
    ]
  },
  "dns": {
    "nameservers": [ "10.0.0.1" ]
  }
}

// -------------------------------------------------------- /etc/cni/net.d/07-example.conf

{
  "cniVersion": "0.4.0",
  "name": "dbnet",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "cni0",
      "args": {
        "labels" : {
            "appVersion" : "1.0"
        }
      },
      "ipam": {
        "type": "host-local",
        "subnet": "10.1.0.0/16",
        "gateway": "10.1.0.1"
      },
      "dns": {
        "nameservers": [ "10.1.0.1" ]
      }
    },
    {
      "type": "tuning",
      "sysctl": {
        "net.core.somaxconn": "500"
      }
    }
  ]
}


# 第三方CNI插件:
# https://github.com/containernetworking/cni/tree/spec-v0.4.0#3rd-party-plugins

# 若仅作为用户去使用CNI插件的话则比较简单,因为很多CNI插件都提供了一键部署的能力
# 以 Flannel 为例,只需使用 Daemonset 资源声明的方式 apply 相关资源清单即能自动将配置、二进制文件部署到每个Node

# -------------------------------------------------------- flannel

# 首先明确 /opt/cni/bin/flannel 是二进制的CNI插件,类似的还有 calico,weave 等 
# 由于 Flannel 项目对应的CNI插件已经默认被内置了,因此无需再单独安装 (其他项目需看情况进行部署)
# 名为 flannel 的CNI插件负责配置Infra容器 (Pause) 的网络栈并将POD接入到宿主机的 cni0 网桥
# 该方案本身还有个名为 flanneld 的守护进程,它会根据配置的不同 backend 来进行特定操作,如创建VETP设备等 ...

# flannel在对kubernetes进行支持时其启动参数中会增加 --kube-subnet-mgr 参数
# flanneld守护进程会从Apiservice或etcd集群获取分配给其所在Node的 Pod-cidr 范围 
# 这个 Pod-cidr 信息将作为flannel为Node本地容器规划的IP地址段记录到 /run/flannel/subnet.env 中 
# 同时 flannel_cni 组件会读取 /run/flannel/subnet.env 并写入到 net-conf.json 中供flanneld使用 (以configmap的形式) 
# 如果说flanneld为POD铺设了跨Node的大网,那么CNI插件就是将各终端的POD挂载到这张大网上的安装工人 ...

# 现在能将整个流程连起来了:
# 名为 flannel 的CNI插件首先读取netconf配置和subnet.env信息生成适用于 bridge CNI 插件的 netconf 文件和 ipam (host-local) 配置
# 并设置其 delegate 为 bridge CNI插件,然后调用 bridge CNI插件实现挂载容器到 bridge 的流程
# 因为各POD的IP分配是基于CNI插件中的Ipam类型的名为 host-local 的插件,所以整个流程是分布式的,不会对APIServer造成负担

# 通常使用 flannel 时宿主机会运行名为 "flanneld" 的守护进程,此进程会返回该Node的flannel网络、subnet、MTU等信息并写入本地文件
# flannel 网络下的bridge名为 flannel0,而这个 flannel0 网卡上的数据会被封包 (udp、vxlan) 或直接转发 (host-gw)

# -------------------------------------------------------- CNI插件的三种实现模式

# 网络插件分类:
# http://5b0988e595225.cdn.sohucs.com/images/20200317/309edfb8cca14acca4092c03c1e4c83c.png

# 通常来说CNI插件按其实现方式可分为三种: Overlay、路由、Underlay

Overlay
#   该模式的典型特征是POD独立于宿主机的IP段,这个IP段进行跨Node通信时是通过在Node之间创建隧道的方式实现
#   将整个容器网段的包全都封装成底层的物理网络中主机之间的包,优势在于对底层的宿主网络没有任何要求 ...
#   相关的CNI插件: flannel-vxlan、calico-ipip、weave、...

路由
#   该模式中Node和POD也分属不同网段,与 Overlay 的主要区别在于其跨Node通信的能力是通过路由实现的
#   因此无需在不同Node间做隧道封包,但路由打通就需要部分依赖于底层网络,比如说要求底层网络有二层可达的能力
#   相关的CNI插件: ...

Underlay
#   Node和POD属于同一网络,因此容器之间网络的打通主要依靠于底层网络,因此性能最好
#   所以该模式强依赖于底层能力 (该模式下很多插件不支持kubernetes的service服务发现)
#   相关的CNI插件: calico-bgp、flannel-hostgw、sriov、...

# 注:
# 若使用阿里的公有云,可使用其提供的高性能 Terway 插件。使用 calico-bgp 方案时,若集群节点处于同一网段则对底层几乎没有要求

# ---------------------------------------------------- docker0 与 cni0

# 在Docker的网络模型中,是基于虚拟网桥设备 docker0 实现宿主机内所有容器网络的互通能力的 
# 这个 docker0 设备既充当网桥,同时又是一个具有IP的网关设备,因而它的IP也是容器的网关 ...
# 通过 route -n 命令能看到原生的 docker0 会有一条默认路由,从而打通容器和宿主机之外的网络 ...
# 而在 kubernetes 中的CNI插件要实现的目标也是通过某种方式将容器借助类似的设备实现互通
# (可以是网桥,也可以是路由规则等等,依不同CNI插件的实现而异)其目标是实现容器跨 Node 通信 ...
# 需注意在使用 flannel 之后一旦通过 kubernetes 创建POD就会产生名为 cni0 的网桥来接管所有CNI插件负责的POD
# 而单纯的使用 docker run 创建的容器还是由 docker0 这个桥接管的
# kubernetes之所以不直接使用docker0是因为其官方认为Docker网络模型还不够优秀

# ---------------------------------------------------- Infra容器 (Pause)

# 每个POD中都有个特殊的容器且永远是POD中创建的第一个容器,只是用户差看不到,因为其完成使命就暂停了
# 该容器就是Infra容器 (使用汇编实现) 当创建POD时kubernetes先创建名称空间,然后把其中的网络名称空间与这个Infra容器关联
# 后续处于此POD中的容器均通过 Join 的方式与这个容器关联在一起,此后这些容器和Infra容器都属于相同的网络名称空间
# 这就是为啥POD内的多个容器能使用 localhost 进行通信的原因,因此严格意义来说网络名称空间是属于Infra的 ...

# kubelet 通过CRI接口创建POD时首先会创建Infra容器,此过程是调用Dokcer对CRI的实现 (dockershim)
# dockershim 通过调用 docker API 来完成,然后再设置网络,其首先准备好CNI插件参数,再调用并传递给CNI插件去设置Infra网络

# ---------------------------------------------------- 10-flannel.conflist 

# 当安装 flanneld daemon 并启动后会在每个宿主机中生成对应的Json格式的CNI配置文件
# 同时它也会以 ConfigMap 形式存入 etcd 从而让 kubernetes 可以进行读取 ...
$ cat /etc/cni/net.d/10-flannel.conflist 
{
  "name": "cbr0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
      # Delegate的意思是这个CNI插件并不会自己做事儿,而是会调用 Delegate 指定的某种CNI内置的插件来完成
        "hairpinMode": true,
        # 默认情况下网桥设备不允许一个数据包从一个端口进来,再从一个端口出去
        # 开启该模式则取消这个限制,因为我们要允许在NAT模式下容器自己访问自己
        # 比如将宿主机8080映射到容器80,完全可能在容器内通过宿主的8080来访问自己,这会造成成报文从容器出去又原路返回,所以要开启该限制
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}

# ----------------------------------------------------

# CNI插件的实现通常需要两个部分:
# 1. 一个二进制CNI插件去配置Pod网卡和IP等,相当于给POD插上网线
# 2. 一个守护进程去实现Pod之间的网络打通,相当于给POD接入网络
# 
# 说明:
# 到这里能总结出要实现给 Kubernetes 用的容器网络方案,需要做两部分的工作,以flannel项目为例:
# 首先,实现该网络方案本身,这部分是flanneld进程的主要逻辑,如创建和配置 flannel.1 设备、配置宿主机路由、ARP和FDB表信息等 ...
# 然后,实现该网络方案对应的CNI插件,插件主要要做的就是设置 Infra 容器里的网络栈,并将其veth的一端连接到 cni0 桥中
# 实际上对于 Weave、Calico 这样的网络方案来说,它们的 DaemonSet 只需挂载宿主机的 /opt/cni/bin/ 即可实现CNI插件的安装

# kubelet调用CNI插件时传递的参数分为两部分:
# 一部分是一组CNI环境变量用于定义当前操作,即ADD或DEL (添加或拆除 veth pair)
# 一部分是 kubelet 从CNI配置文件中获取的一些配置信息 (被flannel从configMap挂载到宿主机的 /etc/cni/net.d/10-flannel.conflist)
# 它们被组装成Json格式的 Network COnfiguration 通过 stdin 传递给了 flannel 插件
# 当有了这两部分的参数之后flannel插件就可以实现具体的网络栈配置了 ...

# -------------------------------- ConfigMap - flannel

kind: ConfigMap
apiVersion: v1
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
  labels:
    tier: node
    app: flannel
data:
  cni-conf.json: |
    {
      "name": "cbr0",
      "ipMasq": false,
      "plugins": [
        {
          "type": "flannel",
          "ipMasq": false,
          "delegate": {
            "hairpinMode": true,
            "isDefaultGateway": true
          }
        },
        {
          "type": "portmap",
          "capabilities": {
            "portMappings": true
          }
        }
      ]
    }
  # flannel_cni 组件读取 /run/flannel/subnet.env 并写入到 net-conf.json 中供flanneld使用 (以configmap的形式) 
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "host-gw"
      }
    }

---

apiVersion: extensions/v1beta1
kind: DaemonSet
spec:
    spec:
      # 从 configmap 中拷贝到Pod内部
      # 该 configmap 会被flannel的init-container挂载,挂载完毕后会执行cp命令到 /etc/cni/net 下面
      initContainers:
      - name: install-cni
        image: quay.io/coreos/flannel:v0.10.0-amd64
        command:
        - cp
        args:
        - -f
        - /etc/kube-flannel/cni-conf.json
        - /etc/cni/net.d/10-flannel.conflist
        volumeMounts:
        - name: cni
          mountPath: /etc/cni/net.d
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      containers:
      - name: kube-flannel
        image: quay.io/coreos/flannel:v0.10.0-amd64
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq=false
        - --kube-subnet-mgr
        - --iface=ens192
        volumeMounts:
        - mountPath: /etc/localtime
          name: flannel-server-time
        - name: run
          mountPath: /run
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
        - name: flannel-server-time
          hostPath:
            path: /etc/localtime
        - name: run
          hostPath:
            path: /run
        - name: cni
          hostPath:
            path: /etc/cni/net.d
        - name: flannel-cfg
          configMap:
            name: kube-flannel-cfg

 类似资料: