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-builderAnd change inside the new directory:
$ cd /opt/yocto/docker-yocto-builderTo 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-builderWhere:
-itinstructs Docker to keepstdinopen even when the container is not attached and assign apseudo-ttyto the interactive shell--rminstructs Docker to remove the container on exit-vmaps the host current directory as the/home/buildcontainer 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/buildcontainer directory with the current directory as thesetup-environmentscript only works when the build directory is under theinstallationfolder:
$ 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 forRUNandCMDinstructions following itWORKDIR, which sets the working directory forRUNandCMDinstructions 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
builduser - 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/