| # Plugin Registration Service |
| |
| This folder contains a utility, pluginwatcher, for Kubelet to register |
| different types of node-level plugins such as device plugins or CSI plugins. |
| It discovers plugins by monitoring inotify events under the directory returned by |
| kubelet.getPluginsDir(). We will refer to this directory as PluginsDir. |
| |
| Plugins are expected to implement the gRPC registration service specified in |
| pkg/kubelet/apis/pluginregistration/v*/api.proto. |
| |
| ## Plugin Discovery |
| |
| The pluginwatcher service will discover plugins in the PluginDir when they |
| place a socket in that directory or, at Kubelet start if the socket is already |
| there. |
| |
| This socket filename should not start with a '.' as it will be ignored. |
| |
| |
| ## gRPC Service Lifecycle |
| |
| For any discovered plugin, kubelet will issue a Registration.GetInfo gRPC call |
| to get plugin type, name, endpoint and supported service API versions. |
| |
| If any of the following steps in registration fails, on retry registration will |
| start from scratch: |
| - Registration.GetInfo is called against socket. |
| - Validate is called against internal plugin type handler. |
| - Register is called against internal plugin type handler. |
| - NotifyRegistrationStatus is called against socket to indicate registration result. |
| |
| During plugin initialization phase, Kubelet will issue Plugin specific calls |
| (e.g: DevicePlugin::GetDevicePluginOptions). |
| |
| Once Kubelet determines that it is ready to use your plugin it will issue a |
| Registration.NotifyRegistrationStatus gRPC call. |
| |
| If the plugin removes its socket from the PluginDir this will be interpreted |
| as a plugin Deregistration. If any of the following steps in deregistration fails, |
| on retry deregistration will start from scratch: |
| - Registration.GetInfo is called against socket. |
| - DeRegisterPlugin is called against internal plugin type handler. |
| |
| |
| ## gRPC Service Overview |
| |
| Here are the general rules that Kubelet plugin developers should follow: |
| - Run plugin as 'root' user. Currently creating socket under PluginsDir, a root owned |
| directory, requires plugin process to be running as 'root'. |
| |
| - The plugin name sent during Registration.GetInfo grpc should be unique |
| for the given plugin type (CSIPlugin or DevicePlugin). |
| |
| - The socket path needs to be unique within one directory, in normal case, |
| each plugin type has its own sub directory, but the design does support socket file |
| under any sub directory of PluginSockDir. |
| |
| - A plugin should clean up its own socket upon exiting or when a new instance |
| comes up. A plugin should NOT remove any sockets belonging to other plugins. |
| |
| - A plugin should make sure it has service ready for any supported service API |
| version listed in the PluginInfo. |
| |
| - For an example plugin implementation, take a look at example_plugin.go |
| included in this directory. |
| |
| |
| # Kubelet Interface |
| |
| For any kubelet components using the pluginwatcher module, you will need to |
| implement the PluginHandler interface defined in the types.go file. |
| |
| The interface is documented and the implementations are registered with the |
| pluginwatcher module in kubelet.go by calling AddHandler(pluginType, handler). |
| |
| |
| The lifecycle follows a simple state machine: |
| |
| Validate -> Register -> DeRegister |
| ^ + |
| | | |
| +--------- + |
| |
| The pluginwatcher calls the functions with the received plugin name, supported |
| service API versions and the endpoint to call the plugin on. |
| |
| The Kubelet component that receives this callback can acknowledge or reject |
| the plugin according to its own logic, and use the socket path to establish |
| its service communication with any API version supported by the plugin. |