Docker + toolchains
March 19, 2019
I heard about Docker and container technology last year, but I’ve never really used it, until I notice that toolchains, depending on the OS, are easy or hard to set-up. In that moment, I remembered the main characteristic of container technology: a piece of software with all its dependencies.
Docker is a tool designed to create, deploy and run an application by using containers, and a container is a unit of software that includes all its dependencies so the application runs regardless the installed OS, because all that application might need is already in the container.
Docker Terms
Let’s define some terms so it will be easier to explain later other concepts.
- Docker Image: Binary file that includes everything needed to run an application.
- Container: Runtime instance of the image. Your application runs on a container.
- Dockerfile: File with commands to build a Docker image.
Building a Docker Image
First I need a Dockerfile, in which I should specify the dependencies of my application and configuration of the image (setting the path, for example). Since I’m working with cortex-M microcontrollers, I will need basically the following:
- GNU ARM embedded toolchain link
- The toolchain runs on a OS, I’ll use Alpine Linux
make
to compile my applications
My Dockerfile is as follows:
FROM frolvlad/alpine-glibc:alpine-3.9_glibc-2.29
# Set up a tools dev directory
WORKDIR /home/dev
# Packages that will be needed once
RUN apk --update --no-cache add --virtual build-dependencies \
w3m \
wget \
openssl \
ca-certificates \
bzip2-dev \
tar
# Install make
RUN apk --update --no-cache add make
# Install GNU ARM toolchain
RUN wget https://developer.arm.com/-/media/Files/downloads/gnu-rm/8-2018q4/gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2 \
&& tar xvf gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2 \
&& rm gcc-arm-none-eabi-8-2018-q4-major-linux.tar.bz2
RUN apk del build-dependencies
# Set up the compiler path
ENV PATH="/home/dev/gcc-arm-none-eabi-8-2018-q4-major/bin:${PATH}"
Building a Docker image is super easy, just run docker build -t IMAGE_TAG .
. In my case
$ docker build -t daniel/test .
To verify my image was built, I used docker image ls
.
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
daniel/test latest 71b2c630bd2f 11 minutes ago 507MB
frolvlad/alpine-glibc alpine-3.9_glibc-2.29 4e5eb981daf8 5 weeks ago 12.2MB
There are two images because my image daniel/test
depends on the base Linux image frolvlad/alpine-glibc
.
Note: if you want to know more about the Alpine Linux package manager (apk) check this link
Running an application
In your Host machine, where you have installed the Docker, will coexist the Docker environment, where the containers will run, and your files or working directories.
Let’s say I want to run my application which is in the application directory WD1 on the container C1. In order to do so, I have to mount WD1 on the container.
In Docker it is done as follows:
docker run \
-rm \
-v SOURCE_DIR:VOLUME \
--name CONTAINER_NAME \
-w DOCKER_WORKDIR \
IMAGE \
COMMANDS
A short explanation:
run
: command to run a container.-rm
: Automatically remove the container when it exits. The alternative would be to manually stop it and then remove it.-v
or--volume
: Mounts a local directory (WD1) on a Docker volume--name
: Assign a name to the container, it’s useful for debugging or to recognize containers.-w
or--workdir
: sets the working directory of the container to where any commands will be executed.
In my case I execute docker run
with make
on my WD1 to compile my C application.
$ docker run \
-v $(pwd):/usr/src/myapp \
-w /usr/src/myapp \
--name my_container \
daniel/test
make
To check my running container docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
971d9feae531 daniel/test "make" About a minute ago Exited (0) my_container
Dockerhub
There is a image repository called Dockerhub, where you can push your customized docker images or just pull one
Pushing your customized image
If you want to push your image, just execute
$ docker push YOUR_REPO
Of course you should have a Dockerhub account. More info in this link
Pulling an image
Pulling an image is also easy. First we need to find an image. For example if I want a docker image that has already the ARM toolchain, I will use the following command:
$ docker search arm eabi
I will get some outputs
NAME DESCRIPTION STARS AUTOMATED
modm/arm-none-eabi-gcc Arm-none-eabi-gcc toolchain in a docker cont… 0 [OK]
thomasf/arm-eabi-toolchain Build toolchain for cross compiling arm 0 [OK]
0fff/gcc-arm-none-eabi This repo contains a set of different versio… 0 [OK]
It’s better to use official packages when possible because a good unofficial image will have a decent set of instructions about its use and how it was built. Unfortunately, most don’t have any information and you can waste a substantial amount of time trawling through the repositories looking for a suitable image. To filter packages I use the option --filter
.
$ docker search --filter "is-official=true" arm
There is unfortunately no official ARM docker image, so I should search for a good one or build a customized as I did it before using Dockerfiles.
Anyway, let’s say I want to try one of the unofficial images I found modm/arm-none-eabi-gcc
.
To pull the image I execute:
$ docker pull modm/arm-none-eabi-gcc
To check if the image is in my host
$ docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
daniel/test latest 71b2c630bd2f 17 hours ago 507MB
modm/arm-none-eabi-gcc latest 1977388e9003 3 weeks ago 834MB
frolvlad/alpine-glibc alpine-3.9_glibc-2.29 4e5eb981daf8 5 weeks ago 12.2MB
It’s already there.
Clean up
Using Docker can get very messy, so to clean up your host try the following commands:
- To show running containers
docker container ls -a
- To delete use the ID, because is unique
docker container rm CONTAINER ID
. Or you can automatically delete the container with--rm
, as it was already mentioned. - To delete images
docker image rm IMAGE
- To delete or prune all the containers
docker container prune
Summary
Docker is a super useful tool to encapsulate your application and dependencies. Now I feel I can use any OS without worry whether my toolchains or apps will run. However, it can be also very annoying, specially when working with multiple containers, or trying to put too much in one container. It’s better to keep the containers simple, and use multiple simple containers to do your work rather than one big messy one.
Share it!
Comments powered by Talkyard.