禁止复制,转载请注明出处和作者
Containerd 模块从 docker 中分离出来后,性能变得更加丰盛,依赖者变得更加宽泛,不仅仅是docker在应用,能够看到在云原生利用中波及到容器技术时根本都在依赖 containerd。


图片起源 https://www.slideshare.net/Docker/leveraging-the-power-of-containerd-events-evan-hazlett

一、Containerd 作用

containerd 的上层是runc,containerd 次要在为runc提供 oci(Open Container Initiative)runtime spec,oci 定义了两个规范,一个是对于镜像的,一个是对于容器运行时,容器运行时规范简略来说就是一个config.json文件和一个rootfs,对于oci的详细信息能够看官网github仓库或者文末参考。containerd就是oci一个规范实现。

containerd 在docker架构中的地位
二、Container架构剖析

containerd自身就提供了ctr命令行工具,grpc接口用来治理容器的生命周期,containerd在镜像治理上进行了翻新,不再像docker应用graphdriver来治理镜像,而是应用快照的形式,在容器的世界中存在两种镜像,一种是overlays filesystems(AUFS、OverlayFS), 一种是snapshotting filesystems(devicemapper、btrfs、ZFS)

containerd中的数据流

containerd的工作次要分为以下几步
1)拉取镜像,存储到 metadata(metadata是个bolt键值型数据库) 和content中,content中的存储是带标签的存储,metadata中的存储是不带标签,content次要用来进行独立执行或者测试应用,查问的还是metadata中的数据。metadata中的content中的内容次要是 manifests 的index、manifests、config.json、image layer。在拉取完之后同时创立了一个镜像到metadata的image内容空间,还有几本snapshot的构建。
metadata 的schema

// keys.//  ├──version : <varint>                        - Latest version, see migrations//  └──v1                                        - Schema version bucket//     ╘══*namespace*//        ├──labels//        │  ╘══*key* : <string>                 - Label value//        ├──image//        │  ╘══*image name*//        │     ├──createdat : <binary time>     - Created at//        │     ├──updatedat : <binary time>     - Updated at//        │     ├──target//        │     │  ├──digest : <digest>          - Descriptor digest//        │     │  ├──mediatype : <string>       - Descriptor media type//        │     │  └──size : <varint>            - Descriptor size//        │     └──labels//        │        ╘══*key* : <string>           - Label value//        ├──containers//        │  ╘══*container id*//        │     ├──createdat : <binary time>     - Created at//        │     ├──updatedat : <binary time>     - Updated at//        │     ├──spec : <binary>               - Proto marshaled spec//        │     ├──image : <string>              - Image name//        │     ├──snapshotter : <string>        - Snapshotter name//        │     ├──snapshotKey : <string>        - Snapshot key//        │     ├──runtime//        │     │  ├──name : <string>            - Runtime name//        │     │  ├──extensions//        │     │  │  ╘══*name* : <binary>       - Proto marshaled extension//        │     │  └──options : <binary>         - Proto marshaled options//        │     └──labels//        │        ╘══*key* : <string>           - Label value//        ├──snapshots//        │  ╘══*snapshotter*//        │     ╘══*snapshot key*//        │        ├──name : <string>            - Snapshot name in backend//        │        ├──createdat : <binary time>  - Created at//        │        ├──updatedat : <binary time>  - Updated at//        │        ├──parent : <string>          - Parent snapshot name//        │        ├──children//        │        │  ╘══*snapshot key* : <nil>  - Child snapshot reference//        │        └──labels//        │           ╘══*key* : <string>        - Label value//        ├──content//        │  ├──blob//        │  │  ╘══*blob digest*//        │  │     ├──createdat : <binary time>  - Created at//        │  │     ├──updatedat : <binary time>  - Updated at//        │  │     ├──size : <varint>            - Blob size//        │  │     └──labels//        │  │        ╘══*key* : <string>        - Label value//        │  └──ingests//        │     ╘══*ingest reference*//        │        ├──ref : <string>             - Ingest reference in backend//        │        ├──expireat : <binary time>   - Time to expire ingest//        │        └──expected : <digest>        - Expected commit digest//        └──leases//           ╘══*lease id*//              ├──createdat : <binary time>     - Created at//              ├──labels//              │  ╘══*key* : <string>           - Label value//              ├──snapshots//              │  ╘══*snapshotter*//              │     ╘══*snapshot key* : <nil>  - Snapshot reference//              ├──content//              │  ╘══*blob digest* : <nil>      - Content blob reference//              └──ingests//                 ╘══*ingest reference* : <nil> - Content ingest reference

在contained中是存在namespace的概念的
2)当运行容器时,利用metadata中的content、snapshot、image信息进行active snapshot(能够了解为docker中的容器层)的构建,构建bundle,调用runc启动容器。

containerd中的插件机制

containerd对外接口有ctr命令行和有grpc,ctr也是通过grpc协定来与containerd server通信,grpc server不是像咱们平时应用的那样将各个service导入到某个入口包中进行注册,containerd应用了插件注册机制,将task、content、snapshot、namespace、event、containers等服务以插件的形式注册而后提供服务.
这是containerd的外部插件

[root@master containerd]# ctr plugin lsTYPE                            ID                       PLATFORMS      STATUSio.containerd.content.v1        content                  -              okio.containerd.snapshotter.v1    aufs                     linux/amd64    errorio.containerd.snapshotter.v1    btrfs                    linux/amd64    errorio.containerd.snapshotter.v1    devmapper                linux/amd64    errorio.containerd.snapshotter.v1    native                   linux/amd64    okio.containerd.snapshotter.v1    overlayfs                linux/amd64    okio.containerd.snapshotter.v1    zfs                      linux/amd64    errorio.containerd.metadata.v1       bolt                     -              okio.containerd.differ.v1         walking                  linux/amd64    okio.containerd.gc.v1             scheduler                -              okio.containerd.service.v1        introspection-service    -              okio.containerd.service.v1        containers-service       -              okio.containerd.service.v1        content-service          -              okio.containerd.service.v1        diff-service             -              okio.containerd.service.v1        images-service           -              okio.containerd.service.v1        leases-service           -              okio.containerd.service.v1        namespaces-service       -              okio.containerd.service.v1        snapshots-service        -              okio.containerd.runtime.v1        linux                    linux/amd64    okio.containerd.runtime.v2        task                     linux/amd64    okio.containerd.monitor.v1        cgroups                  linux/amd64    okio.containerd.service.v1        tasks-service            -              okio.containerd.internal.v1       restart                  -              okio.containerd.grpc.v1           containers               -              okio.containerd.grpc.v1           content                  -              okio.containerd.grpc.v1           diff                     -              okio.containerd.grpc.v1           events                   -              okio.containerd.grpc.v1           healthcheck              -              okio.containerd.grpc.v1           images                   -              okio.containerd.grpc.v1           leases                   -              okio.containerd.grpc.v1           namespaces               -              okio.containerd.internal.v1       opt                      -              okio.containerd.grpc.v1           snapshots                -              okio.containerd.grpc.v1           tasks                    -              okio.containerd.grpc.v1           version                  -              ok

扩大插件的两种形式
1、通过二进制形式在containerd的命令行传入
2、通过配置containerd的配置文件来设置proxy pligin
runtime在containerd中有v1和v2两个版本,能够在执行ctr run命令中通过命令行传入

ctr run --runtime io.containerd.runc.v1

自定义快照插件,/etc/containerd/config.toml 是containerd的默认配置文件,

[proxy_plugins]  [proxy_plugins.customsnapshot]    type = "snapshot"    address = "/var/run/mysnapshotter.sock"

proxy plugin会在containerd启动时随着外部插件一起启动。

containerd中的event

containerd中实现了event的发订阅性能,在对每个资源操作后都会推送相干事件给订阅者,利用这个性能能够事件对containerd的监控和实现一些hook性能。

containerd中的namespace

通过上文中metadata中的scame能够看到在containerd中是存在命名空间的概念以及实现,相似opensatck中多租户一样,能够将不同的业务和利用进行隔离,比方kubernetes中应用containerd和docker在应用containerd时就应用了不同的namespace。

三、总结

containerd代码从docker中分离出来后,性能变得丰盛弱小以至于根本所有云计算中容器相干的底层都在利用containerd,在镜像治理上作者实现了微翻新,docker中应用的是graph driver治理镜像,containerd中应用的snapshot,为什么会应用snapshot模型,因为snapshot在增量快照上是有严格的父子关系,这种关系和镜像的分层模型很统一,在容器世界有两种文件系统一种是块级别的一种是文件系统级别,container的将块级别的进行分层化,将文件系统级别的进行快照化。

四、参考

1、runtime spec
2、https://github.com/containerd/containerd/blob/master/PLUGINS.md
3、https://github.com/containerd/containerd/blob/master/design/data-flow.md
4、https://www.slideshare.net/Docker/assessing-container-runtime-performance-with-bucketbench-by-phil-estes-ibm
5、https://cizixs.com/2017/11/05/oci-and-runc/
6、https://heychenbin.github.io/post/containerd_intro/
7、https://www.jianshu.com/p/86296691ca49
8、https://blog.mobyproject.org/where-are-containerds-graph-drivers-145fc9b7255
9、https://container42.com/2017/10/14/containerd-deep-dive-intro/