Nydus容器镜像加速能力并集成到nerdctl(实验中。。。。。。)

镜像原理

docker进阶之镜像分层

可以想象,像 ubuntu等基础镜像,体积必然不小。那么,思考以下几个问题:

  • 我们基于同一个镜像(ubuntu 18.4)启动了两个容器,会占用两倍磁盘空间吗?

  • 我们在容器内修改或者新建了某个文件,要修改原镜像吗?

  • 我们基于某镜像(ubuntu 18.04)新建一个镜像(myubuntu),需要将原镜像文件全部拷贝到新镜像中吗?

入门图解:
我们创建一个最简单的镜像

  1. 构建测试镜像:docker build -t image_test:1.0 .
  2. FROM alpine:3.15.0 #除了继承基础镜像,啥也不做
  3. 2.构建测试镜像v2.0:docker build -t image_test:2.0 .
  4. FROM alpine:3.15.0
    RUN dd if=/dev/zero of=file1 bs=10M count=1 #添加一个10M的文件file1
  5. 构建测试镜像v3.0:docker build -t image_test:3.0 . FROM alpine:3.15.0 RUN
    dd if=/dev/zero of=file1 bs=10M count=1 #添加一个10M的文件file1 RUN dd
    if=/dev/zero of=file2 bs=10M count=1 #添加一个10M的文件file2

镜像分层的好处

知道了镜像是分层的,那么我们是不是好奇为啥要这么设计呢?
试想一下我们如果不分层会有什么问题?

以拉取镜像为例!
拉取镜像的镜像很大,比如Redis的镜像有100多M
第一次我们拉取6.2版本的Redis,下载了完成的100M到本地,下次我要下载6.2.6版本的,是不是又得下载100M。
尽管可能两个版本之间就改了几行配置文件。

这样是非常低效的。如果能只下载有差异的部分就好了!

这个痛点,也就是镜像分层要解决的问题。实际上,Docker也是这么实现的。
第一次下载redis:6.2时,因为之前没有下载过,所以下载了所有的层,总共113M。网络慢点的话还是需要花一些时间的!
在这里插入图片描述
bootfs(boot file system) 主要包含 bootloader 和 kernel, bootloader 主要是引导加载 kernel,Linux 刚启动时会加载 bootfs 文件系统,在Docker 镜像的最底层是引导文件系统 bootfs。这一层与我们典型的 Linux/Unix 系统是一样的,包含 boot 加载器和内核。当 boot 加载完成之后整个内核就都在内存中了,此时内存的使用权已由 bootfs 转交给内核,此时系统也会卸载 bootfs。

rootfs (root file system) ,在 bootfs 之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs 就是各种不同的操作系统发行版,比如 Ubuntu,Centos 等等。

对于一个精简的 OS,rootfs 可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用 Host 的 kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的 linux 发行版, bootfs 基本是一致的, rootfs 会有差别, 因此不同的发行版可以公用 bootfs。
在这里插入图片描述
Docker镜像层都是只读的,容器层是可写的。 当容器启动时,一个新的可写层被加载到镜像的顶部。 这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。所有对容器的改动,无论添加、删除、还是修改文件都只会发生在容器层中。

那么,先让我们来重新认识一下与 Docker 镜像相关的 4 个概念:rootfs、Union mount、image 以及 layer。

rootfs

Rootfs:代表一个 Docker Container 在启动时(而非运行后)其内部进程可见的文件系统视角,或者是 Docker Container 的根目录。当然,该目录下含有 Docker Container 所需要的系统文件、工具、容器文件等。

传统来说,Linux 操作系统内核启动时,内核首先会挂载一个只读(read-only)的 rootfs,当系统检测其完整性之后,决定是否将其切换为读写(read-write)模式,或者最后在 rootfs 之上另行挂载一种文件系统并忽略 rootfs。Docker 架构下,依然沿用 Linux 中 rootfs 的思想。当 Docker Daemon 为 Docker Container 挂载 rootfs 的时候,与传统 Linux 内核类似,将其设定为只读(read-only)模式。在 rootfs 挂载完毕之后,和 Linux 内核不一样的是,Docker Daemon 没有将 Docker Container 的文件系统设为读写(read-write)模式,而是利用 Union mount 的技术,在这个只读的 rootfs 之上再挂载一个读写(read-write)的文件系统,挂载时该读写(read-write)文件系统内空无一物。
在这里插入图片描述
正如 read-only 和 read-write 的含义那样,该容器中的进程对 rootfs 中的内容只拥有读权限,对于 read-write 读写文件系统中的内容既拥有读权限也拥有写权限。容器虽然只有一个文件系统,但该文件系统由“两层”组成,分别为读写文件系统和只读文件系统。

Union mount

Union mount:代表一种文件系统挂载的方式,允许同一时刻多种文件系统挂载在一起,并以一种文件系统的形式,呈现多种文件系统内容合并后的目录。

一般情况下,通过某种文件系统挂载内容至挂载点的话,挂载点目录中原先的内容将会被隐藏。而 Union mount 则不会将挂载点目录中的内容隐藏,反而是将挂载点目录中的内容和被挂载的内容合并,并为合并后的内容提供一个统一独立的文件系统视角。通常来讲,被合并的文件系统中只有一个会以读写(read-write)模式挂载,而其他的文件系统的挂载模式均为只读(read-only)。实现这种 Union mount 技术的文件系统一般被称为 Union Filesystem,较为常见的有 UnionFS、AUFS、OverlayFS 等。

Docker 实现容器文件系统 Union mount 时,提供多种具体的文件系统解决方案,如 Docker 早版本沿用至今的的 AUFS,还有在 docker 1.4.0 版本中开始支持的 OverlayFS 等。
在这里插入图片描述
使用镜像 ubuntu 创建的容器中,可以暂且将该容器整个 rootfs 当成是一个文件系统。上文也提到,挂载时读写(read-write)文件系统中空无一物。既然如此,从用户视角来看,容器内文件系统和 rootfs 完全一样,用户完全可以按照往常习惯,无差别的使用自身视角下文件系统中的所有内容;然而,从内核的角度来看,两者在有着非常大的区别。追溯区别存在的根本原因,那就不得不提及 AUFS 等文件系统的 COW(copy-on-write)特性。

COW 文件系统和其他文件系统最大的区别就是:从不覆写已有文件系统中已有的内容。由于通过 COW 文件系统将两个文件系统(rootfs 和 read-write filesystem)合并,最终用户视角为合并后的含有所有内容的文件系统,然而在 Linux 内核逻辑上依然可以区别两者,那就是用户对原先 rootfs 中的内容拥有只读权限,而对 read-write filesystem 中的内容拥有读写权限。

既然对用户而言,全然不知哪些内容只读,哪些内容可读写,这些信息只有内核在接管,那么假设用户需要更新其视角下的文件 /etc/hosts,而该文件又恰巧是 rootfs 只读文件系统中的内容,内核是否会抛出异常或者驳回用户请求呢?答案是否定的。当此情形发生时,COW 文件系统首先不会覆写 read-only 文件系统中的文件,即不会覆写 rootfs 中 /etc/hosts,其次反而会将该文件拷贝至读写文件系统中,即拷贝至读写文件系统中的 /etc/hosts,最后再对后者进行更新操作。如此一来,纵使 rootfs 与 read-write filesystem 中均由 /etc/hosts,诸如 AUFS 类型的 COW 文件系统也能保证用户视角中只能看到 read-write filesystem 中的 /etc/hosts,即更新后的内容。

当然,这样的特性同样支持 rootfs 中文件的删除等其他操作。例如:用户通过 apt-get 软件包管理工具安装 Golang,所有与 Golang 相关的内容都会被安装在读写文件系统中,而不会安装在 rootfs。此时用户又希望通过 apt-get 软件包管理工具删除所有关于 MySQL 的内容,恰巧这部分内容又都存在于 rootfs 中时,删除操作执行时同样不会删除 rootfs 实际存在的 MySQL,而是在 read-write filesystem 中删除该部分内容,导致最终 rootfs 中的 MySQL 对容器用户不可见,也不可访。

image

Docker 中 rootfs 的概念,起到容器文件系统中基石的作用。对于容器而言,其只读的特性,也是不难理解。神奇的是,实际情况下 Docker 的 rootfs 设计与实现比上文的描述还要精妙不少。

继续以 ubuntu 为例,虽然通过 AUFS 可以实现 rootfs 与 read-write filesystem 的合并,但是考虑到 rootfs 自身接近 200MB 的磁盘大小,如果以这个 rootfs 的粒度来实现容器的创建与迁移等,是否会稍显笨重,同时也会大大降低镜像的灵活性。而且,若用户希望拥有一个 ubuntu 的 rootfs,那么是否有必要创建一个全新的 rootfs,毕竟 ubuntu 和 ubuntu 的 rootfs 中有很多一致的内容。

Docker 中 image 的概念,非常巧妙的解决了以上的问题。最为简单的解释 image,就是 Docker 容器中只读文件系统 rootfs 的一部分。换言之,实际上 Docker 容器的 rootfs 可以由多个 image 来构成。多个 image 构成 rootfs 的方式依然沿用 Union mount 技术。
在这里插入图片描述
多个 Image 构成 rootfs 的示意图。图中,rootfs 中每一层 image 中的内容划分只为了阐述清楚 rootfs 由多个 image 构成,并不代表实际情况中 rootfs 中的内容划分。

从上图可以看出,举例的容器 rootfs 包含 4 个 image,其中每个 image 中都有一些用户视角文件系统中的一部分内容。4 个 image 处于层叠的关系,除了最底层的 image,每一层的 image 都叠加在另一个 image 之上。另外,每一个 image 均含有一个 image ID,用以唯一的标记该 image。

基于以上的概念,Docker Image 中又抽象出两种概念:Parent Image 以及 Base Image。除了容器 rootfs 最底层的 image,其余 image 都依赖于其底下的一个或多个 image,而 Docker 中将下一层的 image 称为上一层 image 的 Parent Image。imageID_0 是 imageID_1 的 Parent Image,imageID_2 是 imageID_3 的 Parent Image,而 imageID_0 没有 Parent Image。对于最下层的 image,即没有 Parent Image 的镜像,在 Docker 中习惯称之为 Base Image。

通过 image 的形式,原先较为臃肿的 rootfs 被逐渐打散成轻便的多层。Image 除了轻便的特性,同时还有上文提到的只读特性,如此一来,在不同的容器、不同的 rootfs 中 image 完全可以用来复用。

layer

Docker 术语中,layer 是一个与 image 含义较为相近的词。容器镜像的 rootfs 是容器只读的文件系统,rootfs 又是由多个只读的 image 构成。于是,rootfs 中每个只读的 image 都可以称为一层 layer。

除了只读的 image 之外,Docker Daemon 在创建容器时会在容器的 rootfs 之上,再 mount 一层 read-write filesystem,而这一层文件系统,也称为容器的一层 layer,常被称为 top layer。

因此,总结而言,Docker 容器中的每一层只读的 image,以及最上层可读写的文件系统,均被称为 layer。如此一来,layer 的范畴比 image 多了一层,即多包含了最上层的 read-write filesystem。

有了 layer 的概念,大家可以思考这样一个问题:容器文件系统分为只读的 rootfs,以及可读写的 top layer,那么容器运行时若在 top layer 中写入了内容,那这些内容是否可以持久化,并且也被其它容器复用?

上文对于 image 的分析中,提到了 image 有复用的特性,既然如此,再提一个更为大胆的假设:容器的 top layer 是否可以转变为 image?

答案是肯定的。Docker 的设计理念中,top layer 转变为 image 的行为(Docker 中称为 commit 操作),大大释放了容器 rootfs 的灵活性。Docker 的开发者完全可以基于某个镜像创建容器做开发工作,并且无论在开发周期的哪个时间点,都可以对容器进行 commit,将所有 top layer 中的内容打包为一个 image,构成一个新的镜像。Commit 完毕之后,用户完全可以基于新的镜像,进行开发、分发、测试、部署等。不仅 docker commit 的原理如此,基于 Dockerfile 的 docker build,其追核心的思想,也是不断将容器的 top layer 转化为 image。

Docker镜像下载

Docker Image 作为 Docker 生态中的精髓,下载过程中需要 Docker 架构中多个组件的协作。Docker 镜像的下载流程如图:请添加图片描述
1、docker client发送镜像的tag到registry。
2、registry根据镜像tag,得到镜像的manifest文件,返回给docker client。
3、docker client拿到manifest文件后,根据其中的config的digest,也就是image ID,检查下镜像在本地是否存在。
4、如果镜像不存在,则下载config文件,并根据config文件中的diff_ids得到镜像每一层解压后的digest。
5、然后根据每层解压后的digest文件,检查本地是否存在,如果不存在,则通过manifest文件中的6、layer的digest下载该层并解压,然后校验解压后digest是否匹配。
7、下载完所有层后,镜像就下载完毕。

镜像存储

Docker Daemon 执行镜像下载任务时,从 Docker Registry 处下载指定镜像之后,仍需要将镜像合理地存储于宿主机的文件系统中。更为具体而言,存储工作分为两个部分:

(1) 存储镜像内容;

(2) 在 graph 中注册镜像信息。

说到镜像内容,需要强调的是,每一层 layer 的 Docker Image 内容都可以认为有两个部分组成:镜像中每一层 layer 中存储的文件系统内容,这部分内容一般可以认为是未来 Docker 容器的静态文件内容;另一部分内容指的是容器的 json 文件,json 文件代表的信息除了容器的基本属性信息之外,还包括未来容器运行时的动态信息,包括 ENV 等信息。

存储镜像内容,意味着 Docker Daemon 所在宿主机上已经存在镜像的所有内容,除此之外,Docker Daemon 仍需要对所存储的镜像进行统计备案,以便用户在后续的镜像管理与使用过程中,可以有据可循。为此,Docker Daemon 设计了 graph,使用 graph 来接管这部分的工作。graph 负责记录有哪些镜像已经被正确存储,供 Docker Daemon 调用。

Nydus–容器镜像探索

基于本人理解项目导师文章:
文|严松(花名:井守)

Nydus 镜像开源项目 Maintainer、蚂蚁集团技术专家

蚂蚁集团基础设施研发,专注云原生镜像与容器运行时生态
原文:https://developer.aliyun.com/article/971522
在这里插入图片描述
容器镜像是云原生的基础设施之一,作为容器运行时文件系统视图基础,从它诞生到现在,衍生出了镜像构建、存储、分发到运行时的整个镜像生命周期的各种生态。

然而,虽然镜像生态众多,但自它诞生以来,镜像设计本身并没有多少改进。这篇文章要探讨的就是对容器镜像未来发展的一些思考,以及 Nydus 容器镜像的探索和实践。
容器提供给了应用一个快速、轻量且有着基本隔离环境的运行时,而镜像提供给了容器 RootFS,也就是容器内能看到的整个 Filesystem 视图,其中至少包括了文件目录树结构、文件元数据以及数据部分。镜像的特点如下:

  • 易于传输,例如通过网络以 HTTP 的方式从 Registry 上传或下载;

  • 易于存储,例如可以打包成 Tar Gzip 格式,存储在 Registry 上;

  • 具备不可变特性,整个镜像有一个唯一 Hash,只要镜像内容发生变化,镜像 Hash 也会被改变。

早期的镜像格式是由 Docker 设计的,经历了从 Image Manifest V1[1]、V2 Scheme 1[2]到 V2 Scheme 2[3]的演进。后来出现了诸如 CoreOS 推出的其他容器运行时后,为了避免竞争和生态混乱,OCI 标准化社区成立。它定义了容器在运行时、镜像以及分发相关的实现标准,我们目前用的镜像格式基本都是 OCI 兼容的。请添加图片描述

镜像设计应该如何改进

我们看到了 OCI 镜像设计的诸多问题,在大规模集群场景下,存储与网络负载压力会被放大,这些问题的影响尤为明显,因此镜像设计急需从格式、构建、分发、运行、安全等各方面做优化。请添加图片描述
首先,我们需要实现按需加载。 在容器启动时,容器内业务 IO 请求了哪些文件的数据,我们再从远端 Registry 拉取这些数据,通过这种方式,可以避免镜像大量数据拉取阻塞容器的启动。

其次,我们需要用一个索引文件记录某个文件的数据块在层的 Offset 偏移位置。 因为现在的问题是,Tar 格式是不可寻址的,也就是说需要某个文件时,只能从头顺序读取整个 Tar 流才能找到这部分数据,那么我们自然就想到了可以用这种方式来实现。

接着,我们改造层的格式以支持更简单的寻址。 由于 Tar 是会被 Gzip 压缩的,这导致了就算知道 Offset 也比较难 Unzip。

我们让原来的镜像层只存储文件的数据部分 (也就是图中的 Blob 层) 。Blob 层存储的是文件数据的切块 (Chunk) ,例如将一个 10MB 的文件,切割成 10 个 1MB 的块。这样的好处是我们可以将 Chunk 的 Offset 记录在一个索引中,容器在请求文件的部分数据时,我们可以只从远端 Registry 拉取需要的一部分 Chunks,如此一来节省不必要的网络开销。

另外,按 Chunk 切割的另外一个优势是细化了去重粒度,Chunk 级别的去重让层与层之间,镜像与镜像之间共享数据更容易。

最后,我们将元数据和数据分离 。 这样可以避免出现因元数据更新导致的数据层更新的情况,通过这种方式来节省存储和传输成本。

元数据和 Chunk 的索引加在一起,就组成了上图中的 Meta 层,它是所有镜像层堆叠后容器能看到的整个 Filesystem 结构,包含目录树结构,文件元数据,Chunk 信息等。

另外,Meta 层包含了 Hash 树以及 Chunk 数据块的 Hash,以此来保证我们可以在运行时对整颗文件树校验,以及针对某个 Chunk 数据块做校验,并且可以对整个 Meta 层签名,以保证运行时数据被篡改后依然能够被检查出来。

如上所述,我们在 Nydus 镜像格式中引入了这些特性,总结下来如下:

  • 镜像元数据和数据分离,用户态按需加载与解压;

  • 更细粒度的块级别数据切割与去重;

  • 扁平化元数据层 (移除中间层) ,直接呈现 Filesystem 视图;

  • 端到端的文件系统元数据树与数据校验。

Nydus解决方案

Nydus 镜像加速框架是 Dragonfly[7] (CNCF 孵化中项目) 的子项目。它兼容了目前的 OCI 镜像构建、分发、运行时生态。Nydus 运行时由 Rust 编写,它在语言级别的安全性以及在性能、内存和 CPU 的开销方面非常有优势,同时也兼具了安全和高可扩展性。
请添加图片描述
Nydus 默认使用用户态文件系统实现 FUSE[8]来做按需加载,用户态的 Nydus Daemon 进程将 Nydus 镜像挂载点作为容器 RootFS 目录。当容器产生 read (fd, count) 之类的文件系统 IO 时,内核态 FUSE 驱动将该请求加入处理队列,用户态 Nydus Daemon 通过 FUSE Device 读取并处理该请求,从远端 Registry 拉取 Count 对应数量的 Chunk 数据块后,最终通过内核态 FUSE 回复给容器。请添加图片描述
Nydus 加速框架支持了三种运行模式,以支持不同场景下的镜像按需加载:

  1. 通过 FUSE 提供给 RunC 这类容器运行时的按需加载能力,也是 Nydus 目前最常用的模式;

  2. 通过 VirtioFS[9]承载 FUSE 协议,让基于 VM 的容器运行时,例如 Kata 等,为 VM Guest 里的容器提供 RootFS 按需加载能力;

  3. 通过内核态的 EROFS[10]只读文件系统提供 RootFS,目前 Nydus 的 EROFS 格式支持已经进入了 Linux 5.16 主线,其内核态缓存方案 erofs over fscache 也已经合入 Linux 5.19-rc1 主线,内核态方案可以减少上下文切换及内存拷贝开销,在性能有极致要求的情况下可以用这种模式。

在存储后端侧,Nydus 可以接各种 OCI Distribution 兼容的 Registry,以及直接对接对象存储服务例如 OSS,网络文件系统例如 NAS 等。它也包含了本地 Cache 能力,在数据块从远端拉取下来后,它会被解压并存储到本地缓存中,以便在下一次热启动时提供更好的性能。

另外除了近端本地 Cache,它也可以接 P2P 文件分发系统 (例如 Dragonfly) 以加速块数据的传输。同时,它也能够最大程度降低大规模集群下的网络负载以及 Registry 的单点压力,实际场景测试在有 P2P 缓存的情况下,网络延迟能够降低 80% 以上。
请添加图片描述

镜像场景性能优化

目前仅在蚂蚁的落地场景下,都有每日百万级别的 Nydus 加速镜像容器创建,它在生产级的稳定性和性能方面得到了保障。在如此大规模的场景考验下,Nydus 在性能,资源消耗等方面做了诸多优化。

镜像数据性能方面,Rust 实现的运行时 (nydusd) 本身已经在内存及 CPU 方面做到了低开销。影响 Nydus 镜像容器启动性能的主要负载是来自网络,因此除了借助 P2P 分发从就近节点拉取 Chunk 块数据外,Nydus 还实现了一层本地 Cache,已经从远端拉取的 Chunk 会解压缩后缓存在本地,Cache 可以做到以层为单位在镜像之间共享,也可以做到 Chunk 级别的共享。

虽然 Nydus 可以配置集群内 P2P 加速,但按需加载在拉取每个 Chunk 时都可能会发起一次网络 IO。因此我们实现了 IO 读放大,将小块请求合并在一起发起一次请求,降低连接数。同时 Dragonfly 也实现了针对 Nydus 的 Chunk 块级别的 P2P 缓存和加速。

另外,我们通过观察容器启动时读取镜像文件的顺序,能够分析出访问模式,从而在容器 IO 读数据前预先加载这部分数据 (预取) ,能够提高冷启动性能。与此同时,我们通过在镜像构建阶段重新排布 Chunk 顺序,能够进一步降低启动延迟。

镜像元数据性能方面,例如对于一个几十 GB 大小且小文件较多的 Nydus 镜像,它的元数据层可能会达到 10MB 以上,如果一次性加载到内存中会非常不合算。因此我们改造了元数据结构,让它也实现了按需加载 (ondisk mmap) ,对函数计算这种内存敏感场景非常有用。

除了在运行时优化性能以外,Nydus 在构建时还做了一些优化工作。在多数场景下相比 Tar Gzip 格式的 OCI 镜像,Nydus 镜像层导出时间优化到比其快 30%,未来目标是优化到 50% 以上。

Nerdctl

nerdctl 是用于 containerd 并且 兼容 docker cli 习惯的管理工具,主要适用于刚从 docker 转到 containerd 的用户,操作 containerd 的命令行工具 ctr 和 crictl 不怎么好用,所以就有了 nerdctl。

安装

nerdctl 的安装分为 Minimal 精简安装和包含一些插件的 Full 完整安装。精简版只包含 nerdctl,完整版包含 nerdctl 和 CNI 插件等依赖(当然你也可以在精简安装的基础上再自己添加 CNI 等插件)
一、安装containerd

yum install  containerd.io cri-tools  -y

出现异常:Delta RPMs disabled because /usr/bin/applydeltarpm not installed.

yum provides '*/applydeltarpm'  
yum install deltarpm -y

启动containerd并设置开机自动启动

systemctl enable containerd  --now

修改containerd配置文件并配置加速器

 vi /etc/containerd/config.toml
 
 ## 内容如下:
disabled_plugins = ["restart"]
[plugins]
   [plugins.cri.registry.mirrors."docker.io"]
     endpoint = ["https://frz7i079.mirror.aliyuncs.com"]

重启containerd

 systemctl restart containerd

下载并安装nerdctl

wget https://github.com/containerd/nerdctl/releases/download/v0.8.2/nerdctl-0.8.2-linux-amd64.tar.gz

tar zxvf nerdctl-0.8.2-linux-amd64.tar.gz -C /usr/local/bin/

安装网络插件:

## 下载网络插件
wget https://github.com/containernetworking/plugins/releases/download/v0.9.1/cni-plugins-linux-amd64-v0.9.1.tgz
## 解压
mkdir -p /opt/cni/bin/
tar zxf cni-plugins-linux-amd64-v0.9.1.tgz -Chead -2 /etc/profile/opt/cni/bin/

设置nerdctl子命令可以使用tab键

# 编辑文件
vim /etc/profile
source <(nerdctl completion bash)
# 让其生效
source /etc/profile

镜像管理

nerdctl pull nginx #拉取镜像
nerdctl images # 查看镜像列表
nerdctl tag nginx:latest 192.168.11.101/cka/nginx:v1 # 给镜像打标签

创建容器

nerdctl run -d  --name=c1 --restart=always -p 80:80 192.168.26.101/cka/nginx:v1

查看运行时的容器·

nerdctl ps

进入容器

nerdctl exec -it c1 bash

查看版本号验证安装
[root@test tmp] nerdctl --version
nerdctl version 1.0.0

命令:

[root@test tmp]# nerdctl -h
nerdctl is a command line interface for containerd

Config file ($NERDCTL_TOML): /etc/nerdctl/nerdctl.toml

Usage: nerdctl [flags]

Management commands:
  apparmor   Manage AppArmor profiles
  builder    Manage builds
  container  Manage containers
  image      Manage images
  ipfs       Distributing images on IPFS
  namespace  Manage containerd namespaces
  network    Manage networks
  system     Manage containerd
  volume     Manage volumes

Commands:
  build       Build an image from a Dockerfile. Needs buildkitd to be running.
  commit      Create a new image from a container's changes
  completion  Generate the autocompletion script for the specified shell
  compose     Compose
  cp          Copy files/folders between a running container and the local filesystem.
  create      Create a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS.
  events      Get real time events from the server
  exec        Run a command in a running container
  help        Help about any command
  history     Show the history of an image
  images      List images
  info        Display system-wide information
  inspect     Return low-level information on objects.
  internal    DO NOT EXECUTE MANUALLY
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  login       Log in to a container registry
  logout      Log out from a container registry
  logs        Fetch the logs of a container. Currently, only containers created with `nerdctl run -d` are supported.
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  ps          List containers
  pull        Pull an image from a registry. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS.
  push        Push an image or a repository to a registry. Optionally specify "ipfs://" or "ipns://" scheme to push image to IPFS.
  rename      rename a container
  restart     Restart one or more running containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  run         Run a command in a new container. Optionally specify "ipfs://" or "ipns://" scheme to pull image from IPFS.
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  start       Start one or more running containers
  stats       Display a live stream of container(s) resource usage statistics.
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update one or more running containers
  version     Show the nerdctl version information
  wait        Block until one or more containers stop, then print their exit codes.

Flags:
  -H, --H string                 Alias of --address (default "/run/containerd/containerd.sock")
  -a, --a string                 Alias of --address (default "/run/containerd/containerd.sock")
      --address string           containerd address, optionally with "unix://" prefix [$CONTAINERD_ADDRESS] (default "/run/containerd/containerd.sock")
      --cgroup-manager string    Cgroup manager to use ("cgroupfs"|"systemd") (default "cgroupfs")
      --cni-netconfpath string   cni config directory [$NETCONFPATH] (default "/etc/cni/net.d")
      --cni-path string          cni plugins binary directory [$CNI_PATH] (default "/opt/cni/bin")
      --data-root string         Root directory of persistent nerdctl state (managed by nerdctl, not by containerd) (default "/var/lib/nerdctl")
      --debug                    debug mode
      --debug-full               debug mode (with full output)
      --experimental             Control experimental: https://github.com/containerd/nerdctl/blob/master/docs/experimental.md [$NERDCTL_EXPERIMENTAL] (default true)
  -h, --help                     help for nerdctl
      --host string              Alias of --address (default "/run/containerd/containerd.sock")
      --hosts-dir strings        A directory that contains <HOST:PORT>/hosts.toml (containerd style) or <HOST:PORT>/{ca.cert, cert.pem, key.pem} (docker style) (default [/etc/containerd/certs.d,/etc/docker/certs.d])
      --insecure-registry        skips verifying HTTPS certs, and allows falling back to plain HTTP
  -n, --n string                 Alias of --namespace (default "default")
      --namespace string         containerd namespace, such as "moby" for Docker, "k8s.io" for Kubernetes [$CONTAINERD_NAMESPACE] (default "default")
      --snapshotter string       containerd snapshotter [$CONTAINERD_SNAPSHOTTER] (default "overlayfs")
      --storage-driver string    Alias of --snapshotter (default "overlayfs")
  -v, --version                  version for nerdctl

Run 'nerdctl COMMAND --help' for more information on a command.

可以通过配置文件 /etc/nerdctl/nerdctl.toml 对 nerdctl 进行更多配置

手工添加插件(按需可选)

以添加 CNI 插件为例,先到 CNI 插件的官方地址下载插件文件。

CNI 需放在指定目录,默认目录为 /opt/cni/bin (这个默认目录在 nerdctl --help 帮助中 --cni-path 后面有说明),nerdctl 会默认查找该目录。

[root@test tmp]# wget https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
[root@test tmp]# mkdir -p /opt/cni/bin
[root@test tmp]# tar -xzvf cni-plugins-linux-amd64-v1.1.1.tgz -C /opt/cni/bin
[root@test tmp]# ll /opt/cni/bin/
total 63728
-rwxr-xr-x 1 root root 3780654 Mar 10  2022 bandwidth
-rwxr-xr-x 1 root root 4221977 Mar 10  2022 bridge
-rwxr-xr-x 1 root root 9742834 Mar 10  2022 dhcp
-rwxr-xr-x 1 root root 4345726 Mar 10  2022 firewall
-rwxr-xr-x 1 root root 3811793 Mar 10  2022 host-device
-rwxr-xr-x 1 root root 3241605 Mar 10  2022 host-local
-rwxr-xr-x 1 root root 3922560 Mar 10  2022 ipvlan
-rwxr-xr-x 1 root root 3295519 Mar 10  2022 loopback
-rwxr-xr-x 1 root root 3959868 Mar 10  2022 macvlan
-rwxr-xr-x 1 root root 3679140 Mar 10  2022 portmap
-rwxr-xr-x 1 root root 4092460 Mar 10  2022 ptp
-rwxr-xr-x 1 root root 3484284 Mar 10  2022 sbr
-rwxr-xr-x 1 root root 2818627 Mar 10  2022 static
-rwxr-xr-x 1 root root 3379564 Mar 10  2022 tuning
-rwxr-xr-x 1 root root 3920827 Mar 10  2022 vlan
-rwxr-xr-x 1 root root 3523475 Mar 10  2022 vrf

测试一下

启动一个 nginx 容器,名称为 nginx-test,将宿主机端口 10800 和容器的 80 端口映射

# 启动容器
[root@test tmp]# nerdctl run -d --name nginx-test -p 10800:80 nginx:1.22.1
docker.io/library/nginx:1.22.1:                                                   resolved       |++++++++++++++++++++++++++++++++++++++| 
index-sha256:809f0924101d9c07322d69ab0705e1a0d85b1d0f287e320ae19b0826979c56e9:    done           |++++++++++++++++++++++++++++++++++++++| 
manifest-sha256:fa7e5dee56197a5cbb5b346b3c2c41d91ffa57eb1efcabb5ff09483c87270ccb: done           |++++++++++++++++++++++++++++++++++++++| 
config-sha256:404359394820dad4c8f210f935939f5890a02ccf82302e1a1068bd0723149736:   done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:50b97857b95c8b58fbaa89e528105534fc73606f71e0c4866566b2d6dda2f907:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:f3c8f37c59f021e336eb6064cb5ef086a44630c8a1cd0728d9b56d584a89fbaf:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:a603fa5e3b4127f210503aaa6189abf6286ee5a73deeaab460f8f33ebc6b64e2:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:0edfe97a837abe97ce52b42da5fad5df39a3daccc47b5e4d3bc294375b481a0a:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:0bf5e07cb0afcd466f3b9f207c8cbaf77a1d483779f37d0189115282e4374dc1:    done           |++++++++++++++++++++++++++++++++++++++| 
layer-sha256:f95a257c65b62fcb59f62f64ab3212e47226f460e9cbfa8c9187f2ab1923ca8c:    done           |++++++++++++++++++++++++++++++++++++++| 
elapsed: 20.9s                                                                    total:  30.0 M (1.4 MiB/s)                                       
d550e2afd0c1ac924a3047a559c38697167b6b2317a19b3336e43285c6e558dc

# 查看运行中的容器
[root@test tmp]# nerdctl ps
CONTAINER ID    IMAGE                             COMMAND                   CREATED           STATUS    PORTS                    NAMES
d550e2afd0c1    docker.io/library/nginx:1.22.1    "/docker-entrypoint.…"    32 seconds ago    Up        0.0.0.0:10080->80/tcp    nginx-test

# 根据容器名称删除容器
[root@test tmp]# nerdctl rm -f nginx-test
nginx-test

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啊啊啊杨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值