Using Docker for development

Docker is a set of platform as a service products that use OS-level virtualization to deliver software in packages called containers. The software that hosts the containers is called Docker Engine. Containers are isolated from one another and bundle their own software, libraries and configuration files.

Docker can be hosted on a variety of Operating Systems such as Windows, Linux, and MacOS and is extremely useful to configure OS specific container environments for building embedded Linux firmware.

The various board support packages (BSP) that Gateworks provides for building firmware for the various Gateworks Single Board Computers are typically built on Ubuntu Linux development systems. Due to your personal preference as well as Ubuntu's release schedule you may end up with a development host that does not run Ubuntu or the specific version of Ubuntu that is recommended to build a particular BSP. You can use Docker to create a container with a specific version of Ubuntu to overcome this.

This wiki page does not cover much of Docker, it is to be used as an example.

see also:

Installing Docker on Ubuntu

Install (from official Docker repo)

# download deps
sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
# install Docker's GPG key
curl -fsSL | sudo apt-key add -
# install Docker repo
sudo add-apt-repository "deb [arch=amd64]  $(lsb_release -cs)  stable"
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli

It is recommended that you add your user to the docker group so that you do not have to run commands as root. The commands referenced on this page assume you have done that and if you have not, you need to run any docker commands via sudo.


  • test by downloading hello-world image and running it
    docker run hello-world



Docker Images represent root filesystems that you can run as a container. These images are built based on a Dockerfile containing a few simple instructions.

Create Image:

  1. Create a Dockerfile for the image (each Dockerfile should be in a directory representing the image)
    # create a directory for your images
    mkdir docker-images && cd docker-images
    # create a directory for your image
    mkdir ubuntu-16.04 && cd ubuntu-16.04
    cat << EOF > Dockerfile
    # Docwnload base image ubuntu 16.04
    FROM ubuntu:16.04
    # Update software repo
    RUN apt-get update
    # Install apps we want
    RUN  apt-get install -y build-essential git python \
    libssl-dev ncurses-dev device-tree-compiler bc gawk zlib1g-dev file \
    wget unzip sudo \
  2. Build the image:
    # build docker image
    docker build --tag ubuntu-16.04 .
  3. List images
    # list images
    docker images

Other image commands:

docker commit <user/image> # save container as an image
docker save <user/image> #save an image to a tar archive
docker buid --tag sampleuser/ubuntu . # build docer image from Dockerfile in current dir
docker load # loads a image from file

Note that images are stored system-wide in a 'registry'. These images can be pushed to shared registries to share them.



An image name is made up of slash-separated name components, optionally prefixed by a registry hostname:port. The hostname must comply with standard DNS rules but may not contain underscores. If registry hostname:port is not present the command uses Docker's public registry located at by default. Name components can contain lowercase letters, digits and separators (period, one or two underscores, or one or more dashes).

A tag name must be valid ASCII and may contain lower/upper letters,digits, underscores, periods and dashes.

A registry is a storage and content deliver system holding named images available in different tagged versions. Users interact with a registry by using docker push and pull commands

The registry is a stateless, open-source, highly scalable server side application that stores and lets you distribute Docker images.

The Docker Hub provides a free-to-use hosted registry with additional features


  • start local registry
    docker run -d -p 5000:5000 --name registry registry:2
  • pull an image from the hub
    docker pull ubuntu
  • tag that image so it points to your local registry
    docker image tag ubuntu localhost:5000/myimage
  • push it


A container is a running instance of a system sharing the host machines kernel but using an image root filesystem. When the container is stopped all changes to the filesystem are lost unless you mount volumes within that image to access filesystems on the host.

Running container

  • Run container with an interactive shell
    # run container interactively
    docker run -it ubuntu-16.04
  • run container with a bind-mount from host /usr/src/ to containers /usr/src
    docker run -it --mount type=bind,source=/usr/src,target=/usr/src ubuntu-16.04
  • run container in privileged mode (necessary to perform some root-specific functions like 'mount' within the container)
    docker run --privileged -it --mount type=bind,source=/usr/src,target=/usr/src ubuntu-16.04
  • Notes:
    • use '--rm' to remove the container after exiting
    • use '-it' to allocate pseudo-TTY
    • specify /bin/bash to launch specific shell
    • use '-w' to set working directory
    • use '--env foo=bar' or '--env-file ./env.list' to set env vars

Other container commands:

docker ps # list all running containers
docker images # list all images on local machine
docker history <user/image> # list history of an image
docker port <container> # display exposed port of a running container
docker run -it <user/image> # runs an image, creating a container and changing the terminal to it
docker run -p $HOSTPORT:$CONTAINERPORT -d <user/image> # run image in deatched mode wiht port forwarding
ctrl+p, ctrl+q detach from container
docker attach <container>
docker start <container>
docker stop <container>
docker inspect <container> # show details
docker rm -f <container> # delete container
docker rmi # delete image
docker tag <user/image:tag> <usr/image:newtag> # apply a new tag to an image
docker exec <container> shell command # execute a command within a running container


Volumes provide a way to share filesystems or more importantly bring non-volatile storage to docker containers.

You can specify volume mounts within image files or on the command-line when running a container. The modern command-line option for this is the --mount parameter which requires a type, source, and target. The type can be type=bind to use an OS bind mount or type=volume to utilize a docker IO driver.


  • run container with a bind-mount from host /usr/src/ to containers /usr/src
    docker run -it --mount type=bind,source=/usr/src,target=/usr/src ubuntu-16.04
  • create a volume and mount it in a container:
    docker volume create ubuntu-16.04
  • run container with a volume mounted from host to /usr/src
    docker run -it --mount type=volume,source=ubuntu-16.04,target=/root/workspace ubuntu-16.04


  • use '--tmpfs' (ie --tmpfs /run:rw,noexec,nosuid,size=65536k) to mount a tmpfs


Ubuntu 20.04 Focal container

This example shows how to create an Ubuntu 20.04 Focal container from an Ubuntu host OS. The steps will vary a bit on other host Operating Systems.

  1. Create a docker 'image' based on Ubuntu 20.04:
    • On a Linux host, docker images are created from a DockerFile? that provides details and commands used to build the image
      mkdir ubuntu-focal
      cat << EOF ubuntu-focal/DockerFile
      # from base image ubuntu 20.04
      FROM ubuntu:20.04
      # Disable Prompt During Packages Installation
      ARG DEBIAN_FRONTEND=noninteractive
      # update list of available packages
      RUN apt-get update
      # add a non-root user
      ARG USER=build
      ARG UID=1000
      ARG GID=1000
      RUN groupadd -g $GID $USER && useradd -g $GID -m -s /bin/bash -u $UID $USER
      # and give that user permission to use sudo
      RUN apt-get install sudo
      RUN echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
      # and set the prompt as a reminder 
      RUN echo 'export PS1="\u@focal:\w\$ "' >> /home/$USER/.bashrc
      # switch to this user
      USER $USER
      WORKDIR /home/$USER
    • use the 'docker build' command to build the OS image:
      docker build --tag ubuntu-22.04 --build-arg USER=$USER --build-arg UID=$(id -u) --build-arg GID=$(id -g) ubuntu-jammy/
      • the '--build-arg' options above are optional but show how you can use your host Linux OS user/group to replace the default ones specified in the DockerFile?. This can be very useful if you mount a filesystem from your host OS into your container and want to share user permissions
      • building the 'image' is a one-time operation. You only need to repeat it if you change the DockerFile? specifying the image
      • if wanted you can add additional 'RUN apt-get install -y <packages>' steps before the 'USER $USER' command (which switches the user from root to a non-root user, otherwise you would need to use sudo) to install additional packages so that you don't have to do that every time you create a new container from the image
  2. Create and start docker container
    docker run -it --privileged \
      --mount type=bind,source=/usr/src,target=/usr/src \
      --mount type=bind,source=/tftpboot,target=/tftpboot \
      --name jammy ubuntu-jammy
    • the '--mount' options are optional but show how you can mount directories from your host OS to the container's OS. In this case we have mounted /tftpboot so we can copy files from the container to the hosts's tftpboot directory where a TFTP server may be running. We also mount /usr/src from the host OS to allow our host OS to get to source files we use
    • Note that once you 'run' a container it remains present even if you have detached from it meaning you can later re-attach to it
    • The '--it' option is a shortcut for '--interactive' and '--tty' which allocates a pseudo-TTY terminal and keeps STDIN open even if not attached. These options allow the bash process to start in the container, attaches the host OS console to the processes standard input/output/error, and allocates a text-only console.

If you at some point exit your docker container you can attach to it again later with the 'docker attach <containerid>' command after using 'docker container ls' to show available containers.

Last modified 3 months ago Last modified on 08/29/2022 09:14:08 PM