buildkit
buildkit copied to clipboard
Proposal: allow sending "plain" build output to a file
related issues
- https://github.com/moby/buildkit/issues/1656 Feature Request: support different log formats
- https://github.com/moby/buildkit/issues/1556 [Feature Request] --progress=verbose
- https://github.com/moby/buildkit/issues/1421 Easy way to retrieve logs on RUN failure
- https://github.com/moby/buildkit/issues/783 progress=tty display glitch: --debug output is partially masked (.dockerignore Skipping logs)
- https://github.com/moby/buildkit/issues/644 Logging mechanism for frontends
- https://github.com/moby/buildkit/issues/824 --progress tty is not like old docker build
- https://github.com/moby/buildkit/issues/564 Problems with build output
- https://github.com/moby/buildkit/issues/1458 [Feature request] Add a way to hide internal steps in the output (somewhat related)
- https://github.com/moby/buildkit/issues/2190
- https://github.com/docker/buildx/issues/986
- https://github.com/docker/compose/issues/8800
Description
I'm a big fan of the BuildKit output that's printed during build; it shows the steps that are running, and commands running as part of RUN steps while they're running, but keeps output compact by collapsing the output once a step has completed. However, in some situations, the output is not useful; especially if a build fails.
If a build fails, BuildKit prints the "full" output of the failing step, which can help to narrow down the cause of the failure, which could be sufficient if the cause of the failure is in the actual step that failed.
However, in many cases, the actual cause of the failure may be in prior steps; those steps may have completed successfully by themselves, but cause follow-up step(s) to fail.
For example;
ARG PREFIX=/foo
FROM busybox AS builder
ARG PREFIX
RUN mkdir -p "${PREFIX}/build/" && echo "foobar" > "${PREFIX}/build/artifaaaact"
FROM busybox AS final
ARG PREFIX
COPY --from=builder "${PREFIX}/build/" "/output/"
RUN cat "/output/artifact"
$ docker build .
[+] Building 1.2s (7/7) FINISHED
=> [internal] load build definition from Dockerfile 0.1s
=> => transferring dockerfile: 287B 0.0s
=> [internal] load .dockerignore 0.2s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/busybox:latest 0.0s
=> CACHED [builder 1/2] FROM docker.io/library/busybox 0.0s
=> [builder 2/2] RUN mkdir -p "/foo/build/" && echo "foobar" > "/foo/build/artifaaact" 0.5s
=> [final 2/3] COPY --from=builder /foo/build/ /output/ 0.1s
=> ERROR [final 3/3] RUN cat "/output/artifact" 0.3s
------
> [final 3/3] RUN cat "/output/artifact":
#7 0.257 cat: can't open '/output/artifact': No such file or directory
------
executor failed running [/bin/sh -c cat "/output/artifact"]: exit code: 1
One solution for the above is to use --progress=plain to output the build logs in plain text, but this output is very verbose, and would not be useful for the "success" situation ("happy path").
Proposal: allow "plain" output to be sent to a file
My "ideal" would be to allow the CLI to consume both output formats;
- print the "nice looking" output to the console
- specify a path where the "plain text" output should be logged
The path could be specified on a specific build, e.g.
docker build --logs=~/.docker/build/logs/ .
- The
--logsoption takes a path to a directory - Each build generates a new log-file, using a timestamp and/or unique ID
- The unique "Build ID" could potentially be used for other purposes
The build output should print the path of the logfile that's generated; this could be at the start of the build, allowing (if wanted) the user to, e.g. tail the log output;
[+] Building 1.2s (7/7) FINISHED
=> [internal] starting build 4d69d51e2ef9 0.1s
=> [internal] logging to ~/.docker/build/20201125140133_build_4d69d51e2ef9.log 0.1s
Once a build fails, the path of the log file could be printed as well, to assist the user;
Build 4d69d51e2ef9 failed: logs available in ~/.docker/build/20201125140133_build_4d69d51e2ef9.log
Logging by default
The CLI could have a configuration option in ~/.docker/config.json to specify a default location for storing logs
Further considerations
Log rotation / pruning
One downside of generating a logfile per-build, is that the amount of logs will grow over time, perhaps this is out of scope for the initial implementation, but is something to consider (especially if a default can be set in ~/.docker/config.json).
- max files?
- max size?
- max age?
Given that there's no "client side" long running process/daemon, pruning old logs would likely happen before each build, however, "concurrent builds" may have to be taken into account. Possibly sending logs elsewhere (syslog?) could be an option for this as well (to delegate log-rotation and purging).
Other log formats and output targets
The --logs flag could in future be expanded to an 'advanced' format, for example to define a different output format;
docker build --logs format=junit-xml,path=~/.docker/build/logs/ .
Or perhaps to send logs elsewhere (just brainstorming here);
docker build --logs format=junit-xml,path=unix:///run/log-collector.sock .
/cc @tonistiigi @tiborvass
Just FYI - this wouldn't meet the need that prompted me to raise #1421. I showed a simplified version in there, but I'm really running a complex build that outputs test results as HTML files, so I do need the tagged builder stage in order to retrieve those files, not just the plain text output from buildkit.
@Mahoney ah, right yes, I may have been too quick with marking it as "related". Let me leave some ideas on that issue as well
For making this much easier to interop with docker-compose, these should be environment variables. Same goes for the regular --progress plain. Especially in CI where progress logs duplicate into a big mess, and people often use plugins to control docker builds which don't give access to flags.
I'd argue it's still pretty helpful to be able to access the full build output via regular stdout output, and not have to juggle output to files. Especially when debugging builds
@williamboman that should already be possibly with --progress=plain
Ah my bad, I knew I was missing something. Don't mind me 😬
different files for different platforms could be useful as well. :)
It seems like the functionality has been added to BuildKit, but it is not exposted via buildx ATM?