1

I have built on an x86-based Windows laptop a Docker image to be run as a container on an ARM-based architecture (Raspberry Pi 4).

Due to ending up with an x86 executable when this is built in the Dockerfile, as much as possible, including the library and app build, is deferred until the container actually runs on the Pi.

However, this seems absurd in that the build must be done each time the container runs (which it may on many Pis). No doubt it also needlessly increases the container's size (which is less important, but still annoyingly sub-optimal)

So in summary, I wonder if there is a way to run gcc in the Dockerfile and indicate that the target architecture is ARM and not the laptop on which the docker build is running.

My Dockerfile currently comprises :

FROM arm32v7/ubuntu:latest

# Defined only while image is being built
ARG DEBIAN_FRONTEND=noninteractive

# Set in container
ENV TZ=Europe/London

ADD ./src /app
WORKDIR /app

# Development only :
#
#   vim
#
RUN apt-get -y update \
 && apt-get -y upgrade \
 && apt-get -t install apt-utils \
 && apt-get -y install tzdata \
 && apt-get -y install dh-autoreconf \
 && apt-get -y install libcurl4-gnutls-dev \
 && apt-get -y install libexpat1-dev \
 && apt-get -y install make \
 && apt-get -y install gettext \
 && apt-get -y install libz-dev \
 && apt-get -y install libssl-dev \
 && apt-get -y install libghc-zlib-dev \
 && apt-get -y install git \
 && apt-get -y install build-essential \
 && apt-get -y install vim \
 && git clone https://github.com/eclipse/paho.mqtt.c.git

CMD ["/bin/bash", "myapp.sh"]

and myapp.sh comprises :

#!/bin/bash

# Build Paho MQTT library
#
cd /app/paho.mqtt.c
make

# Build the experiment app
#
cd /app

gcc -L/experiment/paho.mqtt.c/build/output -o myapp -lpaho-mqtt3a main.c

./myapp

I would have thought the first line "FROM arm32v7/ubuntu:latest" in the Dockerfile would tell gcc that the target architecture was ARM, but evidently not!

P.S. I know I could manually build the app outside Docker on a Pi, and simply copy the ARM executable into the Docker image. But I would rather the the app build is included as part of the image build if possible.

2 Answers 2

1

I've not tried this myself, but it seems that you can use docker buildx to build for multiple architectures: https://www.docker.com/blog/multi-arch-images/.

1

You can either:

  1. cross compile the image
  2. perform the build within an emulator like qemu using binfmt_misc
  3. run the build on each platform

I've done a fair bit of cross compiling in Go, pretty sure there's the ability to do that in gcc. Just note that you'll need to include all the libraries for those other platforms too, which may get complicated. Therefore a statically compiled binary my be easiest. Doing this, I then have a multi-stage build where the last stage is for the target platform and only includes copy commands to copy in the cross compiled binary. For controlling the platform on each stage, there's a FROM --platform option.

With binfmt_misc, that needs to be installed with the --fix-binary option that will show a F flag in the /proc/sys/fs/binfmt_misc/*. If it's not installed with this option, trying to run a container for another platform will output a "file not found" error as binfmt searches for the interpreter inside the container filesystem rather than the host filesystem. Note that this is already setup on Docker Desktop.

Once built, you can push the resulting image to the registry as a multi-platform image, and the appropriate image will pulled under the same name based on the platform performing the pull. The easiest way I've found to create multi-platform images is to use buildx which comes bundled into recent versions of docker.

I demonstrate each of these options in this presentation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.