|
| 1 | +# NRI Support In Containerd |
| 2 | + |
| 3 | +## Node Resource Interface |
| 4 | + |
| 5 | +NRI, the Node Resource Interface, is a common framework for plugging |
| 6 | +extensions into OCI-compatible container runtimes. It provides basic |
| 7 | +mechanisms for plugins to track the state of containers and to make |
| 8 | +limited changes to their configuration. |
| 9 | + |
| 10 | +NRI itself is agnostic to the internal implementation details of any |
| 11 | +container runtime. It provides an adaptation library which runtimes |
| 12 | +use to integrate to and interact with NRI and plugins. In principle |
| 13 | +any NRI plugin should be able to work with NRI-enabled runtimes. |
| 14 | + |
| 15 | +For a detailed description of NRI and its capabilities please take a |
| 16 | +look at the [NRI respository](https://github.com/containerd/nri). |
| 17 | + |
| 18 | +## Containerd NRI Integration |
| 19 | + |
| 20 | +<details> |
| 21 | +<summary>see the containerd/NRI integration diagram</summary> |
| 22 | +<img src="./containerd-nri-integration.png" title="Containerd/NRI Integration"> |
| 23 | +</details> |
| 24 | + |
| 25 | +NRI support in containerd is split into two parts both logically and |
| 26 | +physically. These parts are a common plugin (/nri/*) to integrate to |
| 27 | +NRI and CRI-specific bits (/pkg/cri/server/nri-api) which convert |
| 28 | +data between the runtime-agnostic NRI representation and the internal |
| 29 | +representation of the CRI plugin. |
| 30 | + |
| 31 | +### Containerd NRI Plugin |
| 32 | + |
| 33 | +The containerd common NRI plugin implements the core logic of integrating |
| 34 | +to and interacting with NRI. However, it does this without any knowledge |
| 35 | +about the internal representation of containers or pods within containerd. |
| 36 | +It defines an additional interface, Domain, which is used whenever the |
| 37 | +internal representation of a container or pod needs to be translated to |
| 38 | +the runtime agnostic NRI one, or when a configuration change requested by |
| 39 | +an external NRI plugin needs to be applied to a container within containerd. `Domain` can be considered as a short-cut name for Domain-Namespace as Domain implements the functions the generic NRI interface needs to deal with pods and containers from a particular containerd namespace. As a reminder, containerd namespaces isolate state between clients of containerd. E.g. "k8s.io" for the kubernetes CRI clients, "moby" for docker clients, ... and "containerd" as the default for containerd/ctr. |
| 40 | + |
| 41 | +### NRI Support for CRI Containers |
| 42 | + |
| 43 | +The containerd CRI plugin registers itself as an above mentioned NRI |
| 44 | +Domain for the "k8s.io" namespace, to allow container configuration to be customized by external |
| 45 | +NRI plugins. Currently this Domain interface is only implemented for |
| 46 | +the original CRI `pkg/cri/server` implementation. Implementing it for |
| 47 | +the more recent experimental `pkg/cri/sbserver` implementation is on |
| 48 | +the TODO list. |
| 49 | + |
| 50 | +### NRI Support for Other Container 'Domains' |
| 51 | + |
| 52 | +The main reason for this split of functionality is to allow |
| 53 | + NRI plugins for other types of sandboxes and for other container clients other than just for CRI containers in the "k8s.io" namespace. |
| 54 | + |
| 55 | +## Enabling NRI Support in Containerd |
| 56 | + |
| 57 | +Enabling and disabling NRI support in containerd happens by enabling or |
| 58 | +disabling the common containerd NRI plugin. The plugin, and consequently |
| 59 | +NRI functionality, is disabled by default. It can be enabled by editing |
| 60 | +the `[plugins."io.containerd.nri.v1.nri"]` section in the containerd |
| 61 | +configuration file, which by default is `/etc/containerd/config.toml`, |
| 62 | +and changing `disable = true` to `disable = false`. Once enabled, the |
| 63 | +NRI section should look something like this: |
| 64 | + |
| 65 | +```toml |
| 66 | + [plugins."io.containerd.nri.v1.nri"] |
| 67 | + config_file = "/etc/nri/nri.conf" |
| 68 | + disable = false |
| 69 | + plugin_path = "/opt/nri/plugins" |
| 70 | + socket_path = "/var/run/nri.sock" |
| 71 | +``` |
| 72 | + |
| 73 | +In addition to this, you need to put a runtime agnostic NRI configuration |
| 74 | +file in place, to let NRI itself know that it is enabled. You can do this |
| 75 | +by creating `/etc/nri/nri.conf` with the following content: |
| 76 | + |
| 77 | +```yaml |
| 78 | +disableConnections: false |
| 79 | +``` |
| 80 | +
|
| 81 | +This enables externally launched NRI plugins to connect and register |
| 82 | +themselves. |
| 83 | +
|
| 84 | +There are two ways how an NRI plugin can be started. Plugins can be |
| 85 | +pre-registered in which case they are automatically started when the NRI |
| 86 | +adaptation is instantiated (or in our case when containerd is started). |
| 87 | +Plugins can also be started by external means, for instance by systemd. |
| 88 | +
|
| 89 | +Pre-registering a plugin happens by placing a symbolic link to the plugin |
| 90 | +executable into a well-known NRI-specific directory, `/opt/nri/plugins` |
| 91 | +by default. A pre-registered plugin is started with a socket pre-connected |
| 92 | +to NRI. Externally launched plugins connect to a well-known NRI-specific |
| 93 | +socket, `/var/run/nri.sock` by default, to register themselves. The only |
| 94 | +difference between pre-registered and externally launched plugins is how |
| 95 | +they get started and connected to NRI. Once a connection is established |
| 96 | +all plugins are identical. |
| 97 | + |
| 98 | +NRI can be configured to disable connections from externally launched |
| 99 | +plugins, in which case the well-known socket is not created at all. The |
| 100 | +configuration fragment shown above ensures that external connections are |
| 101 | +enabled regardless of the built-in NRI defaults. This is convenient for |
| 102 | +testing as it allows one to connect, disconnect and reconnect plugins at |
| 103 | +any time. |
| 104 | + |
| 105 | +For more details about pre-registered and externally launched plugins |
| 106 | + |
| 107 | +## Testing NRI Support in Containerd |
| 108 | + |
| 109 | +You can verify that NRI integration is properly enabled and functional by |
| 110 | +configuring containerd and NRI as described above, taking the NRI |
| 111 | +logger plugin either from the NRI repository or |
| 112 | +[this fork](https://github.com/klihub/nri/tree/pr/proto/draft/plugins/logger) |
| 113 | +on github, compiling it and starting it up. |
| 114 | + |
| 115 | +```bash |
| 116 | +git clone https://github.com/klihub/nri |
| 117 | +cd nri |
| 118 | +git checkout pr/proto/draft |
| 119 | +make |
| 120 | +./build/bin/logger -idx 00 |
| 121 | +``` |
| 122 | + |
| 123 | +You should see the logger plugin receiving receiving a list of existing pods |
| 124 | +and containers. If you then create or remove further pods and containers |
| 125 | +using crictl or kubectl you should see detailed logs of the corresponding NRI |
| 126 | +events printed by the logger. |
| 127 | + |
| 128 | +## NRI Compatibility With v0.1.0 Plugins |
| 129 | + |
| 130 | +You can enable backward compatibility with NRI v0.1.0 plugins using the |
| 131 | +[v010-adapter plugin](https://github.com/klihub/nri/tree/pr/proto/draft/plugins/v010-adapter). |
| 132 | + |
| 133 | +```bash |
| 134 | +git clone https://github.com/klihub/nri |
| 135 | +cd nri |
| 136 | +git checkout pr/proto/draft |
| 137 | +make |
| 138 | +sudo cp build/bin/v010-adapter /usr/local/bin |
| 139 | +sudo mkdir -p /opt/nri/plugins |
| 140 | +sudo ln -s /usr/local/bin/v010-adapter /opt/nri/plugins/00-v010-adapter |
| 141 | +``` |
0 commit comments