Understanding a plugin

So far, we have established that all the plugins that we have installed have actually nothing to do with Docker directly, so what does a plugin do?

Docker describes a plugin as:

"Docker plugins are out-of-process extensions which add capabilities to the Docker Engine."

This is exactly what we have seen when installing third-party tools, they all run alongside Docker as separate daemons.

Let's assume that we are going to be creating a volume plugin called mobyfs for the remainder of this chapter. The mobyfs plugin is a fictional service which is written in Go and it runs as a daemon.

Discovery

Typically, a plugin will be installed on the same host as the Docker binary. We can register our mobyfs plugin with Docker by creating the following files in either /run/docker/plugins if it's a Unix socket file, or /etc/docker/plugins or /usr/lib/docker/plugins if it is one of the other two files:

  • mobyfs.sock
  • mobyfs.spec
  • mobyfs.json

Plugins that use a Unix socket file must run on the same hosts as your Docker installation. Ones which use either a .spec or .json file can run on external hosts if your daemon supports TCP connections.

If you were using a .spec file, your file would just contain a single URL to either a TCP host and port or local socket file. Any of the following three examples are valid:

tcp://192.168.1.1:8080
tcp://localhost:8080
unix:///other.sock

If you wanted to use a .json file, it must look something similar to the following code:

{
  "Name": "mobyfs",
  "Addr": "https:// 192.168.1.1:8080",
  "TLSConfig": {
    "InsecureSkipVerify": false,
    "CAFile": "/usr/shared/docker/certs/example-ca.pem",
    "CertFile": "/usr/shared/docker/certs/example-cert.pem",
    "KeyFile": "/usr/shared/docker/certs/example-key.pem",
  }
}

The TLSConfig section of the JSON file is optional; however, if you are running your service on host other than your Docker host, I would recommend using HTTPS for communication between Docker and your plugin.

Startup order

Ideally, your plugin service should be started before Docker. If you are running a host, which has systemd installed, this can be achieved by using a systemd service file similar to the following one, which should be called mobyfs.service:

[Unit]
Description= mobyfs
Before=docker.service

[Service]
EnvironmentFile=/etc/mobyfs/mobyfs.env
ExecStart=/usr/bin/mobyfs start -p 8080
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process

[Install]
WantedBy=docker.service

This will ensure that your plugin service is always started before the main Docker service.

If you are hosting your Plugin service on an external host, you may have to restart Docker for Docker to start communicating with your plugin service.

It is possible to package your plugin inside a container. To get around Docker having to be started before the plugin service, each activation request will retry several times over 30 seconds.

This will give the container enough time to start and to run the plugin service run though any bootstrapping processes before binding itself to a port on the container.

Activation

Now that the plugin service has started, and we need to let Docker know where it should send requests to if the plugin service is called. According to our example, service is a volume plugin and we should run something similar to the following command:

docker run -ti -v volumename:/data --volume-driver=mobyfs russmckendrick/base bash

This will mount the volumename volume, which we have already configured in our plugin service to /data in a container, which runs my base container image and attaches us to a shell.

When the mobyfs volume driver is called, Docker will search through the three plugin directories that we covered in the Discovery section. By default, Docker will always look for a socket file, then either a .spec or .json file. The plugin name must match the filename in front of the file extension. If it is doesn't, the plugin will not be recognized by Docker.

API calls

Once the plugin has been called, the Docker daemon will make a post request using RPC-style JSON over HTTP to the plugin service using either the socket file or the URL defined in the .spec or .json file.

This means that your plugin service must implement an HTTP server and bind itself to the socket or port that you defined in the Discovery section.

The first request that is made by Docker will be to /Plugin.Activate. Your plugin service must respond to one of three responses. As mobyfs is a volume plugin, the response would be as follows:

{
    "Implements": ["VolumeDriver"]
}

If it was a network driver, then the response our plugin service should give would be as follows:

{
    "Implements": ["NetworkDriver"]
}

The final response of plugin service is as shown in the following code:

{
    "Implements": ["authz"]
}

Any other responses will be rejected and the activation will fail. Now that Docker has activated the plugin, it will continue to make post requests to the plugin service depending on the response it got when calling /Plugin.Activate.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset