wiki:Docker

Version 5 (modified by Tim Harvey, 3 days ago) ( diff )

added examples for ubuntu 22.04 and 24.04 containers and updated installation instructions

Docker

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 https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
# install Docker repo
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu  $(lsb_release -cs)  stable"
# install
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
# add your local user to the docker group
sudo usermod -aG docker $USER

Testing:

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

References:

Images

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
    cat << EOF > ubuntu-16.04/Dockerfile
    # Download 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
    EOF
    
  2. Build the image:
    # build docker image
    docker build --tag ubuntu-16.04 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.

References:

Tags

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 registry-1.docker.io 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

commands:

  • 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

Containers

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 --volume /usr/src:/usr/src ubuntu-16.04
    
  • run container in privileged mode (necessary to access host devices within the container)
    docker run --privileged -it --volume /usr/src:/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

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.

Examples:

  • run container with a bind-mount from host /usr/src/ to containers /usr/src
    docker run -it --volume /usr/src:/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
    

Notes:

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

Examples

The following examples show how to create various Ubuntu containers from an Ubuntu host OS as a non root user. The steps will vary a bit on other host Operating Systems.

The examples create a local user with sudo access using variables (USER, UID, GID) that can be specified when you build the image to make it easier to share files on your host when using a bind mount.

We pass arguments via the 'docker build' command passing in your USER, UID, GID and the Dockerfile uses these to create an image with a user matching these args such that if you run a container with this image you can bind-mount directories from your host and have the same file ownership and permissions as the user on the host.

We show an example of launching a container binding your home directory and a /tftpboot directory to take advantage of this.

The docker-run '--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.

The docker-run '--rm' option automatically removes the container when it exits so that you don't accidentally leave a bunch of unused containers that allocate resources. If instead you wish to create a container that you can detach from and come back to later you can remove the '--rm' option and attach to it again later with the 'docker attach <containerid>' command after using 'docker container ls' to show available containers.

The docker-run '--privileged' option will allow accessing host devices from the container in case you want to access a removable storage device for example.

The docker-run '--hostname' option provides a custom hostname that helps you remember you are in a docker container. By default /etc/hostname will contain the container ID. Often the hostname is included in your prompt as is the case with Ubuntu so providing a custom hostname helps you keep track of what you are doing.

Ubuntu 20.04 Focal container

  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 -y sudo
      RUN echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
      
      # switch to this user
      USER $USER
      WORKDIR /home/$USER
      EOF
      
    • use the 'docker build' command to build the OS image passing in args for your USER, UID, GID
      docker build --tag ubuntu-focal --build-arg USER=$USER --build-arg UID=$(id -u) --build-arg GID=$(id -g) ubuntu-focal/
      
  1. Create and start docker container
    docker run --rm -it --privileged \
      --volume /home/$USER:/home/$USER \
      --volume /tftpboot/tftpboot \
      --hostname docker-focal \
      --name focal ubuntu-focal
    

Ubuntu 22.04 Jammy container

  1. Create a docker 'image' based on Ubuntu 22.04:
    • On a Linux host, docker images are created from a Dockerfile that provides details and commands used to build the image
      mkdir ubuntu-jammy
      cat << \EOF > ubuntu-jammy/Dockerfile
      # from base image ubuntu 22.04
      FROM ubuntu:22.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 -y sudo
      RUN echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
      
      # switch to this user
      USER $USER
      WORKDIR /home/$USER
      EOF
      
    • use the 'docker build' command to build the OS image passing in args for your USER, UID, GID
      docker build --tag ubuntu-jammy --build-arg USER=$USER --build-arg UID=$(id -u) --build-arg GID=$(id -g) ubuntu-jammy/
      
  1. Create and start docker container
    docker run --rm -it --privileged \
      --volume /home/$USER:/home/$USER \
      --volume /tftpboot/tftpboot \
      --hostname docker-jammy \
      --name jammy ubuntu-jammy
    

Ubuntu 24.04 Noble container

  1. Create a docker 'image' based on Ubuntu 24.04:
    • On a Linux host, docker images are created from a Dockerfile that provides details and commands used to build the image
      mkdir ubuntu-noble
      cat << \EOF > ubuntu-noble/Dockerfile
      # from base image ubuntu 24.04
      FROM ubuntu:24.04
      # Ubuntu 24.04 official docker image creates an 'ubuntu' user with uid/gid 1000 that we want to use here - remove it
      RUN userdel -r ubuntu
      
      # 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 -y sudo
      RUN echo "$USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
      
      # switch to this user
      USER $USER
      WORKDIR /home/$USER
      EOF
      
    • use the 'docker build' command to build the OS image passing in args for your USER, UID, GID
      docker build --tag ubuntu-noble --build-arg USER=$USER --build-arg UID=$(id -u) --build-arg GID=$(id -g) ubuntu-noble/
      
  1. Create and start docker container
    docker run --rm -it --privileged \
      --volume /home/$USER:/home/$USER \
      --volume /tftpboot/tftpboot \
      --hostname docker-noble \
      --name noble ubuntu-noble
    
Note: See TracWiki for help on using the wiki.