kubernetes/k8s CRI分析-容器运行时接口分析

关联博客:kubernetes/k8s CSI分析-容器存储接口分析
kubernetes/k8s CNI分析-容器网络接口分析

概述

kubernetes的设计初衷是支持可插拔架构,从而利于扩展kubernetes的功能。在此架构思想下,kubernetes提供了3个特定功能的接口,分别是容器网络接口CNI、容器运行时接口CRI和容器存储接口CSIkubernetes通过调用这几个接口,来完成相应的功能。

下面我们来对容器运行时接口CRI来做一下介绍与分析。

在本文中,会对CRI是什么、为什么要有CRICRI系统架构做一下介绍,以及k8sCRI进行相关操作的流程分析,包括了pod创建、删除等操作。

CRI是什么

CRI是Container Runtime Interface(容器运行时接口)的简写。

CRI解耦了kubelet与容器运行时,让kubelet无需重新编译就可以支持多种容器运行时。

kubelet将通过CRI接口来跟第三方容器运行时进行通信,来操作容器与镜像。

实现了 CRI 接口的容器运行时通常称为 CRI shim, 这是一个 gRPC Server,监听在本地的 unix socket 上;而 kubelet 作为 gRPC 的客户端来调用 CRI 接口,来进行Pod 和容器、镜像的生命周期管理。另外,容器运行时需要自己负责管理容器的网络,推荐使用 CNI。

在这里插入图片描述

图1:CRI shim通信图

提出了CRI标准以后,意味着在新的版本里需要使用新的连接方式与docker通信,为了兼容以前的版本,k8s提供了针对docker的CRI实现,也就是kubelet包下的dockershim包,dockershim是一个grpc服务,监听一个端口供kubelet连接,dockershim收到kubelet的请求后,将其转化为REST API请求,再发送给docker daemon

在这里插入图片描述

图2:dockershim通信图

为什么要有CRI

在1.5以前的版本中,k8s依赖于docker,为了支持不同的容器运行时,如rktcontainerd等,kubelet从1.5开始加入了CRI标准,它将 Kubelet 与容器运行时解耦,将原来完全面向 Pod 级别的内部接口拆分成面向 SandboxContainer的 gRPC 接口,并将镜像管理和容器管理分离到不同的服务,方便后续其他容器运行时与k8s对接。

Kubernetes中的容器运行时组成

按照不同的功能可以分为四个部分:
(1)kubelet 中容器运行时的管理,kubeGenericRuntimeManager,它管理与CRI shim通信的客户端,完成容器和镜像的管理(代码位置:pkg/kubelet/kuberuntime/kuberuntime_manager.go);
(2)容器运行时接口CRI,包括了容器运行时客户端接口与容器运行时服务端接口;
(3)CRI shim客户端,kubelet持有,用于与CRI shim服务端进行通信;
(4)CRI shim服务端,即具体的容器运行时实现,包括 kubelet 内置的 dockershim(代码位置:pkg/kubelet/dockershim)以及外部的容器运行时如 cri-containerd(用于支持容器引擎containerd)、rktlet(用于支持容器引擎rkt)等。

CRI架构图

在 CRI 之下,包括两种类型的容器运行时的实现:
(1)kubelet内置的 dockershim,实现了 Docker 容器引擎的支持以及 CNI 网络插件(包括 kubenet)的支持。dockershim代码内置于kubelet,被kubelet调用,让dockershim起独立的server来建立CRI shim,向kubelet暴露grpc server;
(2)外部的容器运行时,用来支持 rktcontainerd等容器引擎的外部容器运行时。

在这里插入图片描述

kubelet中CRI相关的源码分析

kubelet的CRI源码分析包括如下几部分:
(1)kubelet CRI相关启动参数分析;
(2)kubelet CRI相关interface/struct分析;
(3)kubelet CRI初始化分析;
(4)kubelet调用CRI创建pod分析;
(5)kubelet调用CRI删除pod分析。

因篇幅原因,本篇博文先对前三部分做分析,下一篇博文再对CRI创建pod以及CRI删除pod做分析。

基于tag v1.17.4

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

1.kubelet组件CRI相关启动参数分析

kubelet组件CRI相关启动参数相关代码如下:

// pkg/kubelet/config/flags.go
// AddFlags adds flags to the container runtime, according to ContainerRuntimeOptions.
func (s *ContainerRuntimeOptions) AddFlags(fs *pflag.FlagSet) {
	dockerOnlyWarning := "This docker-specific flag only works when container-runtime is set to docker."

	// General settings.
	fs.StringVar(&s.ContainerRuntime, "container-runtime", s.ContainerRuntime, "The container runtime to use. Possible values: 'docker', 'remote', 'rkt (deprecated)'.")
	fs.StringVar(&s.RuntimeCgroups, "runtime-cgroups", s.RuntimeCgroups, "Optional absolute name of cgroups to create and run the runtime in.")
	fs.BoolVar(&s.RedirectContainerStreaming, "redirect-container-streaming", s.RedirectContainerStreaming, "Enables container streaming redirect. If false, kubelet will proxy container streaming data between apiserver and container runtime; if true, kubelet will return an http redirect to apiserver, and apiserver will access container runtime directly. The proxy approach is more secure, but introduces some overhead. The redirect approach is more performant, but less secure because the connection between apiserver and container runtime may not be authenticated.")

	// Docker-specific settings.
	fs.BoolVar(&s.ExperimentalDockershim, "experimental-dockershim", s.ExperimentalDockershim, "Enable dockershim only mode. In this mode, kubelet will only start dockershim without any other functionalities. This flag only serves test purpose, please do not use it unless you are conscious of what you are doing. [default=false]")
	fs.MarkHidden("experimental-dockershim")
	fs.StringVar(&s.DockershimRootDirectory, "experimental-dockershim-root-directory", s.DockershimRootDirectory, "Path to the dockershim root directory.")
	fs.MarkHidden("experimental-dockershim-root-directory")
	fs.StringVar(&s.PodSandboxImage, "pod-infra-container-image", s.PodSandboxImage, fmt.Sprintf("The image whose network/ipc namespaces containers in each pod will use. %s", dockerOnlyWarning))
	fs.StringVar(&s.DockerEndpoint, "docker-endpoint", s.DockerEndpoint, fmt.Sprintf("Use this for the docker endpoint to communicate with. %s", dockerOnlyWarning))
	fs.DurationVar(&s.ImagePullProgressDeadline.Duration, "image-pull-progress-deadline", s.ImagePullProgressDeadline.Duration, fmt.Sprintf("If no pulling progress is made before this deadline, the image pulling will be cancelled. %s", dockerOnlyWarning))
	...
}
// cmd/kubelet/app/options/options.go
// AddFlags adds flags for a specific KubeletFlags to the specified FlagSet
func (f *KubeletFlags) AddFlags(mainfs *pflag.FlagSet) {
    ...
    fs.StringVar(&f.RemoteRuntimeEndpoint, "container-runtime-endpoint", f.RemoteRuntimeEndpoint, "[Experimental] The endpoint of remote runtime service. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows.  Examples:'unix:///var/run/dockershim.sock', 'npipe:./pipe/dockershim'")
	fs.StringVar(&f.RemoteImageEndpoint, "image-service-endpoint", f.RemoteImageEndpoint, "[Experimental] The endpoint of remote image service. If not specified, it will be the same with container-runtime-endpoint by default. Currently unix socket endpoint is supported on Linux, while npipe and tcp endpoints are supported on windows.  Examples:'unix:///var/run/dockershim.sock', 'npipe:./pipe/dockershim'")
	...
}

kubelet组件启动参数的默认值在NewKubeletFlags函数中设置。

// cmd/kubelet/app/options/options.go
// NewKubeletFlags will create a new KubeletFlags with default values
func NewKubeletFlags() *KubeletFlags {
	remoteRuntimeEndpoint := ""
	if runtime.GOOS == "linux" {
		remoteRuntimeEndpoint = "unix:///var/run/dockershim.sock"
	} else if runtime.GOOS == "windows" {
		remoteRuntimeEndpoint = "npipe:./pipe/dockershim"
	}

	return &KubeletFlags{
		EnableServer:                        true,
		ContainerRuntimeOptions:             *NewContainerRuntimeOptions(),
		CertDirectory:                       "/var/lib/kubelet/pki",
		RootDirectory:                       defaultRootDir,
		MasterServiceNamespace:              metav1.NamespaceDefault,
		MaxContainerCount:                   -1,
		MaxPerPodContainerCount:             1,
		MinimumGCAge:                        metav1.Duration{Duration: 0},
		NonMasqueradeCIDR:                   "10.0.0.0/8",
		RegisterSchedulable:                 true,
		ExperimentalKernelMemcgNotification: false,
		RemoteRuntimeEndpoint:               remoteRuntimeEndpoint,
		NodeLabels:                          make(map[string]string),
		VolumePluginDir:                     "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/",
		RegisterNode:                        true,
		SeccompProfileRoot:                  filepath.Join(defaultRootDir, "seccomp"),
		// prior to the introduction of this flag, there was a hardcoded cap of 50 images
		NodeStatusMaxImages:         50,
		EnableCAdvisorJSONEndpoints: true,
	}
}

CRI相关启动参数的默认值在NewContainerRuntimeOptionsNewMainKubelet函数中设置。

// 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/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值