在上一篇中,通过对 CNI 规范的解读了解了网络配置的操作和相关的流程。在网络的几个操作中除了 CNI_COMMAND
外,有另外三个参数几乎每次都要提供 CNI_CONTAINERID
、CNI_IFNAME
和 CNI_NETNS
,这些参数无外乎都来自容器运行时。这篇将结合 Kubernetes 和 Containerd[1] 源码,来分析一下 CNI 的使用。
Kubernetes 的源码来自分支 release-1.24
,Containerd 的来自分支 release/1.6
。
在之前做过的 kubelet 源码分析 中曾提到 Kubelet#syncLoop()
会持续监控来自 文件、apiserver、http 的变更,来更新 pod 的状态。写那篇文章的时候,分析到这里就结束了。因为这之后的工作就交给容器运行时来完成 sandbox 和各种容器的创建和运行,见 kubeGenericRuntimeManager#SyncPod()
。
kubelet
封装 sandbox 和容器创建、运行请求,调用容器运行时的接口,将具体工作交由容器运行时来完成来完成(容器运行时接口 Container Runtime Interface,简称 CRI,找时间再进行研究)。
记得在 系列的第一篇 中,当我们在节点上查看命名空间时,网络命名空间的进程是 /pause
。
lsns -t net
NS TYPE NPROCS PID USER NETNSID NSFS COMMAND
4026531992 net 126 1 root unassigned /lib/systemd/systemd --system --deserialize 31
4026532247 net 1 83224 uuidd unassigned /usr/sbin/uuidd --socket-activation
4026532317 net 4 129820 65535 0 /run/netns/cni-607c5530-b6d8-ba57-420e-a467d7b10c56 /pause
Kubernetes 在创建 pod 时,会先一个创建 sandbox 容器(使用 pause
镜像,启动时执行 /pause
进入休眠状态)。我们知道 Kubernetes 的 pod 中是允许多容器的,由这个 sandbox 容器来创建和维持网络命名空间,pod 的其他容器会加入到该命名空间中。因为 pause 镜像足够简单,不会出错导致网络管理空间在出错时被删除。sandbox 容器发挥着至关重要的作用[4],它在 PID 进程空间的进程树中作为 PID 为 1 的进程,其他容器进程都将其作为父进程。当其他容器的进程成为孤儿进程时,可以得到清理。
CRI 的 RuntimeServiceServer
定义了运行时对外提供的服务接口,除了管理 sandbox、容器相关的操作外,还有 streaming 相关的操作,即常用的 exec
、attach
、portforward
。streaming 相关的内容,可以参考之前的一篇 《源码解析 kubectl port-forward 工作原理》。
让我们来看容器相关的部分。
Containerd 的 criService
实现了 RuntimeServiceServer
的接口。创建 sandbox 容器的请求通过 CRI 的 UDS(Unix domain socket)[5] 接口 /runtime.v1.RuntimeService/RunPodSandbox
,进入到 criService
的处理流程中。在 criService#RunPodSandbox()
,负责创建和运行 sandbox 容器,并保证容器状态正常。
CNI_CONTAINERID
CNI_NETNS
从零开始学习容器,推荐阅读 Ivan Velichko 的 《Learning Containers From The Bottom Up》[6]
接下来就是创建 pod 内的其他容器:临时(ephemeral
)、初始化(init
)和普通容器,创建这些容器的时候,会将容器加入到 sandox 的网络命名空间中。这里不展开,详细逻辑可参考 containerd 的 containerStore#Create()
。
接着上篇 CNI 的规范介绍,这次又介绍了 CNI 的使用,以及如何与容器运行时的交互、Pod 的创建流程。
不同的 CNI 插件,实现了不一样的网络功能。下篇,将以 Flannel[11] 为例来了解下 CNI 的实现,以及 Kubernetes VXLAN 网络。
为什么介绍 flannel?因为我常用的开发环境之一 k3s[12] 默认就用的 flannel 网络。另一个开发环境是 k8e[13],k8e 默认用的是 Cilium[14],cilium 的 cni 也是系列的文章之一。
Containerd: https://containerd.io
[2]pkg/kubelet/kubelet.go:1985
: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kubelet.go#L1985
pkg/kubelet/kuberuntime/kuberuntime_manager.go:711
: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L711
sandbox 容器发挥着至关重要的作用: https://www.ianlewis.org/en/almighty-pause-container
[5]UDS(Unix domain socket): https://en.wikipedia.org/wiki/Unix_domain_socket
[6]《Learning Containers From The Bottom Up》: https://iximiuz.com/en/posts/container-learning-path/
[7]pkg/cri/server/sandbox_run.go:61
: https://github.com/containerd/containerd/blob/release/1.6/pkg/cri/server/sandbox_run.go#L61
pkg/cri/server/sandbox_run.go:422
: https://github.com/containerd/containerd/blob/release/1.6/pkg/cri/server/sandbox_run.go#L422
pkg/kubelet/kuberuntime/kuberuntime_manager.go:913
: https://github.com/kubernetes/kubernetes/blob/release-1.24/pkg/kubelet/kuberuntime/kuberuntime_manager.go#L913
pkg/cri/server/container_create.go:51
: https://github.com/containerd/containerd/blob/release/1.6/pkg/cri/server/container_create.go#L51
Flannel: https://github.com/flannel-io/flannel
[12]k3s: https://k3s.io/
[13]k8e: https://getk8e.com/
[14]Cilium: https://cilium.io/
《Docker中Image、Container与Volume的迁移》
免责声明:本文内容来源于网络,所载内容仅供参考。转载仅为学习和交流之目的,如无意中侵犯您的合法权益,请及时联系Docker中文社区!