| --- | |
| title: Docker Engine managed plugin system | |
| linkTitle: Docker Engine plugins | |
| description: Develop and use a plugin with the managed plugin system | |
| keywords: "API, Usage, plugins, documentation, developer" | |
| aliases: | |
| - "/engine/extend/plugins_graphdriver/" | |
| --- | |
| - [Installing and using a plugin](index.md#installing-and-using-a-plugin) | |
| - [Developing a plugin](index.md#developing-a-plugin) | |
| - [Debugging plugins](index.md#debugging-plugins) | |
| Docker Engine's plugin system lets you install, start, stop, and remove | |
| plugins using Docker Engine. | |
| For information about legacy (non-managed) plugins, refer to | |
| [Understand legacy Docker Engine plugins](legacy_plugins.md). | |
| > [!NOTE] | |
| > Docker Engine managed plugins are currently not supported on Windows daemons. | |
| ## Installing and using a plugin | |
| Plugins are distributed as Docker images and can be hosted on Docker Hub or on | |
| a private registry. | |
| To install a plugin, use the `docker plugin install` command, which pulls the | |
| plugin from Docker Hub or your private registry, prompts you to grant | |
| permissions or capabilities if necessary, and enables the plugin. | |
| To check the status of installed plugins, use the `docker plugin ls` command. | |
| Plugins that start successfully are listed as enabled in the output. | |
| After a plugin is installed, you can use it as an option for another Docker | |
| operation, such as creating a volume. | |
| In the following example, you install the [`rclone` plugin](https://rclone.org/docker/), verify that it is | |
| enabled, and use it to create a volume. | |
| > [!NOTE] | |
| > This example is intended for instructional purposes only. | |
| 1. Set up the pre-requisite directories. By default they must exist on the host at the following locations: | |
| - `/var/lib/docker-plugins/rclone/config`. Reserved for the `rclone.conf` config file and must exist even if it's empty and the config file is not present. | |
| - `/var/lib/docker-plugins/rclone/cache`. Holds the plugin state file as well as optional VFS caches. | |
| 2. Install the `rclone` plugin. | |
| ```console | |
| $ docker plugin install rclone/docker-volume-rclone --alias rclone | |
| Plugin "rclone/docker-volume-rclone" is requesting the following privileges: | |
| - network: [host] | |
| - mount: [/var/lib/docker-plugins/rclone/config] | |
| - mount: [/var/lib/docker-plugins/rclone/cache] | |
| - device: [/dev/fuse] | |
| - capabilities: [CAP_SYS_ADMIN] | |
| Do you grant the above permissions? [y/N] | |
| ``` | |
| The plugin requests 5 privileges: | |
| - It needs access to the `host` network. | |
| - Access to pre-requisite directories to mount to store: | |
| - Your Rclone config files | |
| - Temporary cache data | |
| - Gives access to the FUSE (Filesystem in Userspace) device. This is required because Rclone uses FUSE to mount remote storage as if it were a local filesystem. | |
| - It needs the `CAP_SYS_ADMIN` capability, which allows the plugin to run | |
| the `mount` command. | |
| 2. Check that the plugin is enabled in the output of `docker plugin ls`. | |
| ```console | |
| $ docker plugin ls | |
| ID NAME DESCRIPTION ENABLED | |
| aede66158353 rclone:latest Rclone volume plugin for Docker true | |
| ``` | |
| 3. Create a volume using the plugin. | |
| This example mounts the `/remote` directory on host `1.2.3.4` into a | |
| volume named `rclonevolume`. | |
| This volume can now be mounted into containers. | |
| ```console | |
| $ docker volume create \ | |
| -d rclone \ | |
| --name rclonevolume \ | |
| -o type=sftp \ | |
| -o path=remote \ | |
| -o sftp-host=1.2.3.4 \ | |
| -o sftp-user=user \ | |
| -o "sftp-password=$(cat file_containing_password_for_remote_host)" | |
| ``` | |
| 4. Verify that the volume was created successfully. | |
| ```console | |
| $ docker volume ls | |
| DRIVER NAME | |
| rclone rclonevolume | |
| ``` | |
| 5. Start a container that uses the volume `rclonevolume`. | |
| ```console | |
| $ docker run --rm -v rclonevolume:/data busybox ls /data | |
| <content of /remote on machine 1.2.3.4> | |
| ``` | |
| 6. Remove the volume `rclonevolume` | |
| ```console | |
| $ docker volume rm rclonevolume | |
| sshvolume | |
| ``` | |
| To disable a plugin, use the `docker plugin disable` command. To completely | |
| remove it, use the `docker plugin remove` command. For other available | |
| commands and options, see the | |
| [command line reference](https://docs.docker.com/reference/cli/docker/). | |
| ## Developing a plugin | |
| #### The rootfs directory | |
| The `rootfs` directory represents the root filesystem of the plugin. In this | |
| example, it was created from a Dockerfile: | |
| > [!NOTE] | |
| > The `/run/docker/plugins` directory is mandatory inside of the | |
| > plugin's filesystem for Docker to communicate with the plugin. | |
| ```console | |
| $ git clone https://github.com/vieux/docker-volume-sshfs | |
| $ cd docker-volume-sshfs | |
| $ docker build -t rootfsimage . | |
| $ id=$(docker create rootfsimage true) # id was cd851ce43a403 when the image was created | |
| $ sudo mkdir -p myplugin/rootfs | |
| $ sudo docker export "$id" | sudo tar -x -C myplugin/rootfs | |
| $ docker rm -vf "$id" | |
| $ docker rmi rootfsimage | |
| ``` | |
| #### The config.json file | |
| The `config.json` file describes the plugin. See the [plugins config reference](config.md). | |
| Consider the following `config.json` file. | |
| ```json | |
| { | |
| "description": "sshFS plugin for Docker", | |
| "documentation": "https://docs.docker.com/engine/extend/plugins/", | |
| "entrypoint": ["/docker-volume-sshfs"], | |
| "network": { | |
| "type": "host" | |
| }, | |
| "interface": { | |
| "types": ["docker.volumedriver/1.0"], | |
| "socket": "sshfs.sock" | |
| }, | |
| "linux": { | |
| "capabilities": ["CAP_SYS_ADMIN"] | |
| } | |
| } | |
| ``` | |
| This plugin is a volume driver. It requires a `host` network and the | |
| `CAP_SYS_ADMIN` capability. It depends upon the `/docker-volume-sshfs` | |
| entrypoint and uses the `/run/docker/plugins/sshfs.sock` socket to communicate | |
| with Docker Engine. This plugin has no runtime parameters. | |
| #### Creating the plugin | |
| A new plugin can be created by running | |
| `docker plugin create <plugin-name> ./path/to/plugin/data` where the plugin | |
| data contains a plugin configuration file `config.json` and a root filesystem | |
| in subdirectory `rootfs`. | |
| After that the plugin `<plugin-name>` will show up in `docker plugin ls`. | |
| Plugins can be pushed to remote registries with | |
| `docker plugin push <plugin-name>`. | |
| ## Debugging plugins | |
| Stdout of a plugin is redirected to dockerd logs. Such entries have a | |
| `plugin=<ID>` suffix. Here are a few examples of commands for pluginID | |
| `f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62` and their | |
| corresponding log entries in the docker daemon logs. | |
| ```console | |
| $ docker plugin install tiborvass/sample-volume-plugin | |
| INFO[0036] Starting... Found 0 volumes on startup plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| ``` | |
| ```console | |
| $ docker volume create -d tiborvass/sample-volume-plugin samplevol | |
| INFO[0193] Create Called... Ensuring directory /data/samplevol exists on host... plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| INFO[0193] open /var/lib/docker/plugin-data/local-persist.json: no such file or directory plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| INFO[0193] Created volume samplevol with mountpoint /data/samplevol plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| INFO[0193] Path Called... Returned path /data/samplevol plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| ``` | |
| ```console | |
| $ docker run -v samplevol:/tmp busybox sh | |
| INFO[0421] Get Called... Found samplevol plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| INFO[0421] Mount Called... Mounted samplevol plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| INFO[0421] Path Called... Returned path /data/samplevol plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| INFO[0421] Unmount Called... Unmounted samplevol plugin=f52a3df433b9aceee436eaada0752f5797aab1de47e5485f1690a073b860ff62 | |
| ``` | |
| #### Using runc to obtain logfiles and shell into the plugin. | |
| Use `runc`, the default docker container runtime, for debugging plugins by | |
| collecting plugin logs redirected to a file. | |
| ```console | |
| $ sudo runc --root /run/docker/runtime-runc/plugins.moby list | |
| ID PID STATUS BUNDLE CREATED OWNER | |
| 93f1e7dbfe11c938782c2993628c895cf28e2274072c4a346a6002446c949b25 15806 running /run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby-plugins/93f1e7dbfe11c938782c2993628c895cf28e2274072c4a346a6002446c949b25 2018-02-08T21:40:08.621358213Z root | |
| 9b4606d84e06b56df84fadf054a21374b247941c94ce405b0a261499d689d9c9 14992 running /run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby-plugins/9b4606d84e06b56df84fadf054a21374b247941c94ce405b0a261499d689d9c9 2018-02-08T21:35:12.321325872Z root | |
| c5bb4b90941efcaccca999439ed06d6a6affdde7081bb34dc84126b57b3e793d 14984 running /run/docker/containerd/daemon/io.containerd.runtime.v1.linux/moby-plugins/c5bb4b90941efcaccca999439ed06d6a6affdde7081bb34dc84126b57b3e793d 2018-02-08T21:35:12.321288966Z root | |
| ``` | |
| ```console | |
| $ sudo runc --root /run/docker/runtime-runc/plugins.moby exec 93f1e7dbfe11c938782c2993628c895cf28e2274072c4a346a6002446c949b25 cat /var/log/plugin.log | |
| ``` | |
| If the plugin has a built-in shell, then exec into the plugin can be done as | |
| follows: | |
| ```console | |
| $ sudo runc --root /run/docker/runtime-runc/plugins.moby exec -t 93f1e7dbfe11c938782c2993628c895cf28e2274072c4a346a6002446c949b25 sh | |
| ``` | |
| #### Using curl to debug plugin socket issues. | |
| To verify if the plugin API socket that the docker daemon communicates with | |
| is responsive, use curl. In this example, we will make API calls from the | |
| docker host to volume and network plugins using curl 7.47.0 to ensure that | |
| the plugin is listening on the said socket. For a well functioning plugin, | |
| these basic requests should work. Note that plugin sockets are available on the host under `/var/run/docker/plugins/<pluginID>` | |
| ```console | |
| $ curl -H "Content-Type: application/json" -XPOST -d '{}' --unix-socket /var/run/docker/plugins/e8a37ba56fc879c991f7d7921901723c64df6b42b87e6a0b055771ecf8477a6d/plugin.sock http:/VolumeDriver.List | |
| {"Mountpoint":"","Err":"","Volumes":[{"Name":"myvol1","Mountpoint":"/data/myvol1"},{"Name":"myvol2","Mountpoint":"/data/myvol2"}],"Volume":null} | |
| ``` | |
| ```console | |
| $ curl -H "Content-Type: application/json" -XPOST -d '{}' --unix-socket /var/run/docker/plugins/45e00a7ce6185d6e365904c8bcf62eb724b1fe307e0d4e7ecc9f6c1eb7bcdb70/plugin.sock http:/NetworkDriver.GetCapabilities | |
| {"Scope":"local"} | |
| ``` | |
| When using curl 7.5 and above, the URL should be of the form | |
| `http://hostname/APICall`, where `hostname` is the valid hostname where the | |
| plugin is installed and `APICall` is the call to the plugin API. | |
| For example, `http://localhost/VolumeDriver.List` |