专栏首页01ZOO扩展 Kubernetes 之 CRI
原创

扩展 Kubernetes 之 CRI

简介

CRI 是什么

  • 容器运行时插件(Container Runtime Interface,简称 CRI)是 Kubernetes v1.5 引入的容器运行时接口,它将 Kubelet 与容器运行时解耦,将原来完全面向 Pod 级别的内部接口拆分成面向 Sandbox 和 Container 的 gRPC 接口,并将镜像管理和容器管理分离到不同的服务。
  • CRI 主要定义了两个 grpc interface.
    • RuntimeService:容器(container) 和 (Pod)Sandbox 运行时管理
    • ImageService:拉取、查看、和移除镜像
  • OCI (开放容器标准): 定义了 ImageSpec(镜像格式, 比如文件夹结构,压缩方式)和 RuntimeSpec(如何运行,比如支持 create, start, stop, delete)
    • 代表实现有:runC,Kata(以及它的前身 runV 和 Clear Containers),gVisor
  • CRI 区别于 OCI,CRI的定义比较简单直接,只是定义了一套协议(grpc 接口)。
    • 代表实现有 kubernetest 内置的 dockershim, CRI-containerd(或者 containerd with CRI plugin), cri-o

CRI 位于什么位置

在 kubernetes 中:

image
image

在和OCI,调度层的角度看:

graph LR
OrchestrationAPI --> ContainerAPI-criRuntime
ContainerAPI-criRuntime --> KernelAPI-ociRuntime

CRI/CRI Runtime

CRI Runtime 的执行流程

经典的 kubernetes runtime 执行流程

image
  • 执行流程里面核心组件是 kubelet/KubeGenericRuntimeManager 他调用很多其他组件,比如 cm (ContainerManager/podContainerManager/cgroupManager/cpuManager/deviceManager, pod 级别的资源管理), RuntimeService (grpc 调用 CRI 的客户端) 共同完成 SyncPod 的操作。

经典的 dockershim -> containerd 的流程 (称为 docker cri)

image
  1. Kubelet 通过 CRI 接口(gRPC)调用 dockershim,请求创建一个容器。CRI 即容器运行时接口(Container Runtime Interface),这一步中,Kubelet 可以视作一个简单的 CRI Client,而 dockershim 就是接收请求的 Server。目前 dockershim 的代码其实是内嵌在 Kubelet 中的,所以接收调用的凑巧就是 Kubelet 进程
  2. dockershim 收到请求后,转化成 Docker Daemon 能听懂的请求,发到 Docker Daemon 上请求创建一个容器。
  3. Docker Daemon 早在 1.12 版本中就已经将针对容器的操作移到另一个守护进程——containerd 中了,因此 Docker Daemon 仍然不能帮我们创建容器,而是要请求 containerd 创建一个容器;
  4. containerd 收到请求后,并不会自己直接去操作容器,而是创建一个叫做 containerd-shim 的进程,让 containerd-shim 去操作容器。这是因为容器进程需要一个父进程来做诸如收集状态,维持 stdin 等 fd 打开等工作。而假如这个父进程就是 containerd,那每次 containerd 挂掉或升级,整个宿主机上所有的容器都得退出了。而引入了 containerd-shim 就规避了这个问题(containerd 和 shim 并不是父子进程关系);
  5. 我们知道创建容器需要做一些设置 namespaces 和 cgroups,挂载 root filesystem 等等操作,而这些事该怎么做已经有了公开的规范了,那就是 OCI(Open Container Initiative,开放容器标准)。它的一个参考实现叫做 runC。于是,containerd-shim 在这一步需要调用 runC 这个命令行工具,来启动容器;
  6. runC 启动完容器后本身会直接退出,containerd-shim 则会成为容器进程的父进程,负责收集容器进程的状态,上报给 containerd,并在容器中 pid 为 1 的进程退出后接管容器中的子进程进行清理,确保不会出现僵尸进程。

直接对接 cri-containerd/cri-o 的运行时

image
image

使用 cri-containerd 的调用流程更为简洁, 省去了上面的调用流程的 1,2 两步

常见 CRI runtime 实现

image

Cri-containerd

image

执行流程为:

  1. Kubelet 通过 CRI runtime service API 调用 cri plugin 创建 pod
  2. cri 通过 CNI 创建 pod 的网络配置和 namespace
  3. cri 使用 containerd 创建并启动 pause container (sandbox container) 并且把这个 container 置于 pod 的 cgroups/namespace
  4. Kubelet 接着通过 CRI image service API 调用 cri plugin, 获取容器镜像
  5. cri 通过 containerd 获取容器镜像
  6. Kubelet 通过 CRI runtime service API 调用 cri, 在 pod 的空间使用拉取的镜像启动容器
  7. cri 通过 containerd 创建/启动 应用容器, 并且把 container 置于 pod 的 cgroups/namespace. Pod 完成启动.

实践

准备集群

使用 terraform 在腾讯云上创建 tke 测试集群

# Configure the TencentCloud Provider
provider "tencentcloud" {
  secret_id  = var.secret_id
  secret_key = var.secret_key
  region     = var.region
}

# test cluster
resource "tencentcloud_kubernetes_cluster" "managed_cluster" {
  vpc_id                  = var.vpc
  cluster_cidr            = "10.4.0.0/16"
  cluster_max_pod_num     = 32
  cluster_name            = "test"
  cluster_desc            = "test cluster desc"
  cluster_max_service_num = 32
  container_runtime          = "containerd"
  cluster_version            = "1.14.3"

  worker_config {
    count                      = 2
    availability_zone          = var.availability_zone
    instance_type              = var.default_instance_type
    system_disk_size           = 50
    security_group_ids         = [var.sg]
    internet_charge_type       = "TRAFFIC_POSTPAID_BY_HOUR"
    internet_max_bandwidth_out = 100
    public_ip_assigned         = true
    subnet_id                  = var.subnet
    enhanced_security_service = false
    enhanced_monitor_service  = false
    key_ids                   = [var.key_id]
  }

  cluster_deploy_type = "MANAGED_CLUSTER"
}

用 bash 实现一个 CRI runtime

CRI runtime 的实现需要实现大量 API,这里我们做一个简单的 shell 脚本,将请求转发给 runc,同时打印出调用的参数。把这个脚本命名为 runb

$ cat /usr/local/bin/runb
#!/bin/bash -e
echo "["`date --iso-8601=seconds`"] call runb: $@" >> /var/log/runb.log
exec runc $@

使用 ctr/crictl 测试

ctr 是调用containerd 的命令行工具,而 crictl 是调用 cri 相关 api 的工具,一个测试的例子 参考这里

配置 containerd, 使用 k8s yaml 测试

在 /etc/containerd/config.toml 下面添加如下的配置,配置 runtime 为 runb,二进制程序为 runb. containerd 的配置因版本变化有所不同,具体可以参考这里。重启 containerd

      [plugins.cri.containerd.runtimes.runb]
         runtime_type = "io.containerd.runc.v1"
         [plugins.cri.containerd.runtimes.runb.options]
           NoPivotRoot = false
           NoNewKeyring = false
           ShimCgroup = ""
           IoUid = 0
           IoGid = 0
           BinaryName = "runb"
           Root = ""
           CriuPath = ""
           SystemdCgroup = false

用 kubectl 把名为 runb 的 runtimeclass 创建出来

apiVersion: node.k8s.io/v1beta1  # RuntimeClass is defined in the node.k8s.io API group
kind: RuntimeClass
metadata:
  name: runb  # The name the RuntimeClass will be referenced by
  # RuntimeClass is a non-namespaced resource
handler: runb  # The name of the corresponding CRI configuration

创建一个使用 runb 为runtime 的pod

root@VM-8-12-ubuntu:~# cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  runtimeClassName: runb
  containers:
    - image: nginx
      name: nginx
      ports:
        - containerPort: 80
          name: http

观察创建结果和 runb 的输出日志

root@VM-8-12-ubuntu:~# crictl ps
CONTAINER ID        IMAGE               CREATED             STATE               NAME                ATTEMPT             POD ID
d0e454f31ad06       2073e0bcb60ee       11 minutes ago      Running             nginx               0                   f640723d57cc2

root@VM-8-12-ubuntu:~# head /var/log/runb.log
starting with runb -namespace default -address /run/containerd/containerd.sock -publish-binary /usr/local/bin/containerd -id hello -debug start
starting with runb: --root /run/containerd/runc/k8s.io --log /run/containerd/io.containerd.runtime.v2.task/k8s.io/5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac/log.json --log-format json create --bundle /run/containerd/io.containerd.runtime.v2.task/k8s.io/5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac --pid-file /run/containerd/io.containerd.runtime.v2.task/k8s.io/5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac/init.pid 5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac
starting with runb: --root /run/containerd/runc/k8s.io --log /run/containerd/io.containerd.runtime.v2.task/k8s.io/5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac/log.json --log-format json state 5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac
starting with runb: --root /run/containerd/runc/k8s.io --log /run/containerd/io.containerd.runtime.v2.task/k8s.io/5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac/log.json --log-format json start 5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac
starting with runb: --root /run/containerd/runc/k8s.io --log /run/containerd/io.containerd.runtime.v2.task/k8s.io/5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac/log.json --log-format json state 5dd814edd58826c3ebcfa87ae96bb972b1541d6007f7f7ed5c01a4da639b0fac

参考

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

登录 后参与评论
0 条评论

相关文章

  • 容器堆栈须知的八个要素

    随着容器发展模式逐渐成为主流,容器堆栈本身也在不断发展。现在,企业看到了容器的价值,开发和业务重点正在从引擎转移到增加更多复杂的功能,以便更直接地获得业务收益。...

    SDNLAB
  • Kubernetes-整体概述和架构

    Kubernetes是一个轻便的和可扩展的开源平台,用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中...

    菲宇
  • K8s宣布弃用Docker,千万别慌!

    近日,Kubernetes 官方发布公告,宣布自 v1.20 起放弃对 Docker 的支持,届时用户将收到 Docker 弃用警告,并需要改用其他容器运行时。

    SDNLAB
  • (闲聊)听说 K8s 要甩了 Docker 了

    今天偶然看到 Kubernetes 1.20 的 ChangeLog,其中有一行大动作:

    米开朗基杨
  • 五分钟技术小分享 - 2022Week09

    今天,我们会以OpenTelemetry的三个核心Metrics、Logs、Traces为切入点,来看看OpenMetrics、Fluentd、Jaeger这三...

    junedayday
  • Kubernetes 1.7:安全加固、有状态应用更新等

    今天我们公布了Kubernetes 1.7,这一里程碑版本引入了更为强大的安全性、存储以及扩展性因素,旨在满足Kubernetes在广泛企业环境下所面临的实际需...

    Debian中国
  • 定了!dockershim 的代码将在 K8s v1.24 正式删除

    目前已经确定, dockershim 的代码将在 Kubernetes v1.24 版本中被正式从 Kubernetes 的代码仓库移除,预计新版本明年 4 月...

    Jintao Zhang
  • Kubernetes 1.7 发布,安全强化、StatefulSet 更新及可扩展特性

    Kubernetes 1.7已经发布,该版本聚焦于安全、存储和扩展性等交付特性,其中包括Network Policy API、StatefulSets自动升级策...

    Debian中国
  • 为什么Kubernetes要引入pod的概念,而不直接操作Docker容器

    首先我们要明确一个概念,Kubernetes并不是只支持Docker这一个容器运行时,通过我的另一篇文章什么是Kubernetes的CRI-容器运行时接口介绍的...

    Jerry Wang
  • K8S 生态周报| containerd v1.6 正式发布,带来众多新特性

    containerd v1.6 在本周也正式发布了,这是 containerd 的第 7 个大版本。距离上一个大的正式版 v1.5.0 已经过了将近 9 个月的...

    Jintao Zhang
  • (译)Kubernetes Containerd 集成进入 GA 阶段

    在之前的博客(Containerd Brings More Container Runtime Options for Kubernetes)中,我们介绍了 K...

    崔秀龙
  • kubernetes真要放弃docker吗?

    这几天,kubernetes社区发生了一件大事,1.20版本宣布放弃docker,圈内一下子炸锅了。我们看一下官方描述:

    jinjunzhu
  • 我到底应该使用哪个 CRI 替换 kubernetes 集群的 Docker?

    前一段时间 kubernetes 对 docker 的弃用引起了不小的讨论,但其实 docker 并不是 kubernetes 中的 CRI 唯一实现。那么除了...

    CNCF
  • CNCF欢迎CRI-O加入孵化项目 - Kubernetes的轻量级容器运行时

    今天,CNCF(Cloud Native Computing Foundation,云原生计算基金会)技术监督委员会(TOC)投票决定接受CRI-O作为孵化级托...

    CNCF
  • Kubernetes决定弃用Docker,到底会影响到谁?

    近几年,Kubernetes 已经成为自有机房、云上广泛使用的容器编排方案,最广泛的使用方式是 Kubernetes+Docker。从 DevOps 人员的角度...

    xcbeyond
  • Kubernetes正式支持Containerd 1.1版

    SDNLAB
  • CRI-RM 助力浪潮AIStation提升云原生工作负载性能

    在 KubeCon + CloudNativeCon + Open Source Summit China2021 大会上, 英特尔®有多场技术分享,这里要给大...

    CNCF
  • virtlet是什么?virtlet如何管理虚拟机?

    随着Docker和Kubernetes生态圈的发展,云计算领域对容器的兴趣达到了狂热的程度。容器技术为应用程序提供了隔离的运行空间,每个容器内都包含一个独享的完...

    谐云

扫码关注云+社区

领取腾讯云代金券