Using Docker as a Yocto build system container
Embedded systems often have a long product lifetime so software needs to be built with the same Yocto version over several years in a predictable way. Older versions of Yocto often have problems in running with state-of-the-art distributions.
To work around this, there are several alternatives:
- Keep a build machine with a fixed operating system. This is problematic as the machine also ages and it may suffer from hardware problems and need re-installation.
- Use a cloud machine with a fixed operating system. Not everyone has this type of infrastructure available and it usually has a price tag attached.
- Build in a virtual machine such as VMware or VirtualBox. This affects the build performance significantly.
- Use a Docker Yocto builder container. This has the advantage of providing the same isolation as the virtual machine but with a much better build performance.
We saw how to run a docker
container in the Using the Toaster web interface recipe. Now we will see how to create our own Docker image to use as a Yocto builder.
Getting ready
Docker is able to build images automatically by reading instructions from a text file called a Dockerfile
. Dockerfiles can be layered on top of each other, so to create a Docker Yocto builder image we would start by using a Ubuntu 16.04 Docker image or one of the other supported distributions, and sequentially configure the image.
An example Dockerfile
for a Yocto builder follows:
FROM ubuntu:16.04 MAINTAINER Alex Gonzalez <[email protected]> # Upgrade system and Yocto Proyect basic dependencies RUN apt-get update && apt-get -y upgrade && apt-get -y install gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping libsdl1.2-dev xterm curl # Set up locales RUN apt-get -y install locales apt-utils sudo && dpkg-reconfigure locales && locale-gen en_US.UTF-8 && update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 ENV LANG en_US.utf8 # Clean up APT when done. RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* # Replace dash with bash RUN rm /bin/sh && ln -s bash /bin/sh # User management RUN groupadd -g 1000 build && useradd -u 1000 -g 1000 -ms /bin/bash build && usermod -a -G sudo build && usermod -a -G users build # Install repo RUN curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo && chmod a+x /usr/local/bin/repo # Run as build user from the installation path ENV YOCTO_INSTALL_PATH "/opt/yocto" RUN install -o 1000 -g 1000 -d $YOCTO_INSTALL_PATH USER build WORKDIR ${YOCTO_INSTALL_PATH} # Set the Yocto release ENV YOCTO_RELEASE "rocko" # Install Poky RUN git clone --branch ${YOCTO_RELEASE} git://git.yoctoproject.org/poky # Install FSL community BSP RUN mkdir -p ${YOCTO_INSTALL_PATH}/fsl-community-bsp && cd ${YOCTO_INSTALL_PATH}/fsl-community-bsp && repo init -u https://github.com/Freescale/fsl-community-bsp-platform -b ${YOCTO_RELEASE} && repo sync # Create a build directory for the FSL community BSP RUN mkdir -p ${YOCTO_INSTALL_PATH}/fsl-community-bsp/build # Make /home/build the working directory WORKDIR /home/build
How to do it...
- To build the container locally from the directory containing the Dockerfile, run the following command:
$ docker build
- However, there is no need to build it locally as the container is automatically built on the Docker registry: https://hub.docker.com/r/yoctocookbook2ndedition/docker-yocto-builder
First create an empty folder owned by a user with the same uid and gid that the build
user inside the container:
$ sudo install -o 1000 -g 1000 -d /opt/yocto/docker-yocto-builder
And change inside the new directory:
$ cd /opt/yocto/docker-yocto-builder
To run the container and map its /home/build
folder to the current directory, type:
$ docker run -it --rm -v $PWD:/home/build yoctocookbook2ndedition/docker-yocto-builder
Where:
-it
instructs Docker to keepstdin
open even when the container is not attached and assign apseudo-tty
to the interactive shell--rm
instructs Docker to remove the container on exit-v
maps the host current directory as the/home/build
container volume
- We can now instruct the container to build a Poky project with:
build@container$ source /opt/yocto/poky/oe-init-build-env qemuarmbuild@container$ MACHINE=qemuarm bitbake core-image-minimal
- To build a FSL community BSP project, you need to map the
/opt/yocto/fsl-community-bsp/build
container directory with the current directory as thesetup-environment
script only works when the build directory is under theinstallation
folder:
$ docker run -it --rm -v $PWD:/opt/yocto/fsl-community-bsp/build yoctocookbook2ndedition/docker-yocto-builder
- Then we can run the following command inside the container to create a new project and start a build:
build@container$ cd /opt/yocto/fsl-community-bsp/build@container$ mkdir -p wandboardbuild@container$ MACHINE=wandboard DISTRO=poky source setup-environment buildbuild@container$ bitbake core-image-minimal
How it works...
Instructing Docker to start the image creation process with a Ubuntu 16.04 image is as easy as starting the Dockerfile
with the following:
FROM ubuntu:16.04
To inherit a Docker image, you use the Dockerfile FROM
syntax.
Other commands used in the Dockerfile are:
RUN
, which will run the specified command in a new layer and commit the resultENV
, to set an environmental variableUSER
, which sets the username to use forRUN
andCMD
instructions following itWORKDIR
, which sets the working directory forRUN
andCMD
instructions that follow itCMD
, which provides the default executable for the container, in this case the Bash shell
The rest of the Dockerfile
does the following:
- Updates Ubuntu 16.04 to the latest packages
- Installs Yocto dependencies
- Sets up the locale for the container
- Adds a new
build
user - Installs both Poky and the FSL community BSP release
The image has Poky installed at /opt/yocto/poky
and the FSL community BSP installed at /opt/yocto/fsl-community-bsp
. When it starts, the default directory is/home/build
.
The usual way to work with a docker
container is to instruct it to run commands but store the output in the host filesystem.
In our case, we instruct the container to run BitBake for us, but we map the build directories to the host by doing the external volume mapping when the container is initialized. In that way, all the build output is stored on the host machine.
See also
- Docker documentation for the image builder can be found at https://docs.docker.com/engine/reference/builder/