热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Kubernetes弃用Docker,一文看懂Container到底怎么用

01需求简介注:Containerruntime统称为容器运行时在Docker时代,关于容器运行时术语的定义是非常明确的,其为运行和管理容器的软件。但随着Docker涵盖的内容日益

01 需求简介

注: Container runtime 统称为容器运行时

在 Docker 时代,关于容器运行时术语的定义是非常明确的,其为运行和管理容器的软件。但随着 Docker 涵盖的内容日益增多,以及多种容器编排工具的引入,该定义变得日益模糊了。

当你运行一个 Docker 容器时,一般的步骤是:

  • 下载镜像

  • 将镜像解压成一个 bundle,即将各层文件平铺到一个单一的文件系统中。

  • 运行容器

最初的规范规定,只有运行容器的部分定义为容器运行时,但一般用户,将上述三个步骤都默认为容器运行时所必须的能力,从而让容器运行时的定义成为一个令人困惑的话题。

当人们想到容器运行时,可能会想到一连串的相关概念;runc、runv、lxc、lmctfy、Docker(containerd)、rkt、cri-o。每一个都是基于不同的场景而实现的,均实现了不同的功能。如containerd和cri-o,实际均可使用runc来运行容器,但其实现了如镜像管理、容器API等功能,可以将这些看作是比runc具备的更高级的功能。

可以发现,容器运行时是相当复杂的。每个运行时都涵盖了从低级到高级的不同部分,如下图所示。

根据功能范围划分,将其分为低级容器运行时 (Low level Container Runtime)和高级容器运行时 (High level Container Runtime),其中只关注容器的本身运行通常称为低级容器运行时(Low level Container Runtime)。支持更多高级功能的运行时,如镜像管理及一些gRPC/Web APIs,通常被称为 高级容器运行时 (High level Container Runtime)。需要注意的是,低级运行时和高级运行时有本质区别,各自解决的问题也不同。

02 低级容器运行时

低级运行时的功能有限,通常执行运行容器的低级任务。大多数开发者日常工作中不会使用到。其一般指按照 OCI 规范、能够接收可运行 roofs 文件系统和配置文件并运行隔离进程的实现。这种运行时只负责将进程运行在相对隔离的资源空间里,不提供存储实现和网络实现。但是其他实现可以在系统中预设好相关资源,低级容器运行时可通过 config.json 声明加载对应资源。低级运行时的特点是底层、轻量,限制也很一目了然:
  • 只认识 rootfs 和 config.json,没有其他镜像能力

  • 不提供网络实现

  • 不提供持久实现

  • 无法跨平台等

低级运行时 demo

通过以 root 方式使用 Linux cgcreate、cgset、cgexec、chroot 和 unshare 命令来实现简单容器。
首先,以 busybox 容器镜像作为基础,设置一个根文件系统。然后,创建一个临时目录,并将 busybox 解压到该目录中。

$ CID=$(docker create busybox)$ ROOTFS=$(mktemp -d)$ docker export $CID | tar -xf - -C $ROOTFS

紧接着创建 uuid,并对内存和 CPU 设置限制。内存限制是以字节为单位设置的。在这里,将内存限制设置为 100MB。

$ UUID=$(uuidgen)$ cgcreate -g cpu,memory:$UUID$ cgset -r memory.limit_in_bytes=100000000 $UUID$ cgset -r cpu.shares=512 $UUID

例如,如果我们想把我们的容器限制在两个 cpu core 上,可以设定一秒钟的周期和两秒钟的配额(1s=1,000,000us),这将允许进程在一秒钟的时间内使用两个cpu core。

$ cgset -r cpu.cfs_period_us=1000000 $UUID$ cgset -r cpu.cfs_quota_us=2000000 $UUID

接下来在容器中执行命令。

$ cgexec -g cpu,memory:$UUID \> unshare -uinpUrf --mount-proc \> sh -c "/bin/hostname $UUID && chroot $ROOTFS /bin/sh"/ # echo "Hello from in a container"Hello from in a container/ # exit

最后,删除前面创建的 cgroup 和临时目录。

$ cgdelete -r -g cpu,memory:$UUID$ rm -r $ROOTFS

低级运行时demo

为了更好地理解低级容器运行时,以下列举了几个低级运行时代表,各自实现了不同的功能。

runC

runC是目前使用最广泛的容器运行时。它最初是集成在Docker的内部,后来作为一个单独的工具,并以公共库的方式提取出来。

在2015 年,在 Linux 基金会的支持下有了 Open Container Initiative (OCI)(就是负责制定容器标准的组织),Docker 将自己容器格式和运行时 runC 捐给了 OCI。OCI 在此基础上制定了 2 个标准:运行时标准 Runtime Specification (runtime-spec) 和 镜像标准 Image Specification (image-spec) ,下面通过示例,简要介绍一下 runC。

首先创建根文件系统。这里我们将再次使用 busybox。

$ mkdir rootfs$ docker export $(docker create busybox) | tar -xf - -C rootfs

接下来创建一个 config.json 文件

$ runc spec

这个命令为容器创建一个模板config.json。

$ cat config.json{ "ociVersion": "1.0.2", "process": { "terminal": true, "user": { "uid": 0, "gid": 0 }, "args": [ "sh" ], "env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm" ], "cwd": "/", "capabilities": {...

默认情况下,它在根文件系统位于 ./rootfs 的目录下运行命令。

$ sudo runc run mycontainerid/ # echo "Hello from in a container"Hello from in a container

rkt(已废弃)

rkt是一个同时具有低级和高级功能的运行时。例如,很像Docker,rkt允许你构建容器镜像,获取和管理本地存储库中的容器镜像,并通过一个命令运行它们。

runV

runv 是 OCF 基于管理程序的(Hypervisor-based )运行时 Runtime.runV 兼容 OCF。作为虚拟容器运行时引擎的runV已被淘汰。runV团队与英特尔一起在OpenInfra Foundation中创建了Kata Containers项目

youki

Rust是时下最流行的编程语言,而容器开发也是一个时兴的应用领域。将两者结合使用Rust来做容器开发是一个值得尝鲜的体验。youki是使用Rust的实现OCI运行时规范,类似于runc。

03高级容器运行时

高级运行时负责容器镜像的传输和管理,解压镜像,并传递给低级运行时来运行容器。通常情况下,高级运行时提供一个守护程序和一个API,远程应用程序可以使用它来运行容器并监控它们,它们位于低层运行时或其他高级运行时之上。
高层运行时也会提供一些看似很低级的功能。例如,管理网络命名空间,并允许容器加入另一个容器的网络命名空间。
这里有一个类似逻辑分层图,可以帮助理解这些组件是如何结合在一起工作的。

高级运行时代表

Docker

Docker 是最早的开源容器运行时之一。它是由平台即服务的公司 dotCloud 开发的,用于在容器中运行用户的应用。
Docker 是一个容器运行时,包含了构建、打包、共享和运行容器。Docker 基于 C/S 架构实现,最初是由一个守护程序 dockerd 和 docker 客户端应用程序组成。守护程序提供了构建容器、管理镜像和运行容器的大部分逻辑,以及一些API。命令行客户端可以用来发送命令和从守护进程中获取信息。
它是第一个流行开来的运行时间,毫不过分的说,Docker 对容器的推广做出了巨大的贡献。
Docker 最初实现了高级和低级的运行时功能,但这些功能后来被分解成单独的项目,如 runc 和 containerd,以前 Docker 的架构如下图所示,现有架构中,docker-containerd 变成了 containerd,docker-runc 变成了 runc。

dockerd 提供了诸如构建镜像的功能,而 dockerd 使用 containerd 来提供诸如镜像管理和运行容器的功能。例如,Docker 的构建步骤实际上只是一些逻辑,它解释 Docker文件,使用 containerd 在容器中运行必要的命令,并将产生的容器文件系统保存为一个镜像。

Containerd

containerd 是从 Docker 中分离出来的高级运行时。containerd 实现了下载镜像、管理镜像和运行镜像中的容器。当需要运行一个容器时,它会将镜像解压到一个 OCI 运行时 bundle 中,并向 runc 发送 init 以运行它。
Containerd 还提供了 API,可以用来与它交互。containerd 的命令行客户端是 ctr 和 nerdctl。
可以通过 ctr 拉取一个容器镜像。

$ sudo ctr images pull docker.io/library/redis:latest

列出所有的镜像:

$ sudo ctr images list

运行容器:

$ sudo ctr container create docker.io/library/redis:latest redis

列出运行容器:

$ sudo ctr container list

停止容器:

$ sudo ctr container delete redis

这些命令类似于用户与 Docker 的互动方式。

rkt(已废弃)

rkt是一个同时具有低级和高级功能的运行时。例如,很像Docker,rkt允许你构建容器镜像,获取和管理本地存储库中的容器镜像,并通过一个命令运行它们。

Kubernetes CRI

CRI 在 Kubernetes 1.5 中引入,作为 kubelet 和容器运行时之间的桥梁。社区希望Kubernetes 集成的高级容器运行时实现 CRI。该运行时处理镜像的管理,支持Kubernetes pods,并管理容器,因此根据高级运行时的定义,支持 CRI 的运行时必须是一个高级运行时。低级别的运行时并不具备上述功能。
为了进一步了解 CRI,可以看看整个 Kubernetes 架构。kubelet 代表工作节点,位于Kubernetes集群的每个节点上,kubelet负责管理其节点的工作负载。当需要运行工作负载时,kubelet通过CRI与运行时进行通信。由此可以看出,CRI只是一个抽象层,允许切换不同的容器运行时。

CRI规范

CRI定义了gRPC API,该规范定义在 Kubernetes 仓库中 cri-api 目录中。CRI定义了几个远程程序调用(RPC)和消息类型。这些RPC用于管理工作负载等内容,如 “拉取镜像”(ImageService.PullImage)、”创建pod”(RuntimeService.RunPodSandbox)、”创建容器”(RuntimeService.CreateContainer)、”启动容器”(RuntimeService.StartContainer)、”停止容器”(RuntimeService.StopContainer)等操作。

例如,通过CRI启动一个新的Pod(篇幅有限,进行了一些简化工作)。RunPodSandbox和CreateContainer RPCs在其响应中返回ID,在后续请求中使用。

ImageService.PullImage({image: "image1"})ImageService.PullImage({image: "image2"})podID = RuntimeService.RunPodSandbox({name: "mypod"})id1 = RuntimeService.CreateContainer({ pod: podID, name: "container1", image: "image1",})id2 = RuntimeService.CreateContainer({ pod: podID, name: "container2", image: "image2",})RuntimeService.StartContainer({id: id1})RuntimeService.StartContainer({id: id2})

可以直接使用 crictl 工具与 CRI 运行时交互,可以用它来调试和测试CRI的相关实现。

cat <runtime-endpoint: unix:///run/containerd/containerd.sockEOF

或者通过命令行指定:

crictl --runtime-endpoint unix:///run/containerd/containerd.sock …

关于 crictl 的使用参见官网。

支持 CRI 的运行时

Containerd

containerd应该是目前最流行的CRI运行时。它以插件的方式实现CRI,默认是启用的。它默认在unix套接字上监听消息。
从1.2版本开始,它通过 runtime handler 来支持多种低级运行时。运行时处理程序是通过 CRI 中的字段传递,根据该运行时处理程序,containerd 运行 shim 的应用程序来启动容器。这可以用来运行 runc及其他的低级运行时的容器,如 gVisor、Kata Containers等。在 Kubernetes API 中通过 RuntimeClass 进行运行时配置。
下图是 Containerd 的发展史。

Docker

docker-shim 是 K8s 社区第一个被开发的,作为kubelet 和 Docker 之间的 shim。随着Docker 将其许多功能分解到 containerd 中,现在通过 containerd 支持 CRI。

当现代版本的 Docker 被安装时,containerd 也一起被安装,CRI 直接与 containerd 对话,随着docker-shim正式废弃,是时候考虑相关迁移的工作了,K8s在这方面做了大量的工作,具体可参看官方文档。

CRI-O

cri-o 是一个轻量级的 CRI 运行时,它支持 OCI,并提供镜像的管理、容器进程管理、监控日志及资源隔离等工作。

cri-o 的通信地址默认是在 /var/run/crio/crio.sock。

下图为CRI插件的演变史。

由于笔者时间、视野、认知有限,本文难免出现错误、疏漏等问题,期待各位读者朋友、业界专家指正交流。

参考文献

1.https://blog.mobyproject.org/where-are-containerds-graph-drivers-145fc9b7255
2.https://insujang.github.io/2019-10-31/container-runtime/
3.https://github.com/cri-o/cri-o

来源:本文转自公众号 DCOS,点击查看原文。

如果你运维转型处于迷茫时,8月19-20日,GOPS 2022 · 深圳站,值得你参加~

通信行业数字化转型,AIOps、MLOps、云原生、SRE等相关精彩内容,2022年最值得参加的运维大会,就在这里啦!

近期好文:

运维必知必会的 Kubectl 命令总结,收藏好了~

运维专属音乐,724运维好声音作品大赏~

“高效运维”公众号诚邀广大技术人员投稿,

投稿邮箱:jiachen@greatops.net,或添加联系人微信:greatops1118.

点个“在看”,一年不宕机


推荐阅读
  • Linux的uucico命令使用方法及工作模式介绍
    本文介绍了Linux的uucico命令的使用方法和工作模式,包括主动模式和附属模式。uucico是用来处理uucp或uux送到队列的文件传输工具,具有操作简单快捷、实用性强的特点。文章还介绍了uucico命令的参数及其说明,包括-c或--quiet、-C或--ifwork、-D或--nodetach、-e或--loop、-f或--force、-i或--stdin、-I--config、-l或--prompt等。通过本文的学习,读者可以更好地掌握Linux的uucico命令的使用方法。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了如何清除Eclipse中SVN用户的设置。首先需要查看使用的SVN接口,然后根据接口类型找到相应的目录并删除相关文件。最后使用SVN更新或提交来应用更改。 ... [详细]
  • 解决github访问慢的问题的方法集锦
    本文总结了国内用户在访问github网站时可能遇到的加载慢的问题,并提供了解决方法,其中包括修改hosts文件来加速访问。 ... [详细]
  • 如何实现JDK版本的切换功能,解决开发环境冲突问题
    本文介绍了在开发过程中遇到JDK版本冲突的情况,以及如何通过修改环境变量实现JDK版本的切换功能,解决开发环境冲突的问题。通过合理的切换环境,可以更好地进行项目开发。同时,提醒读者注意不仅限于1.7和1.8版本的转换,还要适应不同项目和个人开发习惯的需求。 ... [详细]
  • 2016 linux发行版排行_灵越7590 安装 linux (manjarognome)
    RT之前做了一次灵越7590黑苹果炒作业的文章,希望能够分享给更多不想折腾的人。kawauso:教你如何给灵越7590黑苹果抄作业​zhuanlan.z ... [详细]
  • ShiftLeft:将静态防护与运行时防护结合的持续性安全防护解决方案
    ShiftLeft公司是一家致力于将应用的静态防护和运行时防护与应用开发自动化工作流相结合以提升软件开发生命周期中的安全性的公司。传统的安全防护方式存在误报率高、人工成本高、耗时长等问题,而ShiftLeft提供的持续性安全防护解决方案能够解决这些问题。通过将下一代静态代码分析与应用开发自动化工作流中涉及的安全工具相结合,ShiftLeft帮助企业实现DevSecOps的安全部分,提供高效、准确的安全能力。 ... [详细]
  • tcpdump 4.5.1 crash 深入分析
    tcpdump 4.5.1 crash 深入分析 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • PL2303HXD电路图(USB转UART)介绍及应用
    本文介绍了PL2303HXD电路图(USB转UART)的特性和应用,该电路图可以实现RS232和USB信号的转换,方便嵌入到手持设备中。PL2303HXD作为USB/RS232双向转换器,可以将USB数据转换为RS232信息流格式发送给外设,并将RS232外设的数据转换为USB数据格式传送回主机。通过利用USB块传输模式和自动流量控制,PL2303HXD能够实现更高的数据传输吞吐量比传统的UART端口。 ... [详细]
author-avatar
小牛
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有