In this blog, we'll walk through the process of adding docker
to an already existing Yocto project step-by-step.
I don't go into detail on how to use the docker
or Yocto and I presume you know how to use and run docker
, more or less.
docker
in your embedded image in the first place anyways?Integrating docker
into an embedded Linux environment can bring significant advantages, such as simplifying application deployment and management.
We can easily and safely add more features into the image during runtime for different devices, by using specific images in the docker itself.
It might be difficult to roll out newer versions of the whole kernel for the device, when we can plug in and out specific versions of the software using the docker
runtime.
Of course, lxc
would be a better solution if you have to care about limitations on the power/size of your embedded device, but because you are reading this blog post, then I guess you are more familiar with docker
as well as the previous thing isn't a concern for you.
Let's go through all that we need to do to get to the promised land of docker
in embedded system.
First let's talk what we have:
poky
version kirkstone
(but we can use any other yocto version, as long as it is also supported for the meta-virtualization repo)docker
binary to be used in our produced imagepoky
repo (just becuase it's simpler for the example we will discuss here)meta-my-layer
layer, that implements my-docker-image
imagedocker
support is generally provided by the meta-virtualization layer. You’ll need to clone and add this layer to your Yocto build.
# Clone the meta-virtualization layer
~/repos/poky $ git clone git://git.yoctoproject.org/meta-virtualization
# Add the layer to your build configuration, edit config to include meta-virtualization
BBLAYERS ?= " \
${TOPDIR}/../meta \
${TOPDIR}/../meta-poky \
${TOPDIR}/../meta-yocto-bsp \
${TOPDIR}/../meta-virtualization \
"
docker
in the build configurationWith the layer added, you can now enable docker
support in your build.
IMAGE_INSTALL_append = " docker"
This will ensure that docker
is included in the final image.
If you use packagegroup
's to actually append stuff to the final image, you can add it to a new one or one of your current ones.
You might need to add support for certain kernel features required by docker
. Edit your build/conf/local.conf
to include:
DISTRO_FEATURES_append = " virtualization"
docker
also has specific runtime dependencies, such as cgroup support and certain kernel modules. If these features are not enabled in your kernel, you may need to enable them manually.
More on this in the Appendix
.
docker
recipe in the imageIn some cases, adding docker
to IMAGE_INSTALL_append might not be enough. You might need to explicitly include the docker
recipe in your image recipe.
DESCRIPTION = "My custom Docker-enabled image"
LICENSE = "MIT"
inherit core-image
IMAGE_FEATURES += "ssh-server"
IMAGE_INSTALL += "docker docker-contrib"
The docker-contrib package can be added for additional tools and scripts that complement the Docker setup.
With all the configuration changes in place, build your image using the following command:
~/workdir/build $ bitbake my-docker-image
This process may take some time, depending on the complexity of your setup and the hardware used. Once completed, the image will include the Docker
binary and any dependencies needed for Docker
to function.
docker
on the built imageAfter succesfully building and flashing the new image on your device (or running using qemu), you should be able now to test out the docker binary that you have included into your image.
(qemu)/ $ docker --version
(qemu)/ $ docker version
If you don't have the docker
daemon running, try getting it up.
If that fails to run, you might be running into one of the issues that are listed in the Appendix
, scroll down for some tips on how to resolve that.
You should see a message displaying the Docker version. To test Docker functionality, try running a simple container:
(qemu)/ $ docker run hello-world
This should pull the hello-world image and run it successfully, indicating that Docker is properly configured.
If you don't have network access on your device, you can also import an image and load it with docker load
command.
If you are running some problems in getting the docker
daemon working, the below might be a good load of things to make sure is correctly configured and set up so that docker
has everything it needs to handle containers.
docker
daemon with .json config file:You can create a daemon.json configuration file at /etc/docker/
on the target device to set options like:
{
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "2"
}
}
Use docker-slim
or similar tools to minimize the footprint of your Docker images, as embedded devices often have limited storage.
Ensure that your kernel is configured with the required options. Docker requires support for:
If you’re using the Yocto kernel recipes, you can modify these settings in the kernel configuration files under meta/recipes-kernel/linux/
.
You can also use this(taken from moby repository) script on the image, to check where you are with the specific kernel modules.
Ensure that the docker
daemon has correct file permissions set up. If you are using a specific cgroup docker
user, make sure he can access whatever you give it in the daemon.json
config file.
Make sure that your custom routing rules are playing nicely with the docker
rules.