首页 > 其他分享 >kubernets启动容器过程分析

kubernets启动容器过程分析

时间:2023-10-21 22:01:15浏览次数:32  
标签:容器 启动 containerd kubernets returns rpc Docker CRI

1. 背景

对于大数据组件,经常需要进行扩缩容的服务,例如Yarn nodemanager、Alluxio Worker。往往需要频繁的人工操作上线下线,非常繁琐,耗费较高的人力成本。

为了降低这种人工操作的成本,可以考虑将这些服务部署到kubernets中进行管理。本文通过介绍kubernets启动容器的过程,介绍期间经历的所有组件,帮助提升对kubernets的认知。

2. kubernets架构

Untitled.png

一个kubernetes集群主要是由控制节点(master)、工作节点(node)构成,每个节点上都会安装不同的组件。

master:集群的控制平面,负责集群的决策 ( 管理 )

ApiServer : 资源操作的唯一入口,接收用户输入的命令,提供认证、授权、API注册和发现等机制

Scheduler : 负责集群资源调度,按照预定的调度策略将Pod调度到相应的node节点上

ControllerManager : 负责维护集群的状态,比如程序部署安排、故障检测、自动扩展、滚动更新等

Etcd :负责存储集群中各种资源对象的信息

node:集群的数据平面,负责为容器提供运行环境 ( 干活 )

Kubelet : 负责维护容器的生命周期,即通过控制docker,来创建、更新、销毁容器

KubeProxy : 负责提供集群内部的服务发现和负载均衡

Docker : 负责节点上容器的各种操作

下面,以部署一个nginx服务来说明kubernetes系统各个组件调用关系:

  1. 首先要明确,一旦kubernetes环境启动之后,master和node都会将自身的信息存储到etcd数据库中。
  2. 一个nginx服务的安装请求会首先被发送到master节点的apiServer组件。
  3. apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上。在此时,它会从etcd中读取各个node节点的信息,然后按照一定的算法进行选择,并将结果告知apiServer。
  4. apiServer调用controller-manager去调度Node节点安装nginx服务。
  5. kubelet接收到指令后,会通知docker,然后由docker来启动一个nginx的pod。 pod是kubernetes的最小操作单元,容器必须跑在pod中至此。
  6. 一个nginx服务就运行了,如果需要访问nginx,就需要通过kube-proxy来对pod产生访问的代理。

这样,外界用户就可以访问集群中的nginx服务了。

3. k8s启动容器流程

kuberlet组件负责创建、更新、销毁容器。调用过程如下所示:

Untitled 1.png

3.1 调用CRI接口访问dockershim

在CRI诞生之前,架构没那么复杂,当时kubelet是能直接操作docker daemon的(kubelet --> docker)。但后来出现了rkt容器运行时,k8s又去主动对接rkt,随着容器运行时逐渐发展,k8s开发人员意识到容器运行时会越来越多,如果为每个都做开发对接,工作量太大、难以维护。于是就定义了统一的接口CRI。

CRI:Container Runtime Interface(容器运行时接口),是k8s抽象出来的一种标准协议,基于grpc+protocol buffer,规范了容器的上层基本行为,因此也称为high-level运行时(相对应的是low-level,即OCI)。CRI 基于 gRPC 定义了 RuntimeService 和 ImageService 等两个 gRPC 服务,分别用于容器运行时和镜像的管理。其接口如下所示:

RuntimeService接口负责管理容器:

service RuntimeService {
    rpc Version(VersionRequest) returns (VersionResponse) {}
    rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {}
    rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {}
    rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}
    rpc PodSandboxStatus(PodSandboxStatusRequest) returns (PodSandboxStatusResponse) {}
    rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse) {}
    rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse) {}
    rpc StopContainer(StopContainerRequest) returns (StopContainerResponse) {}
    rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse) {}
    rpc ListContainers(ListContainersRequest) returns (ListContainersResponse) {}
    rpc ContainerStatus(ContainerStatusRequest) returns (ContainerStatusResponse) {}
    rpc UpdateContainerResources(UpdateContainerResourcesRequest) returns (UpdateContainerResourcesResponse) {}
    rpc ExecSync(ExecSyncRequest) returns (ExecSyncResponse) {}
    rpc Exec(ExecRequest) returns (ExecResponse) {}
    //省略
}

ImageService负责管理镜像:

service ImageService {
    rpc ListImages(ListImagesRequest) returns (ListImagesResponse) {}
    rpc ImageStatus(ImageStatusRequest) returns (ImageStatusResponse) {}
    rpc PullImage(PullImageRequest) returns (PullImageResponse) {}
    rpc RemoveImage(RemoveImageRequest) returns (RemoveImageResponse) {}
    rpc ImageFsInfo(ImageFsInfoRequest) returns (ImageFsInfoResponse) {}
}

dockershim:

早期kubernetes版本,只支持docker engine一种特定的container runtime, docker engine本身并没有支持CRI接口规范,所以kubernetes project中包含了特定的代码来做这种转化,使得dockershim代码变成了kubernetes中kuberlet组件的一部分。

CRI规范推进以及kubernetes自身的发展:随着kubernetes发展,维护dockershim模块变成了一种巨大的负担。未来随着newer CRI runtime中将会引入以及cgroups v2以及user namespaces等新特性的支持,涉及到大量dockershim的兼容工作要做,移除dockershim对于未来推动CRI发展至关重要。

3.2 dockershim调用docker daemon

dockershim 收到请求后, 转化成 Docker Daemon 能识别的请求, 发到 Docker Daemon 上请求创建一个容器,请求到了 Docker Daemon 后续就是 Docker 创建容器的流程了。Docker Daemon架构图如下所示:

Untitled 2.png

Docker Daemon是Docker架构中运行在后台的守护进程,大致可以分为Docker Server、Engine和Job三部分。

Docker Daemon可以认为是通过Docker Server模块接受Docker Client的请求,并在Engine中处理请求,然后根据请求类型,创建出指定的Job并运行。运行过程的作用有以下几种可能:

  • 向Docker Registry获取镜像。
  • 通过graphdriver执行容器镜像的本地化操作。
  • 通过networkdriver执行容器网络环境的配置。
  • 通过execdriver执行容器内部运行的执行工作等。

3.3 Docker Engine调用containerd

Untitled 3.png

containerd 组件是从 Docker 1.11 版本正式从 dockerd 中剥离出来的,它的诞生完全遵循 OCI 标准,是容器标准化后的产物。containerd 完全遵循了 OCI 标准,并且是完全社区化运营的,因此被容器界广泛采用。

containerd 不仅负责容器生命周期的管理,同时还负责一些其他的功能:

  • 镜像的管理,例如容器运行前从镜像仓库拉取镜像到本地;
  • 接收 dockerd 的请求,通过适当的参数调用 runc 启动容器;
  • 管理存储相关资源;
  • 管理网络相关资源。

containerd 包含一个后台常驻进程,默认的 socket 路径为 /run/containerd/containerd.sock,dockerd 通过 UNIX 套接字向 containerd 发送请求,containerd 接收到请求后负责执行相关的动作并把执行结果返回给 dockerd。

如果你不想使用 dockerd,也可以直接使用 containerd 来管理容器,由于 containerd 更加简单和轻量,生产环境中越来越多的人开始直接使用 containerd 来管理容器。

3.4 containerd启动containerd-shim进程

containerd-shim 的意思是垫片,类似于拧螺丝时夹在螺丝和螺母之间的垫片。containerd-shim 的主要作用是将 containerd 和真正的容器进程解耦,使用 containerd-shim 作为容器进程的父进程,从而实现重启 containerd 不影响已经启动的容器进程。

shim 将 Containerd 进程从容器的生命周期中分离出来,具体的做法是 runc 在创建和运行容器之后退出,并将 shim 作为容器的父进程,即使 Containerd 进程挂掉或者重启,也不会对容器造成任何影响。这样做的好处很明显,你可以高枕无忧地升级或者重启 Containerd,不会对运行中的容器产生任何影响。

3.5 container-shim调用runC启动容器

在2015年前,都是以 docker 作为标准创建容器,那么 docker 接口的变化将导致社区中所有相关工具都要更新,不然就无法使用;如果没有标准,这将导致容器实现的碎片化,出现大量的冲突和冗余。这两种情况都是社区不愿意看到的事情,OCI(Open Container Initiative) 就是在这个背景下出现的,它的使命就是推动容器标准化,容器能运行在任何的硬件和系统上,相关的组件也不必绑定在任何的容器运行时上。

RunC 是从 Docker 的 libcontainer 中迁移而来的,实现了容器启停、资源隔离等功能。Docker将RunC捐赠给 OCI 作为OCI 容器运行时标准的参考实现。通过执行RunC命令就可以启动容器。

4. k8s容器运行时架构总结

除了通过docker的方式管理容器。还可以直接调用cri-containerd和cri-o管理容器:

Untitled 4.png

cri-containerd:

cri-containerd和cri-o实现了CRI接口,cri-containerd包含在containerd组件中。通过Kubelet直接调用containerd可直接创建容器。

cri-o:

CRI-O 全称为 "Container Runtime Interface - OpenShift",CRI-O对CRI和OCI的实现非常严格,为k8s的推荐的实现方式,例如,podman就实现了cri-o。cri-o架构如下:

Untitled 5.png

标签:容器,启动,containerd,kubernets,returns,rpc,Docker,CRI
From: https://blog.51cto.com/u_15327484/7969816

相关文章

  • linux启动常见问题
    一、忘记root密码日常生活中,我们会接触到很多账号和密码,而这些账号和密码我们不能都很好的记忆,对于linux也是一样的,如果root密码忘记了怎么办?岂不是都无法登陆使用Linux了?现在我就教各位,在不知道root密码的前提下,如何给root设置一个新的密码step1重启你的linux系统,在下图这个......
  • CentOS 8启动流程
    一、BIOS与UEFIBIOSBasicInputOutputSystem的缩写,翻译过来就是“基本输入输出系统”,是一种业界标准的固件接口,第一次出现在1975年,是计算机启动时加载的第一个程序,主要功能是检测和设置计算机硬件,引导系统启动。UEFIUnifiedExtensibleFirmwareinterface的缩写,翻译过来为......
  • Docker启动失败,报错Cannot connect to the Docker daemon at unix:///var/run/docker
    问题描述:CannotconnecttotheDockerdaemonatunix:///var/run/docker.sock.Isthedockerdaemonrunning?首次安装docker后,服务没有自启动解决方案:查看docker状态 1servicedockerstatus 设置开启Linux时docker自启动 1systemctlenabledocker   然后......
  • Docker启动报错:Cannot connect to the Docker daemon at unix:///var/run/docker.sock
    问题描述:  Docker启动报错:CannotconnecttotheDockerdaemonatunix:///var/run/docker.sock.Isthedockerdaemonrunning?  CannotconnecttotheDockerdaemonatunix:///var/run/docker.sock.Isthedockerdaemonrunning?输入dockerps命令无法显示服......
  • docker cp 命令 - 宿主机与容器互相拷贝文件
    一、从容器拷贝文件到宿主机命令格式:$dockercp<containder-id>:/path/host/path例子:$dockercpc9b7f17d43e9:/opt/hello.txt/home/hello.txt二、从宿主机拷贝文件到容器命令格式:$dockercp/host/path<containder-id>:/path例子:$dockercp/home/hel......
  • PMP开工会议和启动会议的区别
    项目启动会议(ProjectInitiatingMeeting):项目启动阶段结束时进行。项目开工会议(ProjectKick-offMeeting):项目管理计划完成后,项目具体工作实施之前进行。 一般PMP考试都是考开工会议,但是有时题目会把开工会翻译成启动会,所以需要留意英文翻译。 ......
  • 深入理解 Docker:探索容器技术的核心概念
    在工作中,我们掌握了微服务的服务注册与发现(nacos)、配置中心(nacos)、远程服务调用(feign)、网关(gateway),同时借助Idea编译工具多次完成本地服务启动、部署和验证。但是我们假想下面场景:开发人员A写好的代码-->开发人员小王的电脑上运行,小周必须保证跟小王一样的系统环境(JDK/MyS......
  • 关于tomcat容器抛出的异常解决方案之一
    1,描述问题类型:调试信息泄露如:现要求:前端页面不显示调试信息。解决方案:替换默认的tomcat<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><e......
  • sonarqube启动报错:You must address the points described in the following [2] line
    Youmustaddressthepointsdescribedinthefollowing[2]linesbeforestartingElasticsearch.bootstrapcheckfailure[1]of[2]:maxnumberofthreads[3870]foruser[sonar]istoolow,increasetoatleast[4096]bootstrapcheckfailure[2]of[2]:maxvi......
  • Centos断电后启动失败
    Centos断电后启动失败公司服务器断电,发现服务器启动失败,打开RemoteConsole,查看发现系统进入了救援模式,页面显示内容如下:Welcometoemergencymode!Afterloggingin,type"journalctl-xb"toviewsystemlogs,"systemctlreboot"toreboot,"systemctldefault"or^Dt......