2

I'm doing multi-platform builds with buildx and would like to know if there is a way to determine what platform is currently being build so I can avoid certain steps for certain environments.

For example, something like...

# No DOSEMU outside amd64
RUN if [ "$DOCKER_PLATFORM" = "amd64" ]; then \
      apt install dosemu \
    fi

4 Answers 4

4

This is typically done with a script, not the Dockerfile. The script (perhaps in bash or python) can run at build time to determine what environment it is in, and act accordingly. This can be included in the RUN command, but it risks becoming quite complex and difficult to read in the Dockerfile. Furthermore, each additional RUN or CMD entry in the Dockerfile adds a layer to the image, which is considered bad practice.

This script can instead take the arguments BUILDPLATFORM and TARGETPLATFORM as suggested in the buildx docs, which would make more declarative. Instead of discovering the target, you would declare it (and write your script accordingly), so that the user understands exactly what happens without having to look inside the build.

2
  • Thank you... BUILDPLATFORM and TARGETPLATFORM are precisely what I was looking for. As to an extra RUN entry, it would be integrated into a chain command for prerequisites from apt... I'm currently doing `&& (apt install -yqq dosemu || echo "dosemu not available for platform") ` in the chain separate from the other apt tools. It's a little more involved than I would like, but is at least working for now. github.com/bbs-io/synchronet-docker/blob/master/docker/…
    – Tracker1
    Commented Mar 11, 2021 at 21:53
  • I know the Dockerfile has more steps than ideal, was more concerned about correctness initially than reducing steps.
    – Tracker1
    Commented Mar 11, 2021 at 21:54
2

One other option is to use TARGETPLATFORM as mentioned but with multistage Dockerfile.

If there's no complex logic apart from a few different steps (between targets), this allows to keep everything in the Dockerfile (and a single one).

FROM alpine:3.16 as main-linux-armv7
# do whatever is different on linux/arm/v7

FROM alpine:3.16 as main-linux-amd64
# do whatever should be for linux-amd64

FROM main-linux-amd64 as main-linux-arm64
# linux-arm64 is the same as linux-amd64 but every target needs to be defined

FROM main-${TARGETOS}-${TARGETARCH}${TARGETVARIANT}
# main / final stage
1

I would just have a base script that have the things in common for most of the platform like base_install.sh

Then I would have multiple dockerfiles that can use this base script, an example for your amd64 dockerfile DockerfileAMD64:

FROM mybase64image

RUN ./base_install.sh
RUN apt-get install specific64things -y

and you can build it with:

docker build -f DockerfileAMD64

That way you can version control these files without duplicating code between the dockerfiles.

1
  • I'm specifically using buildx for multi-platform builds, and a single Dockerfile for the service in question, what you propose would greatly complicate things for the need of a single requisite that isn't available on arm platforms. For now, I'm actually using... RUN ... apt install -yqq ... && \ (apt install -yqq dosemu || echo "No dosemu for platform") && \
    – Tracker1
    Commented Mar 11, 2021 at 21:49
1

The simplest answer will be to use TARGETPLATFORM variable which is available when you run docker buildx build ... command. Only thing to remember is that for any variable that is available you need to declare it using ARG.

So, a sample Dockerfile snippet can be:

ARG TARGETPLATFORM
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \
        echo "ARM64 version"; \
    else \
        echo "AMD64 version"; \
    fi

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.