Using Docker Containers for Reproducible Yocto Builds

Published on April 10, 2020

In this post, we want to go over some basics of using Docker Containers for Reproducible Yocto builds. This will allow for a consistent and stable build environment for building images. No matter the linux distro you are using (Ubuntu, Debian, Fedora etc.), it will produce the same result. There are many resources online for describing what Docker is and what a container is, so we will skip over that, but here are a few helpful links: https://docs.docker.com/get-started/overview/ https://docker-curriculum.com/ This blog post will focus on reproducible Yocto builds specifically.

How to use Docker?

In this example, we will be creating an Ubuntu Focal 20.04 build environment and installing all dependencies needed for our Yocto builds (both Boundary evaluation images and boot2qt images). Again, we won't cover Docker requirements and installation in this post, but here is a helpful link to get Docker setup: https://docs.docker.com/engine/install/ Assuming you have Docker and its dependencies already installed, find below our process for creating a Reproducible Yocto build:

Download our template Ubuntu Focal Docker file

The template file can be found here: dockerfile_focal Lets breakdown and explain the file a bit to give you a better understanding of the setup for the build environment. NOTE: If using yocto versions prior to version 3.3 Hardknott, you may have to use a dockerfile that uses an older Ubuntu version, such as our template dockerfile_bionic. Please refer to the yocto manual as per your yocto release to see the supported build OS's

FROM Statement

#
# Docker Focal image to build Yocto 3.3
#
FROM ubuntu:20.04

This setups a baseline image to run on the container. In this case, we start with Ubuntu Focal 20.04

RUN Statement to install dependencies

# Keep the dependency list as short as reasonable
RUN apt-get update && \
apt-get install -y bc bison bsdmainutils build-essential curl locales \
flex g++-multilib gcc-multilib git gnupg gperf lib32ncurses5-dev \
lib32z1-dev libncurses5-dev git-lfs \
libsdl1.2-dev libxkbcommon-x11-0 libwayland-cursor0 libxml2-utils lzop \
openjdk-8-jdk lzop wget git-core unzip \
genisoimage sudo socat xterm gawk cpio texinfo \
gettext vim diffstat chrpath rsync lz4 zstd \
python-mako python-is-python3 libusb-1.0-0-dev exuberant-ctags \
pngcrush schedtool xsltproc zip zlib1g-dev libswitch-perl && \
apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

This will install all needed dependencies to build Boundary Yocto evaluation images and b2qt images.

ADD repo command to rootfs

ADD https://commondatastorage.googleapis.com/git-repo-downloads/repo /usr/local/bin/
RUN chmod 755 /usr/local/bin/*

The repo command is needed to fetch sources for your yocto builds.

RUN command to setup users and permissions

# ===== create user/setup environment =====
# Replace 1000 with your user/group id
RUN export uid=1000 gid=1000 user=jenkins && \
mkdir -p /home/${user} && \
echo "${user}:x:${uid}:${gid}:${user},,,:/home/${user}:/bin/bash" >> /etc/passwd && \
echo "${user}:x:${uid}:" >> /etc/group && \
echo "${user} ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/${user} && \
chmod 0440 /etc/sudoers.d/${user} && \
chown ${uid}:${gid} -R /home/${user}

When creating a container, there will not be any users setup. We use "jenkins" user on our build server, but you should change to whatever your $USER is.

Enable compiler cache to speed up builds

# Improve rebuild performance by enabling compiler cache
ENV USE_CCACHE 1
ENV CCACHE_DIR /home/jenkins/.ccache

This avoids unnecessarily recompiling some elements of the build and adding build time.

Specify locale

# Set the locale
RUN locale-gen en_US.UTF-8
ENV LANG en_US.UTF-8

Specify locale for your language and country.

Setup User and its home directory

ENV HOME /home/jenkins
ENV USER jenkins
USER jenkins

Specify the logged in user in the container and also specify its home directory. That is it! As you can see, its very simple to setup a basic build environment using docker. Now lets build and run it.

Build the Docker image

Execute the following to build the docker image:

wget http://linode.boundarydevices.com/docker/dockerfile_focal
sed -i "s/jenkins/$USER/" dockerfile_focal
docker build --file dockerfile_focal --tag ubuntu_focal .

We first grab the dockerfile, then we modify it for your $USER. Then in the build command, we are instructing docker to use the dockerfile we created. We also provide a tag name called "ubuntu_focal" as an alias for the image.

Run an instance of the image (i.e. Container)

Run your container interactively (which will directly log you in to the container) by providing the tag name specified above.

docker run -it ubuntu_focal

Or you can detach and run the container as a daemon

docker run -d ubuntu_focal

You can also mount a volume which sets up a mount that links the directory from inside the container to the directory on the host machine.

docker run -v : -it ubuntu_focal
There you have it! You can now start building images within your handy docker container.   If you have any issues, please contact us.