Version 5 (modified by 3 days ago) ( diff ) | ,
---|
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:
- Set up Linux Containers on Windows 10
- https://hub.docker.com/editions/community/docker-ce-server-ubuntu
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:
- 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
- Build the image:
# build docker image docker build --tag ubuntu-16.04 ubuntu-16.04
- 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
- 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/
- On a Linux host, docker images are created from a Dockerfile that provides details and commands used to build the image
- 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
- 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/
- On a Linux host, docker images are created from a Dockerfile that provides details and commands used to build the image
- 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
- 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/
- On a Linux host, docker images are created from a Dockerfile that provides details and commands used to build the image
- 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