container networking interface

作者: 李佶澳   转载请保留:原文地址   发布时间:2017/05/03 13:30:32

参数标准

CNI定义了一个网络插件的实现标准,网络插件需要是一个可执行程序,它运行时读取环境变量:

CNI_COMMAND        : 操作ADD/DEL/VERSION
CNI_CONTAINERID    : 容器的ID
CNI_NETNS          : 目标net namespace,将容器加入这个ns,或者从这个ns删除
CNI_ARGS           : 额外传递的参数
CNI_IFNAME         : 设置的容器网卡名称,如eth0

例如:

CNI_COMMAND=ADD CNI_CONTAINERID=bcc8ad23b46b CNI_IFNAME=eth1 CNI_NETNS=

目标网络的配置文件则是从stdin中读取。

插件的实现者只需要调用cniskel.PluginMain,加载实现的ADD和DEL函数。

package main

import (
	"github.com/containernetworking/cni/pkg/skel"
	...
)
...
	skel.PluginMain(cmdAdd, cmdDel, cniSpecVersion.All)

在PluginMain在gthub.com/containernetworking/cni/pkg/skel/skel.go中实现:

func PluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) {
	if e := PluginMainWithError(cmdAdd, cmdDel, versionInfo); e != nil {
	...
}

PluginMainWithError的实现:

func PluginMainWithError(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) *types.Error {
	return (&dispatcher{
		Getenv: os.Getenv,
		Stdin:  os.Stdin,
		Stdout: os.Stdout,
		Stderr: os.Stderr,
	}).pluginMain(cmdAdd, cmdDel, versionInfo)
}

dispatcher的pluginMain函数中:

func (t *dispatcher) pluginMain(cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo) *types.Error {
	...
	cmd, cmdArgs, err := t.getCmdArgsFromEnv()
	...
	switch cmd {
	case "ADD":
		err = t.checkVersionAndCall(cmdArgs, versionInfo, cmdAdd)
	case "DEL":
		err = t.checkVersionAndCall(cmdArgs, versionInfo, cmdDel)
	case "VERSION":
		err = versionInfo.Encode(t.Stdout)

t.getCmdArgsFromEnv()中读取环境变量:

	{
		"CNI_COMMAND",
		&cmd,
		reqForCmdEntry{
			"ADD": true,
			"DEL": true,
		},
	},
	{
		"CNI_CONTAINERID",
		&contID,
		reqForCmdEntry{
			"ADD": false,
			"DEL": false,
		},
	},
	{
		"CNI_NETNS",
		&netns,
		reqForCmdEntry{
			"ADD": true,
			"DEL": false,
		},
	},
	{
		"CNI_IFNAME",
		&ifName,
		reqForCmdEntry{
			"ADD": true,
			"DEL": true,
		},
	},
	{
		"CNI_ARGS",
		&args,
		reqForCmdEntry{
			"ADD": false,
			"DEL": false,
		},
	},
	{
		"CNI_PATH",
		&path,
		reqForCmdEntry{
			"ADD": true,
			"DEL": true,
		},
	},

插件实现

cni-plugins中提供了几个cni的实现:

bridge
dhcp
flannel
host-local 
ipvlan
loopback
macvlan
portmap
ptp
sample
tuning
vlan

还有一些容器的网络项目自己实现了cni插件,例如cni中列出的:

Project Calico - a layer 3 virtual network
Weave - a multi-host Docker network
Contiv Networking - policy networking for various use cases
SR-IOV
Cilium - BPF & XDP for containers
Infoblox - enterprise IP address management for containers
Multus - a Multi plugin
Romana - Layer 3 CNI plugin supporting network policy for Kubernetes
CNI-Genie - generic CNI network plugin
Nuage CNI - Nuage Networks SDN plugin for network policy kubernetes support
Silk - a CNI plugin designed for Cloud Foundry
Linen - a CNI plugin designed for overlay networks with Open vSwitch and fit in SDN/OpenFlow network environment
Vhostuser - a Dataplane network plugin - Supports OVS-DPDK & VPP
Amazon ECS CNI Plugins - a collection of CNI Plugins to configure containers with Amazon EC2 elastic network interfaces (ENIs)

网络配置文件格式

cni约定了网络配置文件的格式:

// NetConf describes a network.
type NetConf struct {
	CNIVersion string `json:"cniVersion,omitempty"`
	
	Name         string          `json:"name,omitempty"`
	Type         string          `json:"type,omitempty"`
	Capabilities map[string]bool `json:"capabilities,omitempty"`
	IPAM         struct {
		Type string `json:"type,omitempty"`
	} `json:"ipam,omitempty"`
	DNS DNS `json:"dns"`
}

type DNS struct {
	Nameservers []string `json:"nameservers,omitempty"`
	Domain      string   `json:"domain,omitempty"`
	Search      []string `json:"search,omitempty"`
	Options     []string `json:"options,omitempty"`
}

golang api

规定了go的api接口:

-+CNIConfig : struct
   [fields]
   +Path : []string
   [methods]
   +AddNetwork(net *NetworkConfig, rt *RuntimeConf) : types.Result, error
   +AddNetworkList(list *NetworkConfigList, rt *RuntimeConf) : types.Result, error
   +DelNetwork(net *NetworkConfig, rt *RuntimeConf) : error
   +DelNetworkList(list *NetworkConfigList, rt *RuntimeConf) : error
   +GetVersionInfo(pluginType string) : version.PluginInfo, error
   -args(action string, rt *RuntimeConf) : *invoke.Args

例如调用AddNetwork()方法时,会运行参数net中的Network.Type对应的二进制程序,将rt中的容器添加到指定ns或者从ns中删除。

// AddNetwork executes the plugin with the ADD command
func (c *CNIConfig) AddNetwork(net *NetworkConfig, rt *RuntimeConf) (types.Result, error) {
	pluginPath, err := invoke.FindInPath(net.Network.Type, c.Path)   //注意Type就是插件对应的二进制程序名
	if err != nil {
		return nil, err
	}
	
	net, err = injectRuntimeConfig(net, rt)
	if err != nil {
		return nil, err
	}
	
	return invoke.ExecPluginWithResult(pluginPath, net.Bytes, c.args("ADD", rt))
}

参数rt中指定了ContainerID,netNS等:

type RuntimeConf struct {
	ContainerID string
	NetNS       string
	IfName      string
	Args        [][2]string
	// A dictionary of capability-specific data passed by the runtime
	// to plugins as top-level keys in the 'runtimeConfig' dictionary
	// of the plugin's stdin data.  libcni will ensure that only keys
	// in this map which match the capabilities of the plugin are passed
	// to the plugin
	CapabilityArgs map[string]interface{}
}

参考

  1. cni
  2. cni-plugins

欢迎加微信,最好备注姓名和方向

QQ交流群

区块链实践互助QQ群:576555864

Kubernetes实践互助QQ群:947371129

Prometheus实践互助QQ群:952461804

API网关Kong实践互助QQ群:952503851

Ansible实践互助QQ群:955105412

Copyright @2011-2018 All rights reserved. 转载请添加原文连接,合作请加微信lijiaocn或者发送邮件: lijiaocn@foxmail.com,备注网站合作 友情链接: lijiaocn github.com