kubernetes CRI剖析-k8s CRI剖析。kubernetes中有3个作用插口,分别是器皿网线端口CNI、器皿运作时插口CRI和器皿储存插口CSI。文中会对CNI是啥、CNI系统架构图做详细介绍,及其k8s对CNI开展有关实际操作来搭建和删掉pod网络开展剖析

关系blog:kubernetes/k8s CSI剖析-器皿储存接口分析
kubernetes/k8s CRI剖析-器皿运作时接口分析

简述

kubernetes的设计方案初心是适用可插下构架,进而有利于拓展kubernetes的作用。在这里构架观念下,kubernetes给予了3个特殊作用的插口,分别是器皿网线端口CNI、器皿运作时插口CRI和器皿储存插口CSI。kubernetes根据启用这好多个插口,来进行相对应的作用。

下边大家来对器皿运作时插口CNI来做一下详细介绍与剖析。

CNI是啥

CNI,全名是 Container Network Interface,即器皿网线端口。

CNI是K8s 中规范的启用互联网完成的插口。Kubelet 根据这一规范的插口来启用不一样的互联网软件以完成不一样的网络配置方法。

CNI互联网软件是一个可执行程序,是遵循器皿网线端口(CNI)标准的互联网软件。普遍的 CNI互联网软件包含 Calico、flannel、Terway、Weave Net等。

当kubelet挑选应用CNI种类的互联网软件时(根据kubelet运行主要参数特定),kubelet在建立pod、删掉pod的情况下,会启用CNI互联网软件来做pod的搭建互联网和消毁互联网等实际操作。

kubelet的互联网软件

kubelet的互联网软件有下列3种种类:
(1)CNI;
(2)kubenet;
(3)Noop,意味着不配备互联网软件。

这儿关键对kubelet中CNI有关的源代码开展剖析。

CNI构架

kubelet建立/删掉pod时,会启用CRI,随后CRI会启用CNI来开展pod网络的搭建/删掉。

kubelet搭建pod网络的大概全过程

(1)kubelet先根据CRI建立pause器皿(pod sandbox),转化成network namespace;
(2)kubelet依据运行参数配置启用实际的互联网软件如CNI互联网软件;
(3)互联网软件给pause器皿(pod sandbox)配备互联网;
(4)pod 中别的的器皿都和pause器皿(pod sandbox)分享网络。

kubelet中cni有关的源代码剖析

kubelet的cni源代码剖析包含以下几一部分:
(1)cni有关运行主要参数剖析;
(2)重要struct/interface剖析;
(3)cni复位剖析;
(4)cni搭建pod网络剖析;
(5)cni消毁pod网络剖析。

根据tag v1.17.4

https://GitHub.com/kubernetes/kubernetes/releases/tag/v1.17.4

1.kubelet部件cni有关运行主要参数剖析

kubelet部件cni有关运行主要参数有关编码以下:

// pkg/kubelet/config/flags.go
func (s *ContainerRuntimeOptions) AddFlags(fs *pflag.FlagSet) {
    ...
    // Network plugin settings for Docker.
	fs.StringVar(&s.NetworkPluginName, "network-plugin", s.NetworkPluginName, fmt.Sprintf("<Warning: Alpha feature> The name of the network plugin to be invoked for various events in kubelet/pod lifecycle. %s", dockerOnlyWarning))
	fs.StringVar(&s.CNIConfDir, "cni-conf-dir", s.CNIConfDir, fmt.Sprintf("<Warning: Alpha feature> The full path of the directory in which to search for CNI config files. %s", dockerOnlyWarning))
	fs.StringVar(&s.CNIBinDir, "cni-bin-dir", s.CNIBinDir, fmt.Sprintf("<Warning: Alpha feature> A comma-separated list of full paths of directories in which to search for CNI plugin binaries. %s", dockerOnlyWarning))
	fs.StringVar(&s.CNICacheDir, "cni-cache-dir", s.CNICacheDir, fmt.Sprintf("<Warning: Alpha feature> The full path of the directory in which CNI should store cache files. %s", dockerOnlyWarning))
	fs.Int32Var(&s.NetworkPluginMTU, "network-plugin-mtu", s.NetworkPluginMTU, fmt.Sprintf("<Warning: Alpha feature> The MTU to be passed to the network plugin, to override the default. Set to 0 to use the default 1460 MTU. %s", dockerOnlyWarning))
    ...
}

cni有关运行主要参数的初始值在NewContainerRuntimeOptions涵数中设定。

// cmd/kubelet/app/options/container_runtime.go
// NewContainerRuntimeOptions will create a new ContainerRuntimeOptions with
// default values.
func NewContainerRuntimeOptions() *config.ContainerRuntimeOptions {
	dockerEndpoint := ""
	if runtime.GOOS != "Windows" {
		dockerEndpoint = "unix:///var/run/docker.sock"
	}

	return &config.ContainerRuntimeOptions{
		ContainerRuntime:           kubetypes.DockerContainerRuntime,
		RedirectContainerStreaming: false,
		DockerEndpoint:             dockerEndpoint,
		DockershimRootDirectory:    "/var/lib/dockershim",
		PodSandboxImage:            defaultPodSandboxImage,
		ImagePullProgressDeadline:  metav1.Duration{Duration: 1 * time.Minute},
		ExperimentalDockershim:     false,

		//Alpha feature
		CNIBinDir:   "/opt/cni/bin",
		CNIConfDir:  "/etc/cni/net.d",
		CNICacheDir: "/var/lib/cni/cache",
	}
}

下边来简易剖析好多个较为关键的cni有关运行主要参数:
(1)--network-plugin:特定要应用的互联网软件种类,可选值cnikubenet"",默认设置 为空串,意味着Noop,即不配备互联网软件(不搭建pod网络)。这里配备数值cni时,即特定kubelet应用的互联网软件种类为cni

(2)--cni-conf-dir:CNI 环境变量所属途径。初始值:/etc/cni/net.d

(3)--cni-bin-dir:CNI 软件的可执行程序所属途径,kubelet 将在这里途径中搜索 CNI 软件的可执行程序来实行pod的互联网实际操作。初始值:/opt/cni/bin

2.重要struct/interface剖析

interface NetworkPlugin

先看来下重要的interface:NetworkPlugin

NetworkPlugin interface申明了kubelet互联网软件的一些操作步骤,不一样种类的互联网软件只必须完成这种方式就可以,在其中最重要的便是SetUpPodTearDownPod方式,功效分别是搭建pod网络与消毁pod网络,cniNetworkPlugin完成了该interface。

// pkg/kubelet/dockershim/network/plugins.go
// NetworkPlugin is an interface to network plugins for the kubelet
type NetworkPlugin interface {
	// Init initializes the plugin.  This will be called exactly once
	// before any other methods are called.
	Init(host Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error

	// Called on various events like:
	// NET_PLUGIN_EVENT_POD_CIDR_CHANGE
	Event(name string, details map[string]interface{})

	// Name returns the plugin's name. This will be used when searching
	// for a plugin by name, e.g.
	Name() string

	// Returns a set of NET_PLUGIN_CAPABILITY_*
	Capabilities() utilsets.Int

	// SetUpPod is the method called after the infra container of
	// the pod has been created but before the other containers of the
	// pod are launched.
	SetUpPod(namespace string, name string, podSandboxID kubecontainer.ContainerID, annotations, options map[string]string) error

	// TearDownPod is the method called before a pod's infra container will be deleted
	TearDownPod(namespace string, name string, podSandboxID kubecontainer.ContainerID) error

	// GetPodNetworkStatus is the method called to obtain the ipv4 or ipv6 addresses of the container
	GetPodNetworkStatus(namespace string, name string, podSandboxID kubecontainer.ContainerID) (*PodNetworkStatus, error)

	// Status returns error if the network plugin is in error state
	Status() error
}

struct cniNetworkPlugin

cniNetworkPlugin struct完成了NetworkPlugin interface,完成了SetUpPodTearDownPod等方式。

// pkg/kubelet/dockershim/network/cni/cni.go
type cniNetworkPlugin struct {
	network.NoopNetworkPlugin

	loNetwork *cniNetwork

	sync.RWMutex
	defaultNetwork *cniNetwork

	host        network.Host
	execer      utilexec.Interface
	nsenterPath string
	confDir     string
	binDirs     []string
	cacheDir    string
	podCidr     string
}

struct PluginManager

struct PluginManager中的plugin特性是interface NetworkPlugin种类,能够 传到实际的互联网软件完成,如cniNetworkPlugin struct

// pkg/kubelet/dockershim/network/plugins.go
// The PluginManager wraps a kubelet network plugin and provides synchronization
// for a given pod's network operations.  Each pod's setup/teardown/status operations
// are synchronized against each other, but network operations of other pods can
// proceed in parallel.
type PluginManager struct {
	// Network plugin being wrapped
	plugin NetworkPlugin

	// Pod list and lock
	podsLock sync.Mutex
	pods     map[string]*podLock
}

struct dockerService

struct dockerService实际上在CRI剖析的博闻一部分有做了深入分析,能够 去回望一下,下边再简易做一下详细介绍。

struct dockerService完成了CRI shim服务器端的器皿运作时插口及其器皿镜像系统插口,因此 其意味着了dockershim(kubelet内嵌的CRI shim)的服务器端。

struct dockerService中的network特性是struct PluginManager种类,在该建筑结构复位的时候会将实际的互联网软件建筑结构如struct cniNetworkPlugin储存进该特性。

建立pod、删掉pod的时候会依据dockerService建筑结构的network特性里边储存的实际的互联网软件建筑结构,去启用某一实际互联网软件(如cniNetworkPlugin)的SetUpPodTearDownPod方式来搭建pod的互联网、消毁pod的互联网。

// pkg/kubelet/dockershim/docker_service.go
type dockerService struct {
	client           libdocker.Interface
	os               kubecontainer.OSInterface
	podSandboxImage  string
	streamingRuntime *streamingRuntime
	streamingServer  streaming.Server

	network *network.PluginManager
	// Map of podSandboxID :: network-is-ready
	networkReady     map[string]bool
	networkReadyLock sync.Mutex

	containerManager cm.ContainerManager
	// cgroup driver used by Docker runtime.
	cgroupDriver      string
	checkpointManager checkpointmanager.CheckpointManager
	// caches the version of the runtime.
	// To be compatible with multiple docker versions, we need to perform
	// version checking for some operations. Use this cache to avoid querying
	// the docker daemon every time we need to do such checks.
	versionCache *cache.ObjectCache
	// startLocalStreamingServer indicates whether dockershim should start a
	// streaming server on localhost.
	startLocalStreamingServer bool

	// containerCleanupInfos maps container IDs to the `containerCleanupInfo` structs
	// needed to clean up after containers have been removed.
	// (see `applyPlatformSpecificDockerConfig` and `performPlatformSpecificContainerCleanup`
	// methods for more info).
	containerCleanupInfos map[string]*containerCleanupInfo
}

3.cni复位剖析

Kubelet 运行全过程中对于互联网关键做下列流程,分别是探头获得当今自然环境的互联网软件及其复位互联网软件(仅有当器皿运作时挑选为内嵌dockershim时,才会做CNI的复位实际操作,将CNI复位进行后交到dockershim应用)。

cni复位的启用链:
main (cmd/kubelet/kubelet.go)
-> NewKubeletCommand (cmd/kubelet/app/server.go)
-> Run (cmd/kubelet/app/server.go)
-> run (cmd/kubelet/app/server.go)
-> RunKubelet (cmd/kubelet/app/server.go)
-> CreateAndInitKubelet(cmd/kubelet/app/server.go)
-> kubelet.NewMainKubelet(pkg/kubelet/kubelet.go)
-> cni.ProbeNetworkPlugins & network.InitNetworkPlugin(pkg/kubelet/network/plugins.go)

启用链较长,这儿直接进入重要的涵数NewMainKubelet开展剖析。

NewMainKubelet

NewMainKubelet涵数中关键见到dockershim.NewDockerService启用。

// pkg/kubelet/kubelet.go
// NewMainKubelet instantiates a new Kubelet object along with all the required internal modules.
// No initialization of Kubelet and its modules should happen here.
func NewMainKubelet(kubeCfg *kubeletconfiginternal.KubeletConfiguration,...) {
    ...
    switch containerRuntime {
	case kubetypes.DockerContainerRuntime:
		// Create and start the CRI shim running as a grpc server.
		streamingConfig := getStreamingConfig(kubeCfg, kubeDeps, crOptions)
		ds, err := dockershim.NewDockerService(kubeDeps.DockerClientConfig, crOptions.PodSandboxImage, streamingConfig,
			&pluginSettings, runtimeCgroups, kubeCfg.CgroupDriver, crOptions.DockershimRootDirectory, !crOptions.RedirectContainerStreaming)
    ...
}

这儿对自变量containerRuntime值相当于docker时做剖析,即kubelet运行主要参数--container-runtime数值docker,这时候kubelet会应用内嵌的CRI shimdockershim做为器皿运作时,复位并运行dockershim

在其中,启用dockershim.NewDockerService的功效是:新创建并复位dockershim服务器端,包含复位docker client、复位cni网络配置等实际操作。

而在其中CNI一部分的关键逻辑性为:
(1)启用cni.ProbeNetworkPlugins:依据kubelet运行主要参数cni有关配备,获得cni环境变量、cni互联网软件可执行程序等信息内容,依据这种cni的有关信息来复位cniNetworkPlugin建筑结构并回到;
(2)启用network.InitNetworkPlugin:依据networkPluginName的值(相匹配kubelet运行主要参数--network-plugin),挑选相对应的互联网软件,启用其Init()方式,做互联网软件的复位实际操作(复位实际操作主要是起了一个goroutine,按时检测cni的环境变量及其可执行程序,让其能够 热更新);
(3)将上边流程中获得到的cniNetworkPlugin建筑结构,取值给dockerService structnetwork特性,待事后建立pod、删掉pod时能够 启用cniNetworkPluginSetUpPodTearDownPod方式来搭建pod的互联网、消毁pod的互联网。

kubelet对CNI的完成的关键编码:pkg/kubelet/network/cni/cni.go-SetUpPod/TearDownPod(搭建Pod网络和消毁Pod网络)

在其中涵数入参pluginSettings *NetworkPluginSettings的变量值,实际上是以kubelet运行参数配置而成,kubelet cni有关运行主要参数在前面早已干了剖析了,忘掉的能够 回过头来再看一下。

// pkg/kubelet/dockershim/docker_service.go
// NewDockerService creates a new `DockerService` struct.
// NOTE: Anything passed to DockerService should be eventually handled in another way when we switch to running the shim as a different process.
func NewDockerService(config *ClientConfig, podSandboxImage string, streamingConfig *streaming.Config, pluginSettings *NetworkPluginSettings,
	cgroupsName string, kubeCgroupDriver string, dockershimRootDir string, startLocalStreamingServer bool, noJsonLogPath string) (DockerService, error) {
    ...
    ds := &dockerService{
		client:          c,
		os:              kubecontainer.RealOS{},
		podSandboxImage: podSandboxImage,
		streamingRuntime: &streamingRuntime{
			client:      client,
			execHandler: &NativeExecHandler{},
		},
		containerManager:          cm.NewContainerManager(cgroupsName, client),
		checkpointManager:         checkpointManager,
		startLocalStreamingServer: startLocalStreamingServer,
		networkReady:              make(map[string]bool),
		containerCleanupInfos:     make(map[string]*containerCleanupInfo),
		noJsonLogPath:             noJsonLogPath,
	}
	...
    // dockershim currently only supports CNI plugins.
	pluginSettings.PluginBinDirs = cni.SplitDirs(pluginSettings.PluginBinDirString)
	// (1)依据kubelet运行主要参数cni有关配备,获得cni环境变量、cni互联网软件可执行程序等信息内容,依据这种cni的有关信息来复位```cniNetworkPlugin```建筑结构并回到
	cniPlugins := cni.ProbeNetworkPlugins(pluginSettings.PluginConfDir, pluginSettings.PluginCacheDir, pluginSettings.PluginBinDirs)
	cniPlugins = append(cniPlugins, kubenet.NewPlugin(pluginSettings.PluginBinDirs, pluginSettings.PluginCacheDir))
	netHost := &dockerNetworkHost{
		&namespaceGetter{ds},
		&portMappingGetter{ds},
	}
	// (2)依据networkPluginName的值(相匹配kubelet运行主要参数```--network-plugin```),挑选相对应的互联网软件,启用其```Init()```方式,做互联网软件的复位实际操作(复位实际操作主要是起了一个goroutine,按时检测cni的环境变量及其可执行程序,让其能够 热更新)
	plug, err := network.InitNetworkPlugin(cniPlugins, pluginSettings.PluginName, netHost, pluginSettings.HairpinMode, pluginSettings.NonMasqueradeCIDR, pluginSettings.MTU)
	if err != nil {
		return nil, fmt.Errorf("didn't find compatible CNI plugin with given settings % v: %v", pluginSettings, err)
	}
	// (3)将上边流程中获得到的```cniNetworkPlugin```建筑结构,取值给```dockerService struct```的```network```特性,待事后建立pod、删掉pod时能够 启用```cniNetworkPlugin```的```SetUpPod```、```TearDownPod```方式来搭建pod的互联网、消毁pod的互联网。	ds.network = network.NewPluginManager(plug)
	klog.Infof("Docker cri networking managed by %v", plug.Name())
    ...
}

先看来下pluginSettings长什么样,实际上是struct NetworkPluginSettings,包括了互联网软件名字、互联网软件可执行程序所属文件目录、互联网软件环境变量所属文件目录等特性,编码以下:

// pkg/kubelet/dockershim/docker_service.go
type NetworkPluginSettings struct {
	// HairpinMode is best described by comments surrounding the kubelet arg
	HairpinMode kubeletconfig.HairpinMode
	// NonMasqueradeCIDR is the range of ips which should *not* be included
	// in any MASQUERADE rules applied by the plugin
	NonMasqueradeCIDR string
	// PluginName is the name of the plugin, runtime shim probes for
	PluginName string
	// PluginBinDirString is a list of directiores delimited by commas, in
	// which the binaries for the plugin with PluginName may be found.
	PluginBinDirString string
	// PluginBinDirs is an array of directories in which the binaries for
	// the plugin with PluginName may be found. The admin is responsible for
	// provisioning these binaries before-hand.
	PluginBinDirs []string
	// PluginConfDir is the directory in which the admin places a CNI conf.
	// Depending on the plugin, this may be an optional field, eg: kubenet
	// generates its own plugin conf.
	PluginConfDir string
	// PluginCacheDir is the directory in which CNI should store cache files.
	PluginCacheDir string
	// MTU is the desired MTU for network devices created by the plugin.
	MTU int
}

3.1 cni.ProbeNetworkPlugins

cni.ProbeNetworkPlugins中关键功效为:依据kubelet运行主要参数cni有关配备,获得cni环境变量、cni互联网软件可执行程序等信息内容,依据这种cni的有关信息来复位cniNetworkPlugin建筑结构并回到。

在其中见到plugin.syncNetworkConfig()启用,关键功效是给cniNetworkPlugin建筑结构的defaultNetwork特性取值。

// pkg/kubelet/dockershim/network/cni/cni.go
// ProbeNetworkPlugins : get the network plugin based on cni conf file and bin file
func ProbeNetworkPlugins(confDir, cacheDir string, binDirs []string) []network.NetworkPlugin {
	old := binDirs
	binDirs = make([]string, 0, len(binDirs))
	for _, dir := range old {
		if dir != "" {
			binDirs = append(binDirs, dir)
		}
	}

	plugin := &cniNetworkPlugin{
		defaultNetwork: nil,
		loNetwork:      getLoNetwork(binDirs),
		execer:         utilexec.New(),
		confDir:        confDir,
		binDirs:        binDirs,
		cacheDir:       cacheDir,
	}

	// sync NetworkConfig in best effort during probing.
	plugin.syncNetworkConfig()
	return []network.NetworkPlugin{plugin}
}
plugin.syncNetworkConfig()

关键逻辑性:
(1)getDefaultCNINetwork():依据kubelet运行参数配置,去相匹配的cni conf文件夹名称下找寻cni环境变量,回到包括cni信息的cniNetwork建筑结构;
(2)plugin.setDefaultNetwork():依据上一步获得到的cniNetwork建筑结构,取值给cniNetworkPlugin建筑结构的defaultNetwork特性。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) syncNetworkConfig() {
	network, err := getDefaultCNINetwork(plugin.confDir, plugin.binDirs)
	if err != nil {
		klog.Warningf("Unable to update cni config: %s", err)
		return
	}
	plugin.setDefaultNetwork(network)
}
getDefaultCNINetwork()

关键逻辑性:
(1)在cni环境变量所属文件目录下,能够 鉴别3种cni环境变量,分别是.conf, .conflist, .json

(2)启用sort.Strings()将cni环境变量所属文件目录下的全部cni环境变量依照词典次序降序排列。

(3)只留第一个载入到的cni环境变量,随后立即return。因此 即使在cni配备文件名称下配备了好几个cni环境变量,也只能有在其中一个最后起效。

(4)启用cniConfig.ValidateNetworkList(),校检cni可执行程序文件目录下是不是存有相匹配的可执行程序。

// pkg/kubelet/dockershim/network/cni/cni.go
func getDefaultCNINetwork(confDir string, binDirs []string) (*cniNetwork, error) {
	files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"})
	switch {
	case err != nil:
		return nil, err
	case len(files) == 0:
		return nil, fmt.Errorf("no networks found in %s", confDir)
	}

	cniConfig := &libcni.CNIConfig{Path: binDirs}

	sort.Strings(files)
	for _, confFile := range files {
		var confList *libcni.NetworkConfigList
		if strings.HasSuffix(confFile, ".conflist") {
			confList, err = libcni.ConfListFromFile(confFile)
			if err != nil {
				klog.Warningf("Error loading CNI config list file %s: %v", confFile, err)
				continue
			}
		} else {
			conf, err := libcni.ConfFromFile(confFile)
			if err != nil {
				klog.Warningf("Error loading CNI config file %s: %v", confFile, err)
				continue
			}
			// Ensure the config has a "type" so we know what plugin to run.
			// Also catches the case where somebody put a conflist into a conf file.
			if conf.Network.Type == "" {
				klog.Warningf("Error loading CNI config file %s: no 'type'; perhaps this is a .conflist?", confFile)
				continue
			}

			confList, err = libcni.ConfListFromConf(conf)
			if err != nil {
				klog.Warningf("Error converting CNI config file %s to list: %v", confFile, err)
				continue
			}
		}
		if len(confList.Plugins) == 0 {
			klog.Warningf("CNI config list %s has no networks, skipping", string(confList.Bytes[:maxStringLengthInLog(len(confList.Bytes))]))
			continue
		}

		// Before using this CNI config, we have to validate it to make sure that
		// all plugins of this config exist on disk
		caps, err := cniConfig.ValidateNetworkList(context.TODO(), confList)
		if err != nil {
			klog.Warningf("Error validating CNI config list %s: %v", string(confList.Bytes[:maxStringLengthInLog(len(confList.Bytes))]), err)
			continue
		}

		klog.V(4).Infof("Using CNI configuration file %s", confFile)

		return &cniNetwork{
			name:          confList.Name,
			NetworkConfig: confList,
			CNIConfig:     cniConfig,
			Capabilities:  caps,
		}, nil
	}
	return nil, fmt.Errorf("no valid networks found in %s", confDir)
}
plugin.setDefaultNetwork

将上边获得到的cniNetwork结构体赋值给cniNetworkPlugin建筑结构的defaultNetwork特性。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) setDefaultNetwork(n *cniNetwork) {
	plugin.Lock()
	defer plugin.Unlock()
	plugin.defaultNetwork = n
}

3.2 network.InitNetworkPlugin

network.InitNetworkPlugin()关键功效:依据networkPluginName的值(相匹配kubelet运行主要参数--network-plugin),挑选相对应的互联网软件,启用其Init()方式,做互联网软件的复位实际操作。

// pkg/kubelet/dockershim/network/plugins.go
// InitNetworkPlugin inits the plugin that matches networkPluginName. Plugins must have unique names.
func InitNetworkPlugin(plugins []NetworkPlugin, networkPluginName string, host Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) (NetworkPlugin, error) {
	if networkPluginName == "" {
		// default to the no_op plugin
		plug := &NoopNetworkPlugin{}
		plug.Sysctl = utilsysctl.New()
		if err := plug.Init(host, hairpinMode, nonMasqueradeCIDR, mtu); err != nil {
			return nil, err
		}
		return plug, nil
	}

	pluginMap := map[string]NetworkPlugin{}

	allErrs := []error{}
	for _, plugin := range plugins {
		name := plugin.Name()
		if errs := validation.IsQualifiedName(name); len(errs) != 0 {
			allErrs = append(allErrs, fmt.Errorf("network plugin has invalid name: %q: %s", name, strings.Join(errs, ";")))
			continue
		}

		if _, found := pluginMap[name]; found {
			allErrs = append(allErrs, fmt.Errorf("network plugin %q was registered more than once", name))
			continue
		}
		pluginMap[name] = plugin
	}

	chosenPlugin := pluginMap[networkPluginName]
	if chosenPlugin != nil {
		err := chosenPlugin.Init(host, hairpinMode, nonMasqueradeCIDR, mtu)
		if err != nil {
			allErrs = append(allErrs, fmt.Errorf("network plugin %q failed init: %v", networkPluginName, err))
		} else {
			klog.V(1).Infof("Loaded network plugin %q", networkPluginName)
		}
	} else {
		allErrs = append(allErrs, fmt.Errorf("network plugin %q not found", networkPluginName))
	}

	return chosenPlugin, utilerrors.NewAggregate(allErrs)
}
chosenPlugin.Init()

当kubelet运行主要参数--network-plugin的值配备为cni时,会启用到cniNetworkPluginInit()方式,编码以下。

运行一个goroutine,每过5秒,启用一次plugin.syncNetworkConfig。再去追忆一下plugin.syncNetworkConfig()的功效:依据kubelet运行参数配置,去相匹配的cni conf文件夹名称下找寻cni环境变量,回到包括cni信息的cniNetwork建筑结构,取值给cniNetworkPlugin建筑结构的defaultNetwork特性,进而做到cni conf及其bin升级后,kubelet也可以认知并升级cniNetworkPlugin建筑结构的实际效果。

这里还可以看得出该goroutine存在的价值,让cni的环境变量及其可执行程序等能够 热更新,而不用重新启动kubelet。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
	err := plugin.platformInit()
	if err != nil {
		return err
	}

	plugin.host = host

	plugin.syncNetworkConfig()

	// start a goroutine to sync network config from confDir periodically to detect network config updates in every 5 seconds
	go wait.Forever(plugin.syncNetworkConfig, defaultSyncConfigPeriod)

	return nil
}

plugin.platformInit()仅仅查验了下是不是有nsenter,沒有做别的实际操作。

// pkg/kubelet/dockershim/network/cni/cni_others.go
func (plugin *cniNetworkPlugin) platformInit() error {
	var err error
	plugin.nsenterPath, err = plugin.execer.LookPath("nsenter")
	if err != nil {
		return err
	}
	return nil
}

4.CNI搭建pod网络剖析

kubelet建立pod时,根据CRI建立并运行pod sandbox,随后CRI会启用CNI互联网软件搭建pod网络。

kubelet中CNI搭建pod网络的方式是:pkg/kubelet/network/cni/cni.go-SetUpPod

在其中SetUpPod方式的启用链以下(只列举了重要一部分):
main (cmd/kubelet/kubelet.go)
...
-> klet.syncPod(pkg/kubelet/kubelet.go)
-> kl.containerRuntime.SyncPod(pkg/kubelet/kubelet.go)
-> m.createPodSandbox(pkg/kubelet/kuberuntime/kuberuntime_manager.go)
-> m.runtimeService.RunPodSandbox (pkg/kubelet/kuberuntime/kuberuntime_sandbox.go)
-> ds.network.SetUpPod(pkg/kubelet/dockershim/docker_sandbox.go)
-> pm.plugin.SetUpPod(pkg/kubelet/dockershim/network/plugins.go)
-> SetUpPod(pkg/kubelet/dockershim/network/cni/cni.go)

下边的编码仅仅列举看来一下重要方式cniNetworkPlugin.SetUpPod()的启用链,不做深入分析。

// pkg/kubelet/kuberuntime/kuberuntime_manager.go
func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, backOff *flowcontrol.Backoff) (result kubecontainer.PodSyncResult) {
	...
	podSandboxID, msg, err = m.createPodSandbox(pod, podContainerChanges.Attempt)
	...
}
// pkg/kubelet/kuberuntime/kuberuntime_sandbox.go
// createPodSandbox creates a pod sandbox and returns (podSandBoxID, message, error).
func (m *kubeGenericRuntimeManager) createPodSandbox(pod *v1.Pod, attempt uint32) (string, string, error) {
    ...
    podSandBoxID, err := m.runtimeService.RunPodSandbox(podSandboxConfig, runtimeHandler)
    ...
}

RunPodSandbox方式中能够 见到,是先建立pod sandbox,随后运行pod sandbox,随后才算是给该pod sandbox搭建互联网。

// pkg/kubelet/dockershim/docker_sandbox.go
func (ds *dockerService) RunPodSandbox(ctx context.Context, r *runtimeapi.RunPodSandboxRequest) (*runtimeapi.RunPodSandboxResponse, error) {
    ...
    createResp, err := ds.client.CreateContainer(*createConfig)
    ...
    err = ds.client.StartContainer(createResp.ID)
    ...
    err = ds.network.SetUpPod(config.GetMetadata().Namespace, config.GetMetadata().Name, cID, config.Annotations, networkOptions)
    ...
}

PluginManager.SetUpPod方式中能够 见到,启用了pm.plugin.SetUpPod,前边详细介绍cni复位的情况下讲过有关取值复位实际操作,这儿会启用到cniNetworkPluginSetUpPod方式。

// pkg/kubelet/dockershim/network/plugins.go
func (pm *PluginManager) SetUpPod(podNamespace, podName string, id kubecontainer.ContainerID, annotations, options map[string]string) error {
	defer recordOperation("set_up_pod", time.Now())
	fullPodName := kubecontainer.BuildPodFullName(podName, podNamespace)
	pm.podLock(fullPodName).Lock()
	defer pm.podUnlock(fullPodName)

	klog.V(3).Infof("Calling network plugin %s to set up pod %q", pm.plugin.Name(), fullPodName)
	if err := pm.plugin.SetUpPod(podNamespace, podName, id, annotations, options); err != nil {
		return fmt.Errorf("networkPlugin %s failed to set up pod %q network: %v", pm.plugin.Name(), fullPodName, err)
	}

	return nil
}

cniNetworkPlugin.SetUpPod

cniNetworkPlugin.SetUpPod方式功效cni互联网软件搭建pod网络的启用通道。其关键逻辑性为:
(1)启用plugin.checkInitialized():检查网络软件是不是早已复位进行;
(2)启用plugin.host.GetNetNS():获得器皿互联网类名途径,文件格式/proc/${器皿PID}/ns/net
(3)启用context.WithTimeout():设定启用cni互联网软件的请求超时時间;
(3)启用plugin.addToNetwork():如果是linux自然环境,则启用cni互联网软件,给pod搭建环回互联网;
(4)启用plugin.addToNetwork():启用cni互联网软件,给pod搭建默认设置 互联网。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) SetUpPod(namespace string, name string, id kubecontainer.ContainerID, annotations, options map[string]string) error {
	if err := plugin.checkInitialized(); err != nil {
		return err
	}
	netnsPath, err := plugin.host.GetNetNS(id.ID)
	if err != nil {
		return fmt.Errorf("CNI failed to retrieve network namespace path: %v", err)
	}

	// Todo get the timeout from parent ctx
	cniTimeoutCtx, cancelFunc := context.WithTimeout(context.Background(), network.CNITimeoutSec*time.Second)
	defer cancelFunc()
	// Windows doesn't have loNetwork. It comes only with Linux
	if plugin.loNetwork != nil {
		if _, err = plugin.addToNetwork(cniTimeoutCtx, plugin.loNetwork, name, namespace, id, netnsPath, annotations, options); err != nil {
			return err
		}
	}

	_, err = plugin.addToNetwork(cniTimeoutCtx, plugin.getDefaultNetwork(), name, namespace, id, netnsPath, annotations, options)
	return err
}
plugin.addToNetwork

plugin.addToNetwork方式的功效便是启用cni互联网软件,给pod搭建特定种类的互联网,其关键逻辑性为:
(1)启用plugin.buildCNIRuntimeConf():搭建启用cni互联网软件的配备;
(2)启用cniNet.AddNetworkList():启用cni互联网软件,开展互联网搭建。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) addToNetwork(ctx context.Context, network *cniNetwork, podName string, podNamespace string, podSandboxID kubecontainer.ContainerID, podNetnsPath string, annotations, options map[string]string) (cnitypes.Result, error) {
	rt, err := plugin.buildCNIRuntimeConf(podName, podNamespace, podSandboxID, podNetnsPath, annotations, options)
	if err != nil {
		klog.Errorf("Error adding network when building cni runtime conf: %v", err)
		return nil, err
	}

	pdesc := podDesc(podNamespace, podName, podSandboxID)
	netConf, cniNet := network.NetworkConfig, network.CNIConfig
	klog.V(4).Infof("Adding %s to network %s/%s netns %q", pdesc, netConf.Plugins[0].Network.Type, netConf.Name, podNetnsPath)
	res, err := cniNet.AddNetworkList(ctx, netConf, rt)
	if err != nil {
		klog.Errorf("Error adding %s to network %s/%s: %v", pdesc, netConf.Plugins[0].Network.Type, netConf.Name, err)
		return nil, err
	}
	klog.V(4).Infof("Added %s to network %s: %v", pdesc, netConf.Name, res)
	return res, nil
}
cniNet.AddNetworkList

AddNetworkList方式中主要是启用了addNetwork方式,因此 看来下addNetwork方式的逻辑性:
(1)启用c.exec.FindInPath():拼凑出cni互联网软件可执行程序的相对路径;
(2)启用buildOneConfig():搭建配备;
(3)启用c.args():搭建启用cni互联网软件的主要参数;
(4)启用invoke.ExecPluginWithResult():启用cni互联网软件开展pod网络的搭建实际操作。

// vendor/github.com/containernetworking/cni/libcni/api.go 
func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {
	var err error
	var result types.Result
	for _, net := range list.Plugins {
		result, err = c.addNetwork(ctx, list.Name, list.CNIVersion, net, result, rt)
		if err != nil {
			return nil, err
		}
	}

	if err = setCachedResult(result, list.Name, rt); err != nil {
		return nil, fmt.Errorf("failed to set network %q cached result: %v", list.Name, err)
	}

	return result, nil
}

func (c *CNIConfig) addNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) (types.Result, error) {
	c.ensureExec()
	pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
	if err != nil {
		return nil, err
	}

	newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
	if err != nil {
		return nil, err
	}

	return invoke.ExecPluginWithResult(ctx, pluginPath, newConf.Bytes, c.args("ADD", rt), c.exec)
}
c.args

c.args方式功效是搭建启用cni互联网软件可执行程序时的主要参数。

从编码中能够 看得出,主要参数有Command(指令,Add意味着搭建互联网,Del意味着消毁互联网)、ContainerID(器皿ID)、NetNS(器皿互联网类名途径)、IfName(Interface Name即网线端口名字)、PluginArgs(别的主要参数如pod名字、pod类名等)等。

// vendor/github.com/containernetworking/cni/libcni/api.go
func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args {
	return &invoke.Args{
		Command:     action,
		ContainerID: rt.ContainerID,
		NetNS:       rt.NetNS,
		PluginArgs:  rt.Args,
		IfName:      rt.IfName,
		Path:        strings.Join(c.Path, string(os.PathListSeparator)),
	}
}
invoke.ExecPluginWithResult

invoke.ExecPluginWithResult主要是将启用主要参数变为env,随后启用cni互联网软件可执行程序,并获得回到結果。

func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) {
	if exec == nil {
		exec = defaultExec
	}

	stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv())
	if err != nil {
		return nil, err
	}

	// Plugin must return result in same version as specified in netconf
	versionDecoder := &version.ConfigDecoder{}
	confVersion, err := versionDecoder.Decode(netconf)
	if err != nil {
		return nil, err
	}

	return version.NewResult(confVersion, stdoutBytes)
}

5.CNI消毁pod网络剖析

kubelet删掉pod时,CRI会启用CNI互联网软件消毁pod网络。

kubelet中CNI消毁pod网络的方式是:pkg/kubelet/network/cni/cni.go-TearDownPod

在其中TearDownPod方式的启用链以下(只列举了重要一部分):
main (cmd/kubelet/kubelet.go)
...
-> m.runtimeService.StopPodSandbox (pkg/kubelet/kuberuntime/kuberuntime_sandbox.go)
-> ds.network.TearDownPod(pkg/kubelet/dockershim/docker_sandbox.go)
-> pm.plugin.TearDownPod(pkg/kubelet/dockershim/network/plugins.go)
-> TearDownPod(pkg/kubelet/dockershim/network/cni/cni.go)

下边的编码仅仅列举看来一下重要方式cniNetworkPlugin.TearDownPod()的启用链,不做深入分析。

StopPodSandbox方式中能够 见到,会先消毁pod网络,随后终止pod sandbox的运作,可是这两个实际操作中的一切一个产生不正确,kubelet都是会再次开展再试,直至取得成功截止,因此 对这两个提交成功的次序并沒有严苛的规定(删掉pod sandbox的实际操作由kubelet gc去进行)。

// pkg/kubelet/dockershim/docker_sandbox.go
func (ds *dockerService) StopPodSandbox(ctx context.Context, r *runtimeapi.StopPodSandboxRequest) (*runtimeapi.StopPodSandboxResponse, error) {
    ...
    // WARNING: The following operations made the following assumption:
	// 1. kubelet will retry on any error returned by StopPodSandbox.
	// 2. tearing down network and stopping sandbox container can succeed in any sequence.
	// This depends on the implementation detail of network plugin and proper error handling.
	// For kubenet, if tearing down network failed and sandbox container is stopped, kubelet
	// will retry. On retry, kubenet will not be able to retrieve network namespace of the sandbox
	// since it is stopped. With empty network namespcae, CNI bridge plugin will conduct best
	// effort clean up and will not return error.
	errList := []error{}
	ready, ok := ds.getNetworkReady(podSandboxID)
	if !hostNetwork && (ready || !ok) {
		// Only tear down the pod network if we haven't done so already
		cID := kubecontainer.BuildContainerID(runtimeName, podSandboxID)
		err := ds.network.TearDownPod(namespace, name, cID)
		if err == nil {
			ds.setNetworkReady(podSandboxID, false)
		} else {
			errList = append(errList, err)
		}
	}
	if err := ds.client.StopContainer(podSandboxID, defaultSandboxGracePeriod); err != nil {
		// Do not return error if the container does not exist
		if !libdocker.IsContainerNotFoundError(err) {
			klog.Errorf("Failed to stop sandbox %q: %v", podSandboxID, err)
			errList = append(errList, err)
		} else {
			// remove the checkpoint for any sandbox that is not found in the runtime
			ds.checkpointManager.RemoveCheckpoint(podSandboxID)
		}
	}
    ...
}

PluginManager.TearDownPod方式中能够 见到,启用了pm.plugin.TearDownPod,前边详细介绍cni复位的情况下讲过有关取值复位实际操作,这儿会启用到cniNetworkPluginTearDownPod方式。

// pkg/kubelet/dockershim/network/plugins.go
func (pm *PluginManager) TearDownPod(podNamespace, podName string, id kubecontainer.ContainerID) error {
	defer recordOperation("tear_down_pod", time.Now())
	fullPodName := kubecontainer.BuildPodFullName(podName, podNamespace)
	pm.podLock(fullPodName).Lock()
	defer pm.podUnlock(fullPodName)

	klog.V(3).Infof("Calling network plugin %s to tear down pod %q", pm.plugin.Name(), fullPodName)
	if err := pm.plugin.TearDownPod(podNamespace, podName, id); err != nil {
		return fmt.Errorf("networkPlugin %s failed to teardown pod %q network: %v", pm.plugin.Name(), fullPodName, err)
	}

	return nil
}

cniNetworkPlugin.TearDownPod

cniNetworkPlugin.TearDownPod方式功效cni互联网软件消毁pod网络的启用通道。其关键逻辑性为:
(1)启用plugin.checkInitialized():检查网络软件是不是早已复位进行;
(2)启用plugin.host.GetNetNS():获得器皿互联网类名途径,文件格式/proc/${器皿PID}/ns/net
(3)启用context.WithTimeout():设定启用cni互联网软件的请求超时時间;
(3)启用plugin.deleteFromNetwork():如果是linux自然环境,则启用cni互联网软件,消毁pod的环回互联网;
(4)启用plugin.deleteFromNetwork():启用cni互联网软件,消毁pod的默认设置 互联网。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) TearDownPod(namespace string, name string, id kubecontainer.ContainerID) error {
	if err := plugin.checkInitialized(); err != nil {
		return err
	}

	// Lack of namespace should not be fatal on teardown
	netnsPath, err := plugin.host.GetNetNS(id.ID)
	if err != nil {
		klog.Warningf("CNI failed to retrieve network namespace path: %v", err)
	}

	// Todo get the timeout from parent ctx
	cniTimeoutCtx, cancelFunc := context.WithTimeout(context.Background(), network.CNITimeoutSec*time.Second)
	defer cancelFunc()
	// Windows doesn't have loNetwork. It comes only with Linux
	if plugin.loNetwork != nil {
		// Loopback network deletion failure should not be fatal on teardown
		if err := plugin.deleteFromNetwork(cniTimeoutCtx, plugin.loNetwork, name, namespace, id, netnsPath, nil); err != nil {
			klog.Warningf("CNI failed to delete loopback network: %v", err)
		}
	}

	return plugin.deleteFromNetwork(cniTimeoutCtx, plugin.getDefaultNetwork(), name, namespace, id, netnsPath, nil)
}
plugin.deleteFromNetwork

plugin.deleteFromNetwork方式的功效便是启用cni互联网软件,消毁pod特定种类的互联网,其关键逻辑性为:
(1)启用plugin.buildCNIRuntimeConf():搭建启用cni互联网软件的配备;
(2)启用cniNet.DelNetworkList():启用cni互联网软件,开展pod网络消毁。

// pkg/kubelet/dockershim/network/cni/cni.go
func (plugin *cniNetworkPlugin) deleteFromNetwork(ctx context.Context, network *cniNetwork, podName string, podNamespace string, podSandboxID kubecontainer.ContainerID, podNetnsPath string, annotations map[string]string) error {
	rt, err := plugin.buildCNIRuntimeConf(podName, podNamespace, podSandboxID, podNetnsPath, annotations, nil)
	if err != nil {
		klog.Errorf("Error deleting network when building cni runtime conf: %v", err)
		return err
	}

	pdesc := podDesc(podNamespace, podName, podSandboxID)
	netConf, cniNet := network.NetworkConfig, network.CNIConfig
	klog.V(4).Infof("Deleting %s from network %s/%s netns %q", pdesc, netConf.Plugins[0].Network.Type, netConf.Name, podNetnsPath)
	err = cniNet.DelNetworkList(ctx, netConf, rt)
	// The pod may not get deleted successfully at the first time.
	// Ignore "no such file or directory" error in case the network has already been deleted in previous attempts.
	if err != nil && !strings.Contains(err.Error(), "no such file or directory") {
		klog.Errorf("Error deleting %s from network %s/%s: %v", pdesc, netConf.Plugins[0].Network.Type, netConf.Name, err)
		return err
	}
	klog.V(4).Infof("Deleted %s from network %s/%s", pdesc, netConf.Plugins[0].Network.Type, netConf.Name)
	return nil
}
cniNet.DelNetworkList

DelNetworkList方式中主要是启用了addNetwork方式,因此 看来下addNetwork方式的逻辑性:
(1)启用c.exec.FindInPath():拼凑出cni互联网软件可执行程序的相对路径;
(2)启用buildOneConfig():搭建配备;
(3)启用c.args():搭建启用cni互联网软件的主要参数;
(4)启用invoke.ExecPluginWithResult():启用cni互联网软件开展pod网络的消毁实际操作。

// vendor/github.com/containernetworking/cni/libcni/api.go 
// DelNetworkList executes a sequence of plugins with the DEL command
func (c *CNIConfig) DelNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) error {
	var cachedResult types.Result

	// Cached result on DEL was added in CNI spec version 0.4.0 and higher
	if gtet, err := version.GreaterThanOrEqualTo(list.CNIVersion, "0.4.0"); err != nil {
		return err
	} else if gtet {
		cachedResult, err = getCachedResult(list.Name, list.CNIVersion, rt)
		if err != nil {
			return fmt.Errorf("failed to get network %q cached result: %v", list.Name, err)
		}
	}

	for i := len(list.Plugins) - 1; i >= 0; i-- {
		net := list.Plugins[i]
		if err := c.delNetwork(ctx, list.Name, list.CNIVersion, net, cachedResult, rt); err != nil {
			return err
		}
	}
	_ = delCachedResult(list.Name, rt)

	return nil
}

func (c *CNIConfig) delNetwork(ctx context.Context, name, cniVersion string, net *NetworkConfig, prevResult types.Result, rt *RuntimeConf) error {
	c.ensureExec()
	pluginPath, err := c.exec.FindInPath(net.Network.Type, c.Path)
	if err != nil {
		return err
	}

	newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
	if err != nil {
		return err
	}

	return invoke.ExecPluginWithoutResult(ctx, pluginPath, newConf.Bytes, c.args("DEL", rt), c.exec)
}
c.args

c.args方式功效是搭建启用cni互联网软件可执行程序时的主要参数。

从编码中能够 看得出,主要参数有Command(指令,Add意味着搭建互联网,Del意味着消毁互联网)、ContainerID(器皿ID)、NetNS(器皿互联网类名途径)、IfName(Interface Name即网线端口名字)、PluginArgs(别的主要参数如pod名字、pod类名等)等。

// vendor/github.com/containernetworking/cni/libcni/api.go
func (c *CNIConfig) args(action string, rt *RuntimeConf) *invoke.Args {
	return &invoke.Args{
		Command:     action,
		ContainerID: rt.ContainerID,
		NetNS:       rt.NetNS,
		PluginArgs:  rt.Args,
		IfName:      rt.IfName,
		Path:        strings.Join(c.Path, string(os.PathListSeparator)),
	}
}
invoke.ExecPluginWithResult

invoke.ExecPluginWithResult主要是将启用主要参数变为env,随后启用cni互联网软件可执行程序,并获得回到結果。

func ExecPluginWithResult(ctx context.Context, pluginPath string, netconf []byte, args CNIArgs, exec Exec) (types.Result, error) {
	if exec == nil {
		exec = defaultExec
	}

	stdoutBytes, err := exec.ExecPlugin(ctx, pluginPath, netconf, args.AsEnv())
	if err != nil {
		return nil, err
	}

	// Plugin must return result in same version as specified in netconf
	versionDecoder := &version.ConfigDecoder{}
	confVersion, err := versionDecoder.Decode(netconf)
	if err != nil {
		return nil, err
	}

	return version.NewResult(confVersion, stdoutBytes)
}

汇总

CNI

CNI,全名是 Container Network Interface,即器皿网线端口。

CNI是K8s 中规范的启用互联网完成的插口。Kubelet 根据这一规范的插口来启用不一样的互联网软件以完成不一样的网络配置方法。

CNI互联网软件是一个可执行程序,是遵循器皿网线端口(CNI)标准的互联网软件。普遍的 CNI互联网软件包含 Calico、flannel、Terway、Weave Net等。

当kubelet挑选应用CNI种类的互联网软件时(根据kubelet运行主要参数特定),kubelet在建立pod、删掉pod的情况下,根据CRI启用CNI互联网软件来做pod的搭建互联网和消毁互联网等实际操作。

kubelet搭建pod网络的大概全过程

(1)kubelet先根据CRI建立pause器皿(pod sandbox),转化成network namespace;
(2)kubelet依据运行参数配置启用实际的互联网软件如CNI互联网软件;
(3)互联网软件给pause器皿(pod sandbox)配备互联网;
(4)pod 中别的的器皿都和pause器皿(pod sandbox)分享网络。

kubelet部件CNI有关运行主要参数剖析

(1)--network-plugin:特定要应用的互联网软件种类,可选值cnikubenet"",默认设置 为空串,意味着Noop,即不配备互联网软件(不搭建pod网络)。这里配备数值cni时,即特定kubelet应用的互联网软件种类为cni

(2)--cni-conf-dir:CNI 环境变量所属途径。初始值:/etc/cni/net.d

(3)--cni-bin-dir:CNI 软件的可执行程序所属途径,kubelet 将在这里途径中搜索 CNI 软件的可执行程序来实行pod的互联网实际操作。初始值:/opt/cni/bin

kubelet中的CNI复位

kubelet运行后,会依据运行主要参数中cni的有关主要参数,获得cni环境变量并复位cni互联网软件,待事后建立pod、删掉pod的时候会启用SetUpPodTearDownPod方式来搭建pod的互联网、消毁pod的互联网。与此同时,复位时起了一个goroutine,按时检测cni的环境变量及其可执行程序,让其能够 热更新。

CNI搭建pod网络

kubelet建立pod时,根据CRI建立并运行pod sandbox,随后CRI会启用CNI互联网软件搭建pod网络。

kubelet中CNI搭建pod网络的编码方式是:pkg/kubelet/network/cni/cni.go-SetUpPod

CNI消毁pod网络

kubelet删掉pod时,CRI会启用CNI互联网软件消毁pod网络。

kubelet中CNI消毁pod网络的方式是:pkg/kubelet/network/cni/cni.go-TearDownPod

评论(0条)

刀客源码 游客评论