Kubernetes Network Plugins

对于 K8s 系统来说,预留了多个可拓展点,我们就先来看看 CNI 网络拓展点。

How it works

CNI 的中定义关于 k8s 对于网络部分的可拓展性定义。

plugin.go 中展示了插件的加载逻辑。

而比较重要的是我们的插件是如何真正的工作的,这部分的逻辑显然 k8s 需要和我们自己所构建的 cni 进行通讯,那我们先来看看模板函数

SetUpPodgithub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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) // 获得netns,这里的 Host 是因为插件都是以 Deamset 运行,拿取的是宿主机的 Net 命名空间
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
}
}

// 这里需要执行就是插件本身需要执行的逻辑了 addToNetwork
_, err = plugin.addToNetwork(cniTimeoutCtx, plugin.getDefaultNetwork(), name, namespace, id, netnsPath, annotations, options)
return err
}

而我们知道了,对于 k8s 本身来说,我们只是需要调用 插件 的 addToNetwork,而这层的封装是单独放置于 containernetworking-cni 之中的。在分析之前,我们在最初的 k8s 的文档中有涉及到,我们使用 CNI 至少需要

  • bin: CNI 的二进制文件
  • conf: CNI 的配置文件

而这里的 plugin 在逻辑上也只是 bin 的一层封装。

addNetworkgithub
1
2
3
4
5
6
7
8
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
}
return invoke.ExecPluginWithResult(ctx, pluginPath, newConf.Bytes, c.args("ADD", rt), c.exec)
}

而本质上,当系统创建了一个新 POD 的时候,k8s 就会通过 Exec 去执行这个 Bin 文件,将上下文对象作为参数传入

image

当然除了这种一次性的模式,我们也可以单独启动一个 Server 这里只是接受入参,逻辑部分放置于 Server 之上。

参考