乐趣区

关于docker:聊聊-containerd

禁止复制,转载请注明出处和作者
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 ls
TYPE                            ID                       PLATFORMS      STATUS
io.containerd.content.v1        content                  -              ok
io.containerd.snapshotter.v1    aufs                     linux/amd64    error
io.containerd.snapshotter.v1    btrfs                    linux/amd64    error
io.containerd.snapshotter.v1    devmapper                linux/amd64    error
io.containerd.snapshotter.v1    native                   linux/amd64    ok
io.containerd.snapshotter.v1    overlayfs                linux/amd64    ok
io.containerd.snapshotter.v1    zfs                      linux/amd64    error
io.containerd.metadata.v1       bolt                     -              ok
io.containerd.differ.v1         walking                  linux/amd64    ok
io.containerd.gc.v1             scheduler                -              ok
io.containerd.service.v1        introspection-service    -              ok
io.containerd.service.v1        containers-service       -              ok
io.containerd.service.v1        content-service          -              ok
io.containerd.service.v1        diff-service             -              ok
io.containerd.service.v1        images-service           -              ok
io.containerd.service.v1        leases-service           -              ok
io.containerd.service.v1        namespaces-service       -              ok
io.containerd.service.v1        snapshots-service        -              ok
io.containerd.runtime.v1        linux                    linux/amd64    ok
io.containerd.runtime.v2        task                     linux/amd64    ok
io.containerd.monitor.v1        cgroups                  linux/amd64    ok
io.containerd.service.v1        tasks-service            -              ok
io.containerd.internal.v1       restart                  -              ok
io.containerd.grpc.v1           containers               -              ok
io.containerd.grpc.v1           content                  -              ok
io.containerd.grpc.v1           diff                     -              ok
io.containerd.grpc.v1           events                   -              ok
io.containerd.grpc.v1           healthcheck              -              ok
io.containerd.grpc.v1           images                   -              ok
io.containerd.grpc.v1           leases                   -              ok
io.containerd.grpc.v1           namespaces               -              ok
io.containerd.internal.v1       opt                      -              ok
io.containerd.grpc.v1           snapshots                -              ok
io.containerd.grpc.v1           tasks                    -              ok
io.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/

退出移动版