docker / buildx

Docker CLI plugin for extended build capabilities with BuildKit
Apache License 2.0
3.6k stars 485 forks source link

Access value of `buildx build --target` within Dockerfile #2646

Closed ByteNybbler closed 1 month ago

ByteNybbler commented 3 months ago

Description

docker buildx build has a --target option where you can specify the desired target stage of a multi-platform build. It would be very useful for the value of this option to be accessible as a built-in ARG, perhaps one named TARGETSTAGE.

This enhancement would make it easier to utilize some useful patterns within Dockerfiles, including navigating to a specific directory within a builder stage depending on the value of the --target option:

FROM rustlang/rust:nightly-buster-slim AS builder
RUN apt-get update && apt-get -y install libssl-dev pkg-config make
WORKDIR /usr/src
COPY . .
ARG TARGETSTAGE
WORKDIR /usr/src/${TARGETSTAGE}
RUN cargo install --locked --path .

FROM debian:buster-slim AS base
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates && update-ca-certificates && rm -rf /var/lib/apt/lists/*
ARG TARGETSTAGE
COPY --from=builder /usr/local/cargo/bin/${TARGETSTAGE} /usr/local/bin/${TARGETSTAGE}

FROM base AS app1
CMD app1

FROM base AS app2
EXPOSE 8080
CMD app2

Right now, doing something like this requires an extra build argument when invoking docker buildx build, which feels a bit cumbersome and redundant: docker buildx build --target app1 --build-arg TARGETSTAGE=app1 .

If this feature gets implemented, the build invocation would be a lot more succinct: docker buildx build --target app1 .

There is some precedent for this sort of change because the --platform option has associated built-in ARGs.

tonistiigi commented 3 months ago

@thaJeztah @AkihiroSuda @crazy-max wdyt?

(The issue belongs in buildkit with kind/dockerfile)

AkihiroSuda commented 3 months ago

SGTM

thaJeztah commented 3 months ago

I like the general idea, and could see some potential, like skipping parts of a script in intermediate stages if we know it's a used for a specific target (but should give some thought to play with additional examples / ideas). Using this option will affect caching (i.e. same stage but target is different will likely bust the cache?) But I think that would be expected, and it would still be opt-in (similar to the platform builtin args.)

One thing that could be tricky (but maybe there's solutions for that) is if we would decide to implement expansion in stage names;

Or at least, I could imagine some recursion happening in that case (FROM foo AS $TARGETSTAGE)

With more builtin args being added, I start to wonder if we need to consider prefix/namespace those at some point to prevent collisions with build-args that are already in use by users.