Gotcha: docker inspect can lie about the architecture of an image

Today I've been working with some (internal) cross-compiled Docker images, while responding to an internal incident.

As part of this, we followed some documentation (I had written a few weeks ago) around how to build an image ad-hoc, and noticed that the images weren't correctly working - a colleague using an ARM Mac wasn't able to correctly build an image that worked on our x86 infrastructure.

What was weird is that we'd tested this when writing the docs and it seemed to build the image + binary correctly - but as we discovered today, docker inspect was lying to us.

Following the official docs, and a blog post from 2021 which still holds up, we produced a Dockerfile like:

FROM --platform=$BUILDPLATFORM golang:1.24 AS build

WORKDIR /app

COPY . .
ARG TARGETOS TARGETARCH
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build .

FROM --platform=$BUILDPLATFORM alpine
#    ^^^^^^^^^^^^^ is wrong
COPY --from=build /app/hello-world /bin

When building this image locally (without cross-compiling) everything worked:

% docker build .
...
=> => writing image sha256:8ac63a06a83515e253795be92a6966dc77e9e259473abb747769902e85049e3c
% docker run -ti sha256:8ac63a06a83515e253795be92a6966dc77e9e259473abb747769902e85049e3c  /bin/hello-world
Hello there

And it looks like it produced an x86 image:

% docker inspect sha256:8ac63a06a83515e253795be92a6966dc77e9e259473abb747769902e85049e3c
[
    {
        "Id": "sha256:8ac63a06a83515e253795be92a6966dc77e9e259473abb747769902e85049e3c",
        "Architecture": "amd64",
        "Os": "linux"
    }
]

And we can build it for a different architecture:

% docker build --platform linux/arm64 .
...
=> => writing image

Naturally, as this is cross-compiled, it shouldn't allow us to start the container:

% docker run sha256:b837b97f705342e28bb90cc5cc592a37916c4ac640e41f97e42287bdc5dfdaa7   /app/hello-world
WARNING: The requested image's platform (linux/arm64) does not match the detected host platform (linux/amd64/v4) and no specific platform was requested
docker: Error response from daemon: failed to create task for container: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: exec: "/app/hello-world": stat /app/hello-world: no such file or directory

And we can see that - correctly - this is an ARM64 image:

% docker inspect sha256:07db3c064d85270a7e62586339ef9f063a3af02e5b636921fcaf26c6afc08476
[
    {
        "Architecture": "arm64",
        "Variant": "v8",
        "Os": "linux"
    }
]

However what went wrong was when my colleague built it - on an ARM Mac - and cross-compiled the Go app and the image for x86.

When I ran the Go app in the image itself, it all worked:

$ docker run -ti $image
{"log_level": "INFO", ...}

And it correctly reported itself as an x86 image:

% docker inspect $image
[
    {
        "Id": "...",
        "Architecture": "amd64",
        "Os": "linux"
    }
]

The problem presented itself when I tried to execute any other binaries - i.e. not the Go binary we'd cross-compiled - at which point we noticed:

$ docker run -ti $image sh
exec /bin/sh: format error

As I've written about before, this is down to the sh binary having the wrong CPU architecture.

But wait - docker inspect says it's an amd64 AKA x86 image - what??

The root cause was that the Dockerfile was wired in incorrectly, and that instead we should have written:

 FROM --platform=$BUILDPLATFORM golang:1.24 AS build

 WORKDIR /app

 COPY . .
 ARG TARGETOS TARGETARCH
 RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build .

-FROM --platform=$BUILDPLATFORM alpine
+FROM --platform=$TARGETPLATFORM alpine
 COPY --from=build /app/hello-world /bin

Or, it appears, simply:

 FROM --platform=$BUILDPLATFORM golang:1.24 AS build

 WORKDIR /app

 COPY . .
 ARG TARGETOS TARGETARCH
 RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build .

-FROM --platform=$BUILDPLATFORM alpine
+FROM alpine
 COPY --from=build /app/hello-world /bin

Because of this, we told Docker that the image is an x86, even though it wasn't.

What's weird here is that Docker kinda knew that it was building the final image as an ARM image, because all the binaries in it were ARM, but because --platform=$BUILDPLATFORM seems to take priority, it didn't work.

Written by Jamie Tanna's profile image Jamie Tanna on , and last updated on .

Content for this article is shared under the terms of the Creative Commons Attribution Non Commercial Share Alike 4.0 International, and code is shared under the Apache License 2.0.

#blogumentation #docker.

This post was filed under articles.

Interactions with this post

Interactions with this post

Below you can find the interactions that this page has had using WebMention.

Have you written a response to this post? Let me know the URL:

Do you not have a website set up with WebMention capabilities? You can use Comment Parade.