1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296
|
# containerd Plugins
containerd supports extending its functionality using most of its defined
interfaces. This includes using a customized runtime, snapshotter, content
store, and even adding gRPC interfaces.
## Smart Client Model
containerd has a smart client architecture, meaning any functionality which is
not required by the daemon is done by the client. This includes most high
level interactions such as creating a container's specification, interacting
with an image registry, or loading an image from tar. containerd's Go client
gives a user access to many points of extensions from creating their own
options on container creation to resolving image registry names.
See [containerd's Go documentation](https://godoc.org/github.com/containerd/containerd/v2/client)
## External Plugins
External plugins allow extending containerd's functionality using an officially
released version of containerd without needing to recompile the daemon to add a
plugin.
containerd allows extensions through two methods:
- via a binary available in containerd's PATH
- by configuring containerd to proxy to another gRPC service
### V2 Runtimes
containerd supports multiple container runtimes. Each container can be
invoked with a different runtime.
When using the Container Runtime Interface (CRI) plugin, named runtimes can be defined
in the containerd configuration file. When a container is run without specifying a runtime,
the configured default runtime is used. Alternatively, a different named runtime can be
specified explicitly when creating a container via CRI gRPC by selecting the runtime handler to be used.
When a client such as `ctr` or `nerdctl` creates a container, it can optionally specify a runtime and options to use.
If a runtime is not specified, containerd will use its default runtime.
containerd invokes v2 runtimes as binaries on the system,
which are used to start the shim process for containerd. This, in turn, allows
containerd to start and manage those containers using the runtime shim api returned by
the binary.
For more details on runtimes and shims, including how to invoke and configure them,
see the [runtime v2 documentation](../core/runtime/v2/README.md)
### Proxy Plugins
A proxy plugin is configured using containerd's config file and will be loaded
alongside the internal plugins when containerd is started. These plugins are
connected to containerd using a local socket serving one of containerd's gRPC
API services. Each plugin is configured with a type and name just as internal
plugins are.
#### Configuration
Update the containerd config file, which by default is at
`/etc/containerd/config.toml`. Add a `[proxy_plugins]` section along with a
section for your given plugin `[proxy_plugins.myplugin]`. The `address` must
refer to a local socket file which the containerd process has access to. The
currently supported types are `snapshot`, `content`, and `diff`.
```toml
version = 2
[proxy_plugins]
[proxy_plugins.customsnapshot]
type = "snapshot"
address = "/var/run/mysnapshotter.sock"
```
#### Implementation
Implementing a proxy plugin is as easy as implementing the gRPC API for a
service. For implementing a proxy plugin in Go, look at the go doc for
[content store service](https://godoc.org/github.com/containerd/containerd/v2/api/services/content/v1#ContentServer), [snapshotter service](https://godoc.org/github.com/containerd/containerd/v2/api/services/snapshots/v1#SnapshotsServer), and [diff service](https://pkg.go.dev/github.com/containerd/containerd/v2/api/services/diff/v1#DiffServer).
The following example creates a snapshot plugin binary which can be used
with any implementation of
[containerd's Snapshotter interface](https://godoc.org/github.com/containerd/containerd/v2/snapshots#Snapshotter)
```go
package main
import (
"fmt"
"net"
"os"
"google.golang.org/grpc"
snapshotsapi "github.com/containerd/containerd/api/services/snapshots/v1"
"github.com/containerd/containerd/v2/contrib/snapshotservice"
"github.com/containerd/containerd/v2/plugins/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 server
rpc := 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#Snapshotter
sn, 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/snapshotservice
service := snapshotservice.FromSnapshotter(sn)
// Register the service with the gRPC server
snapshotsapi.RegisterSnapshotsServer(rpc, service)
// Listen and serve
l, 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)
}
}
```
Using the previous configuration and example, you could run a snapshot plugin
with
```
# 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
`-- var
18 directories, 1 file
```
## Built-in Plugins
containerd uses plugins internally to ensure that internal implementations are
decoupled, stable, and treated equally with external plugins. To see all the
plugins containerd has, use `ctr plugins ls`
```
$ ctr plugins ls
TYPE ID PLATFORMS STATUS
io.containerd.content.v1 content - ok
io.containerd.snapshotter.v1 btrfs linux/amd64 ok
io.containerd.snapshotter.v1 aufs 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 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.grpc.v1 snapshots - ok
io.containerd.grpc.v1 tasks - ok
io.containerd.grpc.v1 version - ok
io.containerd.grpc.v1 cri linux/amd64 ok
```
From the output all the plugins can be seen as well those which did not
successfully load. In this case `aufs` and `zfs` are expected not to load
since they are not support on the machine. The logs will show why it failed,
but you can also get more details using the `-d` option.
```
$ ctr plugins ls -d id==aufs id==zfs
Type: io.containerd.snapshotter.v1
ID: aufs
Platforms: linux/amd64
Exports:
root /var/lib/containerd/io.containerd.snapshotter.v1.aufs
Error:
Code: Unknown
Message: modprobe aufs failed: "modprobe: FATAL: Module aufs not found in directory /lib/modules/4.17.2-1-ARCH\n": exit status 1
Type: io.containerd.snapshotter.v1
ID: zfs
Platforms: linux/amd64
Exports:
root /var/lib/containerd/io.containerd.snapshotter.v1.zfs
Error:
Code: Unknown
Message: path /var/lib/containerd/io.containerd.snapshotter.v1.zfs must be a zfs filesystem to be used with the zfs snapshotter
```
The error message which the plugin returned explains why the plugin was unable
to load.
#### Configuration
Plugins are configured using the `[plugins]` section of containerd's config.
Every plugin can have its own section using the pattern `[plugins."<plugin type>.<plugin id>"]`.
example configuration
```toml
version = 2
[plugins]
[plugins."io.containerd.monitor.v1.cgroups"]
no_prometheus = false
```
To see full configuration example run `containerd config default`.
If you want to get the configuration combined with your configuration, run `containerd config dump`.
##### Version header
containerd has several configuration versions:
- Version 3 (Recommended for containerd 2.x): Introduced in containerd 2.0.
Several plugin IDs have changed in this version.
- Version 2 (Recommended for containerd 1.x): Introduced in containerd 1.3.
Still supported in containerd v2.x.
Plugin IDs are changed to have prefixes like "io.containerd.".
- Version 1: Introduced in containerd 1.0. Removed in containerd 2.0.
A configuration for Version 2 or 3 must specify the version `version = 2` or `version = 3` in the header, and must have
fully qualified plugin IDs in the `[plugins]` section:
```toml
version = 3
[plugins]
[plugins.'io.containerd.monitor.task.v1.cgroups']
no_prometheus = false
```
```toml
version = 2
[plugins]
[plugins."io.containerd.monitor.v1.cgroups"]
no_prometheus = false
```
A configuration with Version 1 may not have `version` header, and does not need fully qualified plugin IDs.
```toml
[plugins]
[plugins.cgroups]
no_prometheus = false
```
|