Build multi-arch images with different commands per architecture in Docker file

Hello, I have a question related to building containers for multi architectures.
I am working from a mac the the M1 arm chip.

Usually, I write my docker file and use the command
docker buildx build --platform linux/arm64,linux/amd64 -t name:latest --push .
And this works fine, as the commands in the dockerfile are the same for both architectures.

However, I now have a case where the commands are different for arm64 and amd64.

For example, for arm64 I need to write:

RUN cd ~/github && \
 git clone https://github.com/lh3/minimap2.git && \
 cd minimap2 && \
 make arm_neon=1 aarch64=1

While for amd64 I need to write:

RUN cd ~/github && \
 git clone https://github.com/lh3/minimap2.git && \
 cd minimap2 && \
 make

I wrote this docker file:

FROM ubuntu:focal

ENV DEBIAN_FRONTEND=noninteractive 

# Add build arguments for specific architectures
ARG TARGETPLATFORM

RUN mkdir ~/github

RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
cd ~/github && \
git clone https://github.com/lh3/minimap2.git && \
cd minimap2 && \
make arm_neon=1 aarch64=1; \
elif ["$TARGETPLATFORM" = "linux/amd64"]; then \
cd ~/github && \
git clone https://github.com/lh3/minimap2.git && \
cd minimap2 && \
make; \
fi

ENV PATH="$PATH:/root/github/minimap2/"

And I am using this command to build the image:

docker buildx build --platform linux/arm64,linux/amd64 -t name:latest --push .

However, the program minimap is installed only on the image for arm64 arch, while the image for amd64 gets built but does not have minimap.

Is there a way to have a single dockerfile with these two commands and specify that each is for a different architecture, and then run a single docker buildx command?

Thanks

Marco

As a general idea:

Try a simple echo "$TARGETPLATFORM" before the conditional RUN instruction so you can see the value of the variable.

You can also add some echos to the “if” and the “elif” blocks and add an “else” block es well.

Than you can add --progress plain to the build command so you can seethe echos so you will know exactly what ran and what didn’t.

On the other hand, I think it is just a shell syntax error and your the RUN instruction fails in the amd64 build butin the end it doesn’t return an error code so the ENV instruction can run and Docker can finish the build.

This line:

elif ["$TARGETPLATFORM" = "linux/amd64"]; then \

should be like this

elif [ "$TARGETPLATFORM" = "linux/amd64" ]; then \

If you use the --progress plain option, you should see he error message even though the build continues.

To be more precise it is rather a semantic error as you can write an if like this:

mycommand() {
  echo "mycommand: $*"
}

if mycommand = "b"; then
  echo "OK"
fi

where mycommand will run with two arguments. = and b. Since the function doesn’t return any erro code, the output is:

mycommand: = b
OK

In your case the command is [linux/amd64 and the arguments are = and linux/amd64], but [linux/amd64 can’t be found as a command.

You can fix the elif line or you can use another solution which could be much better when you have much more than just 4 conditional lines. You can simply create two scripts:

linux/arm64.sh

#!/usr/bin/env sh

set -eu

cd ~/github
git clone https://github.com/lh3/minimap2.git
cd minimap2
make arm_neon=1 aarch64=1

and
linux/amd64.sh

#!/usr/bin/env sh

set -eu

cd ~/github
git clone https://github.com/lh3/minimap2.git
cd minimap2
make

Then run it like this:

COPY linux/ /app/installer/linux
RUN /app/installer/$TARGETPLATFORM.sh

It will fail when the file doesn’t exist. Since the only difference is the make line, you can make the scripts even shorter by keeping everything else in the Dockerfile except the “make” line

1 Like

Hi @rimelek,

Thank you for your reply and for noticing the error.

Writing

elif [ "$TARGETPLATFORM" = "linux/amd64" ]; then \

fixes the problem.

And thank you for your other suggestion.

Marco