ARM
Modern Docker builds should treat CPU architecture as an explicit build output. A developer may build on an amd64 laptop, deploy to arm64 cloud nodes, and still publish one image name that works for both platforms. See the cross-builds chapter for the full Mac-to-x86, x86-to-ARM64, and multi-platform release workflow.
Use Buildx for multi-platform builds.
1docker buildx ls
2docker buildx create --name multiarch --driver docker-container --use
3docker buildx inspect --bootstrap
If the builder needs CPU emulation, install QEMU/binfmt support on the build host.
1docker run --privileged --rm tonistiigi/binfmt --install all
Build and push one manifest list containing both amd64 and arm64 images.
1docker buildx build \
2 --platform linux/amd64,linux/arm64 \
3 -t registry.example.com/team/app:latest \
4 --push .
For local testing, load a single-platform image into the local Docker image store.
1docker buildx build --platform linux/arm64 --load -t app:arm64 .
Do not assume that every base image supports every platform. Check the manifest before choosing the base image.
1docker buildx imagetools inspect python:3-slim
Basic ARM container
An example Dockerfile to build a basic ARM container for Raspberry Pi-style work is as follows.
1FROM arm32v7/ubuntu
2
3ENV DEBIAN_FRONTEND=noninteractive
4
5RUN apt-get update -y && \
6 apt-get upgrade -y
7
8RUN apt-get install -y \
9 wget \
10 build-essential \
11 tk-dev \
12 libncurses5-dev \
13 libncursesw5-dev \
14 libreadline6-dev \
15 libdb5.3-dev \
16 libgdbm-dev \
17 libsqlite3-dev \
18 libssl-dev \
19 libbz2-dev \
20 libexpat1-dev \
21 liblzma-dev \
22 zlib1g-dev \
23 libffi-dev \
24 gfortran \
25 libopenblas-dev \
26 liblapack-dev \
27 python-dev \
28 default-libmysqlclient-dev \
29 libfreetype6-dev \
30 libxml2-dev \
31 libxslt1-dev
32
33RUN apt-get clean
Notice the following.
The base image is
arm32v7/ubuntu.The
ENV DEBIAN_FRONTEND=noninteractiveinstruction is to enable non-interactive installs (so we do not get prompted forYesorNo).We install a lot of system libraries since we want to do interesting things later on.
Build.
1docker build --no-cache -t rpi-base:local .
Run.
1docker run -it rpi-base:local
Jupyter Lab
What if we want to have a reproducible, consistent data science work environment on the Raspberry Pi? We can build a container to spin up a Jupyter Lab instance.
1FROM rpi-base:local
2
3ENV CONDA_HOME=/root/miniconda
4ENV PATH=${CONDA_HOME}/bin:${PATH}
5ENV JUPYTER_TYPE=lab
6
7# setup OS
8RUN apt-get update -y && \
9 apt-get upgrade -y && \
10 apt-get install supervisor -y
11
12# setup supervisor
13COPY jupyter.conf /etc/supervisor/conf.d/
14
15# setup miniconda
16RUN wget -q http://repo.continuum.io/miniconda/Miniconda3-latest-Linux-armv7l.sh -O /tmp/miniconda.sh && \
17 /bin/bash /tmp/miniconda.sh -b -p /root/miniconda && \
18 conda update -n root conda -y && \
19 conda update --all -y && \
20 pip install --upgrade pip && \
21 conda config --add channels rpi && \
22 conda install python=3.6 -y && \
23 conda install jupyter jupyterlab nodejs scikit-learn numpy scipy matplotlib -y -c anaconda -c conda-forge
24
25# setup mount point
26RUN mkdir /ipynb
27VOLUME ["/ipynb"]
28
29# setup ports
30EXPOSE 8888
31
32# clean up
33RUN apt-get clean
34
35CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf", "-n"]
Notice the following.
We use the previous
rpi-base:localimage to bootstrap this image.We install
minicondato manage our Python environments and dependencies.We setup a mount volume at
/ipynbso that we can mount our local notebooks onto the container at runtime.We expose port
8888, which is what Jupyter Lab is running on.We use
supervisorto start up Jupyter Lab at runtime.If you do not like Jupyter Lab and want the classic Jupyter Notebook, override at runtime with
-e JUPYTER_TYPE=notebook.
Build.
1docker build --no-cache -t rpi-jupyter:local .
Run.
1docker run \
2 -it \
3 --rm \
4 -p 8888:8888 \
5 -v `pwd`/ipynb:/ipynb \
6 rpi-jupyter:local
You may now access the Jupyter Lab at http://localhost:8888.