K8S-网络插件原理

一 前言

  • CNI和kubelet关系

    kubelet负责创建POD,POD启动和删除(可以类比为虚拟机)需要设置网络环境。kubelet自身不关心网络实现,它调用CNI实现。

  • CNI实现能否同时存在多个?
    答案:可以有多个,但是kubelet只会使用第一个有效的插件。如果不同的POD网络插件不一致,它们将无法通信。

二 kubelet启动

image

2.1 kubelet启动命令

kubelet \
    --network-plugin=cni 
    --cni-conf-dir=/etc/cni/net.d 
    --cni-bin-dir=/opt/cni/bin 
    ...

通过--network-plugin指定要使用的网络插件类型。

2.2 Runtime设置

cmd/kubelet/app/server.go:createAndInitKubelet

默认k8s的运行时是Docker。

switch containerRuntime {
case kubetypes.DockerContainerRuntime:
   streamingConfig := getStreamingConfig(kubeCfg, kubeDeps, crOptions)
   ds, err := dockershim.NewDockerService(kubeDeps.DockerClientConfig, crOptions.PodSandboxImage, streamingConfig,
      &pluginSettings, runtimeCgroups, kubeCfg.CgroupDriver, crOptions.DockershimRootDirectory, !crOptions.RedirectContainerStreaming)
  // 省略...
case kubetypes.RemoteContainerRuntime:
   // No-op.
   break
default:
   return nil, fmt.Errorf("unsupported CRI runtime: %q", containerRuntime)
}

2.3 网络插件加载

pkg/kubelet/dockershim/docker_service.go:NewDockerService

网络插件有两种实现cni、kubenet,一般都使用cni。

func NewDockerService(config *ClientConfig, podSandboxImage string, streamingConfig *streaming.Config, pluginSettings *NetworkPluginSettings,
    cgroupsName string, kubeCgroupDriver string, dockershimRootDir string, startLocalStreamingServer bool) (DockerService, error) {

    client := NewDockerClientFromConfig(config)
    // cni插件
    pluginSettings.PluginBinDirs = cni.SplitDirs(pluginSettings.PluginBinDirString)
    cniPlugins := cni.ProbeNetworkPlugins(pluginSettings.PluginConfDir, pluginSettings.PluginCacheDir, pluginSettings.PluginBinDirs)
    // kubenet插件
    cniPlugins = append(cniPlugins, kubenet.NewPlugin(pluginSettings.PluginBinDirs, pluginSettings.PluginCacheDir))
    netHost := &dockerNetworkHost{
        &namespaceGetter{ds},
        &portMappingGetter{ds},
    }
    // 插件初始化
    plug, err := network.InitNetworkPlugin(cniPlugins, pluginSettings.PluginName, netHost, pluginSettings.HairpinMode, pluginSettings.NonMasqueradeCIDR, pluginSettings.MTU)
    // 省略
    return ds, nil
}

三 CNI插件

3.1 插件初始化

func ProbeNetworkPlugins(confDir, cacheDir string, binDirs []string) []network.NetworkPlugin {
    //设置可执行程序路径、配置文件路径等
    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}
}

3.2 插件实现加载

按照配置文件名称加载实现,找到第一个有效的实现作为CNI实现。

func getDefaultCNINetwork(confDir string, binDirs []string) (*cniNetwork, error) {
    // 从/etc/cni/net.d 查找后缀为conf,conflist,json的配置文件
    files, err := libcni.ConfFiles(confDir, []string{".conf", ".conflist", ".json"})
    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)
        } else {
            conf, err := libcni.ConfFromFile(confFile)
            confList, err = libcni.ConfListFromConf(conf)
        }
        // 校验可执行程序是否存在
        caps, err := cniConfig.ValidateNetworkList(context.TODO(), confList)
        return &cniNetwork{
            name:          confList.Name,
            NetworkConfig: confList,
            CNIConfig:     cniConfig,
            Capabilities:  caps,
        }, nil
    }
    return nil, fmt.Errorf("no valid networks found in %s", confDir)
}

3.3 配置

读取配置文件,它的内容如下图所示.

{
      "cniVersion": "0.3.1",
      "name": "my-cni",
      "type": "my-cni",
      "podcidr": "10.244.2.0/24"
}

四 网络插件初始化

下面以cni的网络插件分析,cni从配置文件加载用户的网络实现后,开始监控配置是否变更。

func (plugin *cniNetworkPlugin) Init(host network.Host, hairpinMode kubeletconfig.HairpinMode, nonMasqueradeCIDR string, mtu int) error {
    err := plugin.platformInit()
    plugin.host = host
    plugin.syncNetworkConfig()
    // 定时监控配置文件是否发生变更
    go wait.Forever(plugin.syncNetworkConfig, defaultSyncConfigPeriod)
    return nil
}

五 插件使用

5.1 容器网络设置

在pod创建后启动之前设置网络信息

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)
    // 添加pod到网络中
    _, err = plugin.addToNetwork(cniTimeoutCtx, plugin.getDefaultNetwork(), name, namespace, id, netnsPath, annotations, options)
    return err
}

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)
    // 调用CNI接口
    res, err := cniNet.AddNetworkList(ctx, netConf, rt)
    return res, nil
}

5.2 CNI

cni关联到用户的实现,从代码中可以看出,自己的CNI实现是一个可执行程序,需要包含ADD等命令。

type CNI interface {
    AddNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)
    CheckNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
    DelNetworkList(ctx context.Context, net *NetworkConfigList, rt *RuntimeConf) error
    GetNetworkListCachedResult(net *NetworkConfigList, rt *RuntimeConf) (types.Result, error)

    AddNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) (types.Result, error)
    CheckNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
    DelNetwork(ctx context.Context, net *NetworkConfig, rt *RuntimeConf) error
    GetNetworkCachedResult(net *NetworkConfig, rt *RuntimeConf) (types.Result, error)

    ValidateNetworkList(ctx context.Context, net *NetworkConfigList) ([]string, error)
    ValidateNetwork(ctx context.Context, net *NetworkConfig) ([]string, error)
}

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)
    newConf, err := buildOneConfig(name, cniVersion, net, prevResult, rt)
    // 调用ADD方法
    return invoke.ExecPluginWithResult(ctx, pluginPath, newConf.Bytes, c.args("ADD", rt), c.exec)
}

// AddNetworkList executes a sequence of plugins with the ADD command
func (c *CNIConfig) AddNetworkList(ctx context.Context, list *NetworkConfigList, rt *RuntimeConf) (types.Result, error) {

    for _, net := range list.Plugins {
        result, err = c.addNetwork(ctx, list.Name, list.CNIVersion, net, result, rt)
    }
    return result, nil
}

六 参考

https://www.lijiaocn.com/%E9%A1%B9%E7%9B%AE/2017/05/03/Kubernetes-pod-network.html#%E5%B0%86%E5%AE%B9%E5%99%A8%E5%8A%A0%E5%85%A5%E6%8C%87%E5%AE%9A%E7%BD%91%E7%BB%9C

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容