暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

技术干货丨cilium 原理之pod ep,bpf 创建流程

沃趣技术 2024-05-24
371

在此前的多篇文章中,我们详细的讲解了cilium 的多个原理,本篇文章我们将通过多个细致流程详解pod ep以及bpf的创建流程。


在pod创建后,到pod的网络就绪,这中间涉及到多个组件的流程:


  1. ip地址分配

  2. lxc网卡创建

  3. cilium endpoint的创建

  4. ebpf程序注入

整体时序图⬇️⬇️⬇️


相关说明

  1. cri 以 docker-shim为例,整个网络的初始化,是由cri调用cni的接口触发的

  2. cni 以 cilium 为例,主要分三步:

    1. 调用ipam申请ip

    2. 基于ip初始化lxc网卡

    3. 调用createEndpoint接口

其它的步骤大致调用流程已经在上图中标识,下面将详细说明endpoint的创建过程


1、cilium endpoint初始化流程



关于cilium endpoint有两个特殊的id:endpointIDidentityID。其中,endpointID为单主机唯一,identityID为全局唯一。


1.1、endpointID的生成


通过mgr.expose(ep)调用,本地加互斥锁,生成endpointID


    // ids is a slice of IDs available in this idCache.
     ids map[ID]struct{}
     // 初始化时,将65535个id保存在ids中。每次取第一个。
     for id := range c.ids {
       delete(c.ids, id)
       return id
     }
     // 释放时,将id保存回来
     c.ids[id] = struct{}{}
     // id是可以反复复用的


    1.2、identityID的生成


    上图中,有个 d.identityAllocator 对象,用于管理identityID的生成


    由于identity需要全局唯一,所以基于分布式锁,cilium实现了一个backend接口。而这里主要讲基于k8s的crd实现的逻辑。


    因为k8s的crd的name+namespace是全局唯一的,所以只需要基于id创建ciliumIdentity资源,能创建成功,就表示获取了全局唯一资源。


      [root@c7-1 ~]# k get ciliumidentity
      NAME NAMESPACE AGE
      17392 default 131d
      2151 default 167d
      22412 kube-system 257d
      25213 kube-system 257d
      35453 default 131d
      3734 default 256d
      43561 default 256d
      60364 kube-system 257d


      从程序逻辑上,ciliumIdentity 是基于labels要求全局唯一的。为实现这个功能,cilium会先确保所有ciliumIdentity资源都同步到本地,然后基于本地id池中分配一个可用的,完成id到labels的关联。


      最后梳理下核心:ebpf程序的加载


      1.3、ebpf程序加载流程


      ebpf程序加载会发生在几种情况下:

      1. 第一次创建时进行初始化

      2. cilium重启时,会进行一次regenerate(按需初始化)

      3. 用户执行cilium endpoint regenerate 时(按需)

      4. 用户执行ciluim config时(按需)

      staus状态机:

      由于状态机是基于代码流程梳理出来,实际代码中,并没有严格的状态控制。所以状态切换场景可能是不完整的。


      重新编译ebpf级别:DatapathRegenerationLevel


      1. 0 -> “invalid” (未设置)

      2. 1:RegenerateWithoutDatapath -> “no-rebuild”

      3. 2:RegenerateWithDatapathLoad -> “reload”

      4. 3:RegenerateWithDatapathRewrite -> “rewrite+reload” (ep第一次创建时,为该级别)

      5. 4:RegenerateWithDatapathRebuild -> “compile+reload”

      1.3.1、第一次初始化
      第一次初始化时,编译级别设置为3

      二、重启时reload
      编译级别设置为3

      三、cilium endpoint regenrate
      编译级别设置为4

        // pkg/endpoint/endpoint.go
        // func (e *Endpoint) identityLabelsChanged
        regenMetadata := &regeneration.ExternalRegenerationMetadata{
           Reason:            "updated security labels",
           RegenerationLevel: regeneration.RegenerateWithDatapathRewrite,
         }


        四、cilium config
        比如调用 cilium config debug=true,会触发所有ebpf程序的重新生成与加载,组编译级别为3


        五、regenerate ebpf

        总体流程图


        从上图可看出,基于编译级别,会分别调用三个函数来处理。下面将单独分析这三个函数


        • CompileAndLoad 完全编译并且加载ebpf程序(编译级别=4时触发)

        tc 编译命令详细说明:

        1. 编译了 bpf_lxc.dbg.o,bpf_lxc.asm,bpf_lxc.c,bpf_lxc.o ,除了bpf_lxc.o用于运行外,其它是用于debug的

        2. 命令都基本类似,先由clang编译生成.c文件,再由llc编译生成.o文件

        3. 编译的bpf_lxc.c是所有程序大集合,可以方便我们阅读代码,

        4. 不过,正式运行时,除了 bpf_lxc.o 会保留外,其它文件都会清理


          # build dbg.o
          clang -emit-llvm -g -O2 -target bpf -std=gnu89 -nostdinc -D__NR_CPUS__=8 -Wall -Wextra -Werror -Wshadow -Wno-address-of-packed-member -Wno-unknown-warning-option -Wno-gnu-variable-sized-type-not-at-end -Wdeclaration-after-statement -Wimplicit-int-conversion -Wenum-conversion -D__MAGIC_FILE__=8 -I/var/run/cilium/state/globals -I3703_next -I/var/lib/cilium/bpf -I/var/lib/cilium/bpf/include -c var/lib/cilium/bpf/bpf_lxc.c -o - | llc -mattr=dwarfris -march=bpf -mcpu=v2 -filetype=obj -o 3703_next/bpf_lxc.dbg.o


          # build .asm
          clang -emit-llvm -g -O2 -target bpf -std=gnu89 -nostdinc -D__NR_CPUS__=8 -Wall -Wextra -Werror -Wshadow -Wno-address-of-packed-member -Wno-unknown-warning-option -Wno-gnu-variable-sized-type-not-at-end -Wdeclaration-after-statement -Wimplicit-int-conversion -Wenum-conversion -D__MAGIC_FILE__=8 -I/var/run/cilium/state/globals -I3703_next -I/var/lib/cilium/bpf -I/var/lib/cilium/bpf/include -c var/lib/cilium/bpf/bpf_lxc.c -o - |llc -march=bpf -mcpu=v2 -filetype=asm -o 3703_next/bpf_lxc.asm


          # build .c
          clang -E -O2 -target bpf -std=gnu89 -nostdinc -D__NR_CPUS__=8 -Wall -Wextra -Werror -Wshadow -Wno-address-of-packed-member -Wno-unknown-warning-option -Wno-gnu-variable-sized-type-not-at-end -Wdeclaration-after-statement -Wimplicit-int-conversion -Wenum-conversion -D__MAGIC_FILE__=8 -I/var/run/cilium/state/globals -I3703_next -I/var/lib/cilium/bpf -I/var/lib/cilium/bpf/include -c var/lib/cilium/bpf/bpf_lxc.c -o 3703_next


          # build lxc.o
          clang -emit-llvm -g -O2 -target bpf -std=gnu89 -nostdinc -D__NR_CPUS__=8 -Wall -Wextra -Werror -Wshadow -Wno-address-of-packed-member -Wno-unknown-warning-option -Wno-gnu-variable-sized-type-not-at-end -Wdeclaration-after-statement -Wimplicit-int-conversion -Wenum-conversion -D__MAGIC_FILE__=8 -I/var/run/cilium/state/globals -I3703_next -I/var/lib/cilium/bpf -I/var/lib/cilium/bpf/include -c var/lib/cilium/bpf/bpf_lxc.c -o - | llc -mattr=dwarfris -march=bpf -mcpu=v2 -filetype=obj -o 3703_next/bpf_lxc.o


          # bind to lxc
          tc filter replace dev lxc56c1f1723430 ingress prio 1 handle 1 bpf da obj 3703_next/bpf_lxc.o sec from-container


          cilium bpf migrate-maps是个隐藏命令,cilium bpf -h是看不到的,cilium bpf migrate-maps -h可以。命令也是可执行的。


          • CompileOrLoad 编译加载或者只是单纯加载ebpf程序(编译级别=3时触发)


          1.3.6、ebpf程序重新加载说明


          基于官方的回复:

          Changing settings via cilium config should not cause any in-progress connections to be dropped. In fact, Cilium is designed such that restarting the agent should not affect pod networking - including existing and new connections during agent restart.


          因为ebpf程序加载到内核,是原子性操作,而且加载失败时,不影响旧的程序的运行。所以cilium的重启与重加载ebpf是安全的。但有一点,cilium早期版本,比如1.9时,由于安装部署设计的不好,导致cilium pod重启时,bpf目录会卸载并重新挂载,导致了epbf程序会出现失效,新版本从1.10开始,已经完善了该问题。


          2、扩展

          1. ipam是 ip allocate manager ,可基于该模块实现固定ip相关功能。cilium的ip分配信息都保存在 ciliumnode 中,并在启动时加载到本地缓存中,按需同步更新到 ciliumnode 上,减少 apiserver 的压力

          2. 关于 cilium 的运行观察,可以在 /var/run/cilium/state 目录下执行 inotifywait -r -m . -e open -e move -e create -e delete 查看相关文件的生成情况

          3. cilium 在完成ep的初始化后,后续将详细介绍网络数据包的流转目录

          本期作者丨沃趣科技产品研发部

          版权作品,未经许可禁止转载



          往期作品快速浏览:





          文章转载自沃趣技术,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论