containerd 支持使用它定义的接口,扩展功能。这包括使用自定义的运行时,快照,content 存储,甚至增加 gRPC 接口。
Smart Client Model
containerd 有一个智能的 client 架构,意思是着 deamon 不需要的任何功能都是被 client 完成的。这包括最高级的交互,例如创建一个容器规范,与镜像源交互或者从 tar 中载入一个镜像。 containerd 的 Go client 允许用户访问很多扩展点,从创建他们自己的容器选项到解析镜像源名称。
详情 containerd’s Go documentation。
External Plugins
External Plugins 允许使用官方的 containerd 发行版本扩展功能,不需要从新编译守护进程来添加 Plugin。
containerd 允许通过下面两种办法扩展
- 通过在 containerd 的 Path 中,使用可用的二进制文件
- 通过配置 containerd 来代理给其他 gRPC 服务
V2 Runtimes
V2 runtime 接口允许解析 runtimes 到二进制文件。这些二进制被用来启动 shim 进程,允许 containerd 来控制这些 containers 使用二进制提供的 runtime shim api。
Proxy Plugins
代理插件使用 containerd 的配置文件进行配置,并在 containerd 启动时与内部插件一起加载。 这些插件使用本地套接字连接到 containerd,该套接字为 containerd 的 gRPC API 服务之一提供服务。 每个插件都配置有类型和名称,就像内部插件一样。
Configuration
containerd 配置默认在 /etc/containerd/config.toml,添加 [proxy_plugins] 和你的 Plugin [proxy_plugins.myplugin], address 必须引用 containerd 有权访问的本地 socket 文件。目前支持的类型是 snapshot 和 content
[proxy_plugins][proxy_plugins.customsnapshot]type = "snapshot"address = "/var/run/mysnapshotter.sock"
Implementation
实现一个 proxy plugin 与实现一个 gRPC API 一样容易。如果要使用 Go 实现 proxy plugin,参考 content store service 和 snapshotter service.
下面的例子是创建一个快照 plugin,可以被用于任何 containerd’s Snapshotter interface 实现。
package mainimport ("fmt""net""os""google.golang.org/grpc"snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1""github.com/containerd/containerd/contrib/snapshotservice""github.com/containerd/containerd/snapshots/native")func main() {// Provide a unix address to listen to, this will be the `address`// in the `proxy_plugin` configuration.// The root will be used to store the snapshots.if len(os.Args) < 3 {fmt.Printf("invalid args: usage: %s <unix addr> <root>\n", os.Args[0])os.Exit(1)}// Create a gRPC serverrpc := grpc.NewServer()// Configure your custom snapshotter, this example uses the native// snapshotter and a root directory. Your custom snapshotter will be// much more useful than using a snapshotter which is already included.// https://godoc.org/github.com/containerd/containerd/snapshots#Snapshottersn, err := native.NewSnapshotter(os.Args[2])if err != nil {fmt.Printf("error: %v\n", err)os.Exit(1)}// Convert the snapshotter to a gRPC service,// example in github.com/containerd/containerd/contrib/snapshotserviceservice := snapshotservice.FromSnapshotter(sn)// Register the service with the gRPC serversnapshotsapi.RegisterSnapshotsServer(rpc, service)// Listen and servel, err := net.Listen("unix", os.Args[1])if err != nil {fmt.Printf("error: %v\n", err)os.Exit(1)}if err := rpc.Serve(l); err != nil {fmt.Printf("error: %v\n", err)os.Exit(1)}}
使用先前的配置和用例,运行一个快照 plugin
# Start plugin in one terminal$ go run ./main.go /var/run/mysnapshotter.sock /tmp/snapshots# Use ctr in another$ CONTAINERD_SNAPSHOTTER=customsnapshot ctr images pull docker.io/library/alpine:latest$ tree -L 3 /tmp/snapshots/tmp/snapshots|-- metadata.db`-- snapshots`-- 1|-- bin|-- dev|-- etc|-- home|-- lib|-- media|-- mnt|-- proc|-- root|-- run|-- sbin|-- srv|-- sys|-- tmp|-- usr`-- var18 directories, 1 file
Built-in Plugins
containerd 内部使用 Plugin 来确保内部实现解耦,稳定,与 external plugins 平等,查看 containerd 有的所有插件,使用 ctr plugins ls
$ ctr plugins lsTYPE ID PLATFORMS STATUSio.containerd.content.v1 content - okio.containerd.snapshotter.v1 btrfs linux/amd64 okio.containerd.snapshotter.v1 aufs 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 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.grpc.v1 snapshots - okio.containerd.grpc.v1 tasks - okio.containerd.grpc.v1 version - okio.containerd.grpc.v1 cri linux/amd64 ok
从输出里可以看到所有的 plugins,包括那些没有成功加载的。 现在 aufs 和 zfs 没有像预期一样载入,因为他们不支持本机。日志显示了为什么他会失败,但是你能够使用 -d 来获取更多细节。
$ ctr plugins ls -d id==aufs id==zfsType: io.containerd.snapshotter.v1ID: aufsPlatforms: linux/amd64Exports:root /var/lib/containerd/io.containerd.snapshotter.v1.aufsError:Code: UnknownMessage: modprobe aufs failed: "modprobe: FATAL: Module aufs not found in directory /lib/modules/4.17.2-1-ARCH\n": exit status 1Type: io.containerd.snapshotter.v1ID: zfsPlatforms: linux/amd64Exports:root /var/lib/containerd/io.containerd.snapshotter.v1.zfsError:Code: UnknownMessage: path /var/lib/containerd/io.containerd.snapshotter.v1.zfs must be a zfs filesystem to be used with the zfs snapshotter
plugin 返回的错误消息解释了它为什么没能被加载
configuration
Plugins 通过使用 containerd 配置文件中的 [plugin] 配置,每一个插件能够拥有他自己的段,通过使用 [plugins.<plugin id>]
样例配置
[plugins][plugins.cgroups]no_prometheus = false[plugins.cri]stream_server_address = ""stream_server_port = "10010"enable_selinux = falsesandbox_image = "k8s.gcr.io/pause:3.5"stats_collect_period = 10systemd_cgroup = false[plugins.cri.containerd]snapshotter = "overlayfs"[plugins.cri.containerd.default_runtime]runtime_type = "io.containerd.runtime.v1.linux"runtime_engine = ""runtime_root = ""[plugins.cri.containerd.untrusted_workload_runtime]runtime_type = ""runtime_engine = ""runtime_root = ""[plugins.cri.cni]bin_dir = "/opt/cni/bin"conf_dir = "/etc/cni/net.d"[plugins.cri.registry][plugins.cri.registry.mirrors][plugins.cri.registry.mirrors."docker.io"]endpoint = ["https://registry-1.docker.io"]
