I am trying to create docker image for my Rust project. I want builder to run on native architecture for shorter compile time (I am using Apple M1) and runtime use linux/amd64 because this is what I use on my VPS.
As I read in documentation of Docker I should be able to provide platform as I do FROM --platform=linux/amd64 scratch AS runtime
.
The Dockerfile
:
###########
# Builder #
###########
FROM rust:1.68-slim as builder
# Preparation for cross-compilation
RUN apt update && apt-get install -y gcc-x86-64-linux-gnu
RUN rustup target add x86_64-unknown-linux-musl
ENV RUSTFLAGS='-C linker=x86_64-linux-gnu-gcc'
ENV CC_x86_64_unknown_linux_musl=x86_64-linux-gnu-gcc
WORKDIR /calar
# Copy only list of dependencies and make dummy main.rs
COPY Cargo.toml .
COPY Cargo.lock .
RUN mkdir src/
RUN echo 'fn main() { println!("You should not see this") }' > src/main.rs
# Build all dependecies without app itself, so they can be cached
RUN cargo build --target x86_64-unknown-linux-musl --release
RUN rm -f target/x86_64-unknown-linux-musl/release/deps/calar*
# Copy source code itself
ADD src src
# Build the binary
RUN cargo build --target x86_64-unknown-linux-musl --release
###########
# Runtime #
###########
FROM --platform=linux/amd64 scratch AS runtime
# Copy the binary from build container
COPY --from=builder /calar/target/x86_64-unknown-linux-musl/release/calar /
# Run the server!
CMD ["/calar", "server"]
But when I run docker build .
, I get an image which is linux/arm64
. The output of docker image inspect <>
:
[
{
"Id": "sha256:cf0dbeef100806446e06750b6efb61c024ff71afd21f12ff190bbe165f35346e",
"RepoTags": [
"calar:latest"
],
"RepoDigests": [],
"Parent": "",
"Comment": "buildkit.dockerfile.v0",
"Created": "2023-04-16T13:16:10.070954304Z",
"Container": "",
"ContainerConfig": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": null,
"Cmd": null,
"Image": "",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"DockerVersion": "",
"Author": "",
"Config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/calar",
"server"
],
"ArgsEscaped": true,
"Image": "",
"Volumes": null,
"WorkingDir": "/",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"Architecture": "arm64",
"Os": "linux",
"Size": 7727216,
"VirtualSize": 7727216,
"GraphDriver": {
"Data": {
"MergedDir": "/var/lib/docker/overlay2/he0r34w53plj6u6fpiecbgxte/merged",
"UpperDir": "/var/lib/docker/overlay2/he0r34w53plj6u6fpiecbgxte/diff",
"WorkDir": "/var/lib/docker/overlay2/he0r34w53plj6u6fpiecbgxte/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:4590f083dd1c4e02bab97863aa00d8528921b8274ec9723876f30fb69ba5c395"
]
},
"Metadata": {
"LastTagTime": "2023-04-16T13:16:10.106901346Z"
}
}
]
How can I change the resulting image architecture to be linux/amd64
?
EDIT: A bit later I noticed something very interesting. I tried to use podman instead of Docker and it simply worked. podman build . produced linux/amd64 image. So maybe the problem is in Docker itself?
2
Answers
Try using
docker build —platform …
. Docs here.The FROM reference docs say
It doesn’t say that it will use the platform target of the last layer by default, so maybe your system’s default platform is overriding the last layer.
You can build with a different platform than the released stage using the
FROM --platform
syntax and builtin variables:Then you can build with:
and the build stage runs on your local arch (of the builder) while the runtime stage (resulting image) is of the target platform.