Skip to content

Proposal: Dockerfile BUILD instruction #7149

@proppy

Description

@proppy

TLTR;

BUILD /rootfs/path/to/context == RUN docker build /rootfs/path/to/context


This was originally a fork of proposal #7115, as I didn't want to pollute the main discussion.

Suggested changes were:

  • in Proposal: Nested builds #7115 the first argument to IN scopes and populates the rootfs of the inner build, and the context are shared w/ the outer build. With this proposal you explicitly pass a new context to the inner build, and you have to ADD or COPY file from the context to the image, just like a regular docker build.

Since then @tonistiigi made a simpler PoC in #8021, this proposal was then updated to match the PR.


Proposal

Most application that build from sources have a disjoint set of build and runtime dependencies/requirements. Because of convenience and in order to benefit from automated build, most images bundle both in their docker images.

A common example is a go application, where the go toolchain and possibly a C compiler is necessary to build the app, but busybox is totally fine to run it.

Another example is a java application, where the JDK is necessary to build the app, but the JRE is enough to run it.

This proposal derives the main ideas from #7115 and #8021 to introduce a simple syntax for allowing chained build with explicit contexts. The indent is to generalize and consolidate workarounds introduced w/ #5715 (docker run builder | docker build -t runner) into the main Dockerfile syntax.

New Dockerfile keyword BUILD

Usage:

BUILD <path/to/context> [path/to/Dockerfile]
[FROM ...
other Dockerfile instructions]...

Description:

BUILD triggers a new docker build job using a given context directory (coming from the image rootfs being built), followed by new Dockerfiles instructions.

Either the path/to/Dockerfile, or the Dockerfile are the root of the new <context> if present or the instructions following the BUILD command are used in-lieu-of the Dockerfile of the new build job: in that order; if instructions follow the BUILD command and path/to/Dockerfile is set or <context>/Dockerfile exists, the build is failed.

The new build start with a fresh rootfs populated from the inner FROM instructions and a fresh environments and replaces the current build job.

It is effectively equivalent to being able to call RUN docker build /path/to/context in a Dockerfile.

Example:

FROM ubuntu

RUN apt-get install build-essentials
ADD . /src
RUN cd /src && make

BUILD /src/build
FROM busybox
COPY app /usr/local/bin/app
EXPOSE 80
ENTRYPOINT /usr/local/bin/app

Note that:

  • the context in chained build is different from the context in the previous build.
  • docker build -t would tag the last chained build defined at the end the Dockerfile until there is a better support for naming distinct image in Dockerfile (the problem already exists today with multiple FROM)
  • changes made to /src/build after the BUILD block won't be represented in the chained image
  • chained BUILDs can't make change to the previous directory being passed as the context, much like regular build can't mutate the context: the context gets tared like regular docker build today and the inner BUILD operate on a copy.

Metadata

Metadata

Assignees

Labels

area/builderBuildkind/featureFunctionality or other elements that the project doesn't currently have. Features are new and shiny

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions