Build an Ubuntu Core image for Docker deployments

Applications run on Ubuntu Core as snaps and the Docker Engine is not an exception.
To run Docker containers on a running Ubuntu Core instance, install the Docker snap and run your docker commands. You can even create a companion snap that runs the container and takes care of updates to the bundled container image.

In order to ship containerized applications together with Ubuntu Core, one needs to create a custom image. Such an image can be used to create bootable media, and can automate deployment of a production system. To create this Ubuntu Core image, the applications need to be packaged as Docker companion snaps, listed in the model assertion along with the Docker snap, and given the right permissions to operate.
The image may also include container configurations.

Start by creating a model assertion. Add the Docker snap and all other companion snaps to the list:

{
    "name": "docker",
    "type": "app",
    "default-channel": "latest/stable",
    "id": "sLCsFAO8PKM5Z0fAKNszUOX0YASjQfeZ"
},
{
    "name": "<my-companion-snap>",
    "type": "app",
    "default-channel": "<channel>",
    "id": "<snap-id>"
}

This example only lists one companion snap, available in a snap store. A single companion snap could manage multiple Docker containers.

Each companion snap needs access to the Docker snap to operate. We grant the access via snap interface connections between the snaps. In order to automate the granting of access, each companion snap must be published to a store and have an ID. There are two ways to configure this automated interface connection: via an auto-connection assertion defined in a snap store, or via a custom gadget. Here we cover the method via a custom gadget.

Read the gadget snaps documentation to get familiar with the concepts and instructions. Inside the gadget.yaml file, adapt and add the following to connections, for each companion snap:

connections:
    # Needed to communicate with Docker over the Unix socket
    - slot: sLCsFAO8PKM5Z0fAKNszUOX0YASjQfeZ:docker-daemon
      plug: <companion snap id>:docker
    # Needed to use the docker CLI
    - slot: sLCsFAO8PKM5Z0fAKNszUOX0YASjQfeZ:docker-executables
      plug: <companion snap id>:docker-executables

Container configuration can be passed on to the companion snap, via snap configuration options. To set such configurations in the Ubuntu Core image, add them to the same gadget.yaml file, under defaults:

defaults:
  <companion snap id>:
    key: value

Finally, replace the default gadget snap listed in the model assertion with the custom one that has the connections:

{
    "name": "<custom-gadget>",
    "type": "gadget",
    "default-channel": "<channel>",
    "id": "<gadget snap id>"
}

Omit default-channel and id if you want to build the image using a custom gadget snap that hasn’t been uploaded to a store.