Open pratiksanglikar opened 4 years ago
Related issue - https://github.com/microsoft/DockerTools/issues/213
Treating prints to stderr as error is not correct. Stdout is used for actual build results (eg. you can pipe a tarball of the built files) or for id with -q
. https://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout
In what scenario is that a thing for Docker? The build output isn't files, it's images, and trying to cram an image into STDOUT...I don't even think that would be possible.
Using STDERR for all logging output, while arguably technically correct, is highly irregular, and likely to cause more problems than solve.
It would be nice to be able to build a container and capture the image ID at the end (like -q
) but still have the build output as a separate stream.
@mdonoughe --iidfile
@bwateratmsft
The build output isn't files, it's images
Build output is whatever you define in --output
, eg. for stdout docker build -o - . > t.tar
It would be nice to be able to build a container and capture the image ID at the end (like
-q
) but still have the build output as a separate stream.
How would one do that? Seems not to be possible, normal docker build always writes everything to stdout, and buildkit doesn't write anything to stdout. And --iidfile
wants a physical file, so process substitition doesn't work either. :(
The opinions here by the maintainers are categorically wrong. Unix tools all throughout the ecosystem utilize stderr
for progress-like output. Since buildkit's output is highly erratic it wouldn't even make sense to try to capture it to begin with, so the usefulness of outputting it to stdout is limited.
I've run into this issue so many times now, where I would like to capture the resulting ID from stdout but still show the build progress on stderr. Docker tools have always been scripting-hostile and this is no exception - please improve this.
@Qix- I'm not sure who you arguing here with. Buildkit does use stderr and only stderr for progress.
The ultimate comment still stands - there is no way to extract a resulting image sha from the output of docker build
in a standardized way (buildkit or not) akin to -q
without also silencing build output.
EDIT: Without brittle text processing commands, which completely disable or break the compact and neatly formatted ANSI-escaped output.
Yes, there is no --write-iid
flag. Because we can't add a flag for absolutely every use case. --iidfile
is more general and covers more use cases. We can't change the behavior of -q
, not because where we write progress but because it is unexpected to the current users. -q
first and foremost means "quiet" so printing progress is unexpected whatever the fd is. Another reason we can't print the id is that stdout is already used by -o
so we would need to detect conflicts and add confusion to users.
In buildx I would recommend that nobody should use -q
as it is a historic hack. Instead, you should configure behavior separately: --iidfile
if you want to know the image ID and --progress=quiet
if you want to suppress progress output. --progress=quiet
does not currently exists in in regular docker build
but we are standardizing in https://github.com/docker/cli/pull/3314
Hello, I got hit by this yesterday. We were previously using docker without buildkit and decided to migrate to it to get all the goodies. Long story short, docker/buildkit is integrated in a custom CI, and a low lvl library handling processes was not fair regarding the priority to give to output. (hint: stdout had the priority)
What happened is that, everything went fine at first, but if the build was emitting too many logs, due to unfairness, the process handling the output of buildkit was not picking up line on stderr fast enough. Up to a certain point, the pipe of stderr got full and buildkit build was stuck on write syscall waiting for this pipe to get some room. So after this threshold, everything was working, but was extremly slow...
I double down on moving logs output to stdout, it is not very common to send everything to stderr
Let's say I have a bash script that wants to build an image with docker build
, take the resulting image id, and then run it.
With non-BuildKit, the command docker build dir_with_dockerfile 2> /dev/null
will output:
Sending build context to Docker daemon 2.048kB
Step 1/1 : FROM ubuntu:bionic
---> 886eca19e611
Successfully built 886eca19e611
Pragmatically speaking, this is completely useless. You might could parse the image id out but that's probably not an ideal way to go. The only way to do it currently is to apply the --quiet
argument which gives a viable image id.
With BuildKit, the command docker buildx build dir_with_dockerfile 2> /dev/null
will output:
It outputs nothing. The logs and progress are output to stderr so redirecting stderr to /dev/null silences the logs. This is still useless because it doesn't output the image id. Ironically, if you give it --quiet
, only then will it output the image id.
So, with the above, the problem is there is no way to reliably have both the docker build log / progress output and also obtain the image id in a meaningful way.
What I think should change:
docker build
should always output only the resulting image id to stdout.If people want the logs output to stdout, they can redirect stderr to stdout. If they don't want the logs at all, they can redirect it to null or somewhere it's not seen. This gives us the most flexibility.
...Since buildkit's output is highly erratic it wouldn't even make sense to try to capture it to begin with
Not if you set BUILDKIT_PROGRESS=plain
- then it outputs in a more "standard" fashion. Although it still outputs some lines to stderr that are not even error messages 😞
Got hit by this today, after enabling BuildKit in an Azure DevOps pipeline, as AzDo fails tasks by default if anything is written to stderr. AzDo's default has never been an issue for me in years of working with it - it's absolutely bizarre that BuildKit writes stuff to stderr that are not even error messages!! :confused:
I get BuildKit wants some means to redirect image output, but surely that unusual case could be behind a flag?
Got hit by this today, after enabling BuildKit in an Azure DevOps pipeline, as AzDo fails tasks by default if anything is written to stderr. AzDo's default has never been an issue for me in years of working with it - it's absolutely bizarre that BuildKit writes stuff to stderr that are not even error messages!! confused
I get BuildKit wants some means to redirect image output, but surely that unusual case could be behind a flag?
Historically, stderr has been used for logging, so much so that some languages and libraries have called it the log stream. The whole point is that when meaningful output is possible, you use stderr as a means of human-readable output and stdout as a means for pragmatic output.
Frankly, causing anything to fail if something is written to stderr is downright dumb as a default. That behavior should be fixed rather than expecting every application that uses stderr for disposable logs to stop using stderr. I find it more bizarre that this default hasn't caused you more issues.
In addition, it's trivial to redirect stderr to stdout if that's what's wanted.
The whole point is that when meaningful output is possible, you use stderr as a means of human-readable output and stdout as a means for pragmatic output.
Then why is there no meaningful output on stdout? Like, for example, the image sha? Which would allow to do something simple like this, which would be incredibly unbelievably useful:
docker run `docker build .` ...
Instead I'm required to... , well, actually I don't even know what I'm required to do, all I know is that something which should be easy and obvious will probably take me at least 30min to figure out, and will require juggling and cleaning up temporary files or some complicated shell redirection magic with non standard file descriptors.
Guys and gals, all I want is to be able to type docker build-n-run mvn install
, and Docker builds the container and runs my Maven command inside it (preferably with the directory mounted inside). This is my most common use case. Why is this so complicated? Am I the only one who needs this?
The whole point is that when meaningful output is possible, you use stderr as a means of human-readable output and stdout as a means for pragmatic output.
Then why is there no meaningful output on stdout? Like, for example, the image sha? Which would allow to do something simple like this, which would be incredibly unbelievably useful:
docker run `docker build .` ...
Instead I'm required to... , well, actually I don't even know what I'm required to do, all I know is that something which should be easy and obvious will probably take me at least 30min to figure out, and will require juggling and cleaning up temporary files or some complicated shell redirection magic with non standard file descriptors.
Guys and gals, all I want is to be able to type
docker build-n-run mvn install
, and Docker builds the container and runs my Maven command inside it (preferably with the directory mounted inside). This is my most common use case. Why is this so complicated? Am I the only one who needs this?
That's the whole point of the issue, if you would read my previous reply explaining the changes I think should be made. For reference, other tools like buildah do exactly that.
EDIT: Also, you can already do that with BuildKit.
image_id=$(docker buildx build --quiet -f <Dockerfile>)
docker run "$image_id"
The problem here is you lose diagnostics.
Yes, I absolutely agree. The question is, we have the year 2022, why are easy and obvious changes like this not being made?
EDIT: and of course I would rather prefer to see the diagnostic output...
Yes, I absolutely agree. The question is, we have the year 2022, why are easy and obvious changes like this not being made?
EDIT: and of course I would rather prefer to see the diagnostic output...
Because half the people in the thread appear to think shoving everything into stdout is how things should be done. For the other half, while my suggestion is simple, it has a compatibility break as shown here: https://github.com/moby/buildkit/issues/1186#issuecomment-934804909
EDIT: And mine isn't the only suggestion and it differs slightly from others.
There probably has to be some consensus which appears to be hard to come to.
As an alternative, something like this would also work:
img_file=$(mktemp)
docker buildx build . --iidfile "$img_file"
img_id=$(cat "$img_file")
Just remember to cleanup the temp file.
Sorry for being verbose on the thread (I swear I'm not usually this chatty), but another thing that could be done is just keep --iidfile
the way it is but fix the deletion logic. Currently, if you do something like docker buildx build . --iidfile /dev/stdout
or docker buildx build . --iidfile >(cat)
, it fails because it appears to try to delete the iid file first. I'd argue this is probably not desirable to begin with but if that's fixed, the temp file hack above wouldn't be necessary either and it's fully backwards compatible.
Thanks for saving me the 30min. ;) Yea, that's what I meant by require juggling and cleaning up temporary files. Probably something like:
trap 'rm -f "$img_file"' 0
Yes, the quoting still interpolates the variable, and yes, this is waaaay too complicated for such a simple task.
@computerquip-work
Any version of docker build should always output only the resulting image id to stdout.
Image ID is what the user needs only for specific types of builds: when build exported an image (into Docker image store), that image was not multi-arch and that image was not exported(eg. in OCI format). Even with all of these constraints most people just want to see the best progress information about their build, not a line in hex.
-q
continues to work and output the image ID in stdout if the user wants it for backward compatibility. For everything else stdout works together with -o
flag and allows redirecting the output(result) of the build.
Logs and progress should only be put out to stderr.
This is how it is today.
Simply remove the --quiet argument altogether or have it to where it only effects the stderr output.
I agree that we should deprecate it and suggest people to use the new flags that are single purpose and don't do multiple things at once.
@cocowalla
Azure DevOps pipeline, as AzDo fails tasks by default if anything is written to stderr. AzDo's default has never been an issue for me in years of working with it
This claim sounded so bizarre I needed to set up Azure DevOps for the first time. No surprise that it is not the case.
How do you think the most common unix tools like wget
, curl -v
, time
etc. print their progress information? Or do they fail on every invocation?
@marc-guenther
Then why is there no meaningful output on stdout?
which would be incredibly unbelievably useful: docker run
docker build .
...Instead I'm required to... , well, actually I don't even know what I'm required to do
Stdout is used for -o/--output
redirects and for -q
for backward compatibility exactly for the case you show in the example. This has been explained numerous times in previous comments.
@computerquip-work
but fix the deletion logic. Currently, if you do something like docker buildx build . --iidfile /dev/stdout or docker buildx build . --iidfile >(cat), it fails because it appears to try to delete the iid file first. I'd argue this is probably not desirable to begin with but if that's fixed, the temp file hack above wouldn't be necessary either and it's fully backwards compatible.
I'm not OK with removing the deletion logic as that is clearly the expected behavior of --iidfile
on regular files, but we could detect the /dev/stdout
is not a regular file and have a different behavior for it.
I'm not OK with removing the deletion logic as that is clearly the expected behavior of
--iidfile
on regular files, but we could detect the/dev/stdout
is not a regular file and have a different behavior for it.
Is it the file deletion logic that's expected or just that the file is cleared before writing to it? For example, in python (since I don't know how to emulate it in bash), you should be able to open a /dev/stdout device file with truncate mode like so it should work for regular files as well:
f = open('/dev/stdout', 'w+b', buffering=0)
f.write(b'bob\n')
f.close()
This won't work if the filesystem is set to read-only though and other issues.
@computerquip-work Truncate mode is not ideal as it would leave an empty file if there is a crash. It should either clear the file or switch it with an atomic rename(there might be some tricky cases for unprivileged users).
@cocowalla This claim sounded so bizarre I needed to set up Azure DevOps for the first time. No surprise that it is not the case.
It certainly is the case with the SSH task (we SSH into a VM to build containers)
I think we need to go back to conventions and what developers expect of build tools.
All of these build tools (I would guess every other language's build tool) output progress to stdout and errors to stderr. The content of build artifacts are never output to either stdout or stderr.
To break these long-standing conventions is a rather brave and pointless decision.
What problem is being solved by doing that? I'd also argue that's not a long-standing convention, I've seen more projects output to stderr for progress than I have to stdout. If I were to proclaim the opposite as the long-standing convention and say To break these long-standing conventions is a rather brave and pointless decision.
, there isn't really much discussion to be had and it's not very productive.
I haven't just proclaimed it, I've given concrete examples of other build tools that all conform to the convention, including Dockers own build tool.
Let me repeat that: including Dockers own build tool.
This reason this thread exist is that this change is a breaking change to docker, a change that appears to provide no benefits and which broke my code and clearly others.
On Fri, 17 June 2022, 1:49 am computerquip-work, @.***> wrote:
What problem is being solved by doing that? I'd also argue that's not a long-standing convention, I've seen more projects output to stderr for progress than I have to stdout. If I were to proclaim the opposite as the long-standing convention and say To break these long-standing conventions is a rather brave and pointless decision., there isn't really much discussion to be had and it's not very productive.
— Reply to this email directly, view it on GitHub https://github.com/moby/buildkit/issues/1186#issuecomment-1157822157, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG32OB3UHMLT6DFDZQ6DK3VPNEJZANCNFSM4I43Z46A . You are receiving this because you commented.Message ID: @.***>
The "gotcha" arguments are really not productive. The benefit of it is that it allows one to do something like tar=$(docker buildx build -o type=oci,dest=-)
without the need to create a temporary file.
If you can make a simple example where you can pragmatically run an image that you just built without race conditions or temporary files, you would have a stronger argument.
@bsutton
The content of build artifacts are never output to either stdout
So because there is a tool on the internet that doesn't have -o
, that means that buildkit should not have this feature either?
All of these build tools (I would guess every other language's build tool
Your Github bio says you work with C/C++/Java . What stdio stream do gcc, clang or javac print their progress output?
It's this sort of philosophic nonsense from the Moby contributors that has forced me to switch to something else entirely. I've advocated against Docker for a few years now due to these bizarre "dying on a hill" stances they take about how tools should behave.
Docker does not behave like any other tool I know of. Its constant misuse of streams, bizarre output formats, and general inoperability with larger systems has rendered it entirely obsolete in my book.
Podman is a step in the right direction, and I urge everyone to focus their time switching to it instead. I'm tired of fighting with the Moby devs over these things. It's been years without any budging.
@Qix-
Docker does not behave like any other tool I know of.
So you don't know gcc, clang, javac, wget, curl, time (only a sample I listed in the last 2 previous comments)?
Please read through the issue and comments before going for the noise. In your previous comment https://github.com/moby/buildkit/issues/1186#issuecomment-934726005 you already wrote
The opinions here by the maintainers are categorically wrong. Unix tools all throughout the ecosystem utilize stderr for progress-like output.
.. without realizing that buildkit does use stderr for progress, and this issue was created by the user who found it confusing and suggested we should change it(what we have refused because it is wrong).
I'm tired of fighting with the Moby devs over these things.
Unfortunately, in both of your last comments, the only person you are fighting with is yourself. You are furiously requesting a behavior that is already there.
I think you have misunderstood my logic.
So because there is a tool on the internet that doesn't have -o,
If you think there is a use case for a -o switch that outputs the artifacts to stdout then go ahead and do it.
The difference here is that the -o switch is under my control and I choose to use it or not.
Let me detail the problem I'm trying to solve.
Essentially we run a CI/CD environment that builds a no. of docker containers. When reviewing logs from those CI/CD runs the docker builds generate thousands of lines of output, none of which I care about.
Being able to suppress stdout and only outputting stderr lets me efficiently review the logs as I'm only seeing the errors.
This is a daily use case and I suspect a common use case for others.
There seems to be a lot of talk about getting the id out of the build.
Yes, this is useful but there are lots of ways that this can be done and creating a temp file with the id is a perfectly acceptable method.
My rule when developing CLI scripts is that the user owns the console and I should only output to the console what the user has asked me to.
General progress messages go to stdout, errors go to stderr. If there is an error, the app returns a non-zero exit code and I expect to see a descriptive message in stderr.
I consider any CLI that doesn't follow these simple rules to be a badly behaving app.
For what it's worth, I'm the author of DCLI the Dart Console SDK so I feel I have some experience in this area and with what end-users want from a CLI app. dcli.onepub.dev
S. Brett Sutton Noojee Contact Solutions 03 8320 8100
On Fri, 17 Jun 2022 at 07:52, Tõnis Tiigi @.***> wrote:
@bsutton https://github.com/bsutton
The content of build artifacts are never output to either stdout
So because there is a tool on the internet that doesn't have -o, that means that buildkit should not have this feature either?
All of these build tools (I would guess every other language's build tool
Your Github bio says you work with C/C++/Java . What stdio stream do gcc, clang or javac print their progress output?
— Reply to this email directly, view it on GitHub https://github.com/moby/buildkit/issues/1186#issuecomment-1158168767, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAG32OCP7CAKUSHIIJ3NB4LVPOO27ANCNFSM4I43Z46A . You are receiving this because you were mentioned.Message ID: @.***>
You can literally already do that, described in this very thread, with --progress=quiet
.
Ran into this issue today. In our functional testing suite, we use general information lines to assert tests. Workaround was to use stderr stream. I find it strange that --quiet
flag writes to stdout while docker build .
does not write anything to stdout. The semantics are a little confusing.
Diagnostics/progress/logs go to stderr. Values to be used with pipes, -o
or with id=$(docker build ...)
to stdout. That being said, --quiet
is there for backward compatibility and if we wouldn't need to worry about that then that case should only be handled with --iidfile
.
I just wanted to point out that this is still a bit problematic a year later. While there are workarounds for getting things to work with --iidfile
, it's pretty inconvenient to use any time it's not clear if you have a functioning temp directory.
Is there any progress on this issue?
we are also still facing the same in an Azure DevOps pipeline, where the docker build is called in a bash task.
Please see these screenshots:
FailOnStderr
defaults to false
in bash task of Azure https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/bash-v3?view=azure-pipelines . Afaics, it is there to handle invoking programs that handle stderr and error codes incorrectly. Builtkit is not such a process and works with the defaults.
Essentially we run a CI/CD environment that builds a no. of docker containers. When reviewing logs from those CI/CD runs the docker builds generate thousands of lines of output, none of which I care about.
Being able to suppress stdout and only outputting stderr lets me efficiently review the logs as I'm only seeing the errors.
This is a daily use case and I suspect a common use case for others.
This is also our use case, and why I ended up on this page. Since --progress=quiet
is not reported by docker build --help
and as indicated by tonistiigi may disappear when backward compatibility is no longer a concern, what is the proposed solution?
Essentially we run a CI/CD environment that builds a no. of docker containers. When reviewing logs from those CI/CD runs the docker builds generate thousands of lines of output, none of which I care about. Being able to suppress stdout and only outputting stderr lets me efficiently review the logs as I'm only seeing the errors. This is a daily use case and I suspect a common use case for others.
This is also our use case, and why I ended up on this page. Since
--progress=quiet
is not reported bydocker build --help
and as indicated by tonistiigi may disappear when backward compatibility is no longer a concern, what is the proposed solution?
Ditto, the problem with redirecting is that it requires more effort to detect when a build has actually failed (you have to store the output somewhere and then parse it again to see if anything starts with ERROR, if so, fail the task compared to just failing if errors are written stderr).
This is quite irritating - I faced this issue when recently deploying Docker on a fresh Ubuntu install. Had to revert back to older version of Docker.
Ditto, the problem with redirecting is that it requires more effort to detect when a build has actually failed (you have to store the output somewhere and then parse it again to see if anything starts with ERROR, if so, fail the task compared to just failing if errors are written stderr). That should be more robust and easier than scanning for
error
in the command output.
Are you able to use the exit code of the build command? For example, when I build an image with an error, I'll get an exit code of 1. A successful build returns exit code 0. If you're on some bash / zsh / similar, you can use set -e
in the build script to fail the script at that point.
You can also explicitly read the exit code as in
docker build ...
if [ $? -ne 0 ]; then
echo "Build failed"
exit 1
fi
You can also inline it
docker build ... || { echo "failed to build"; exit 1 }
Ditto, the problem with redirecting is that it requires more effort to detect when a build has actually failed (you have to store the output somewhere and then parse it again to see if anything starts with ERROR, if so, fail the task compared to just failing if errors are written stderr). That should be more robust and easier than scanning for
error
in the command output.Are you able to use the exit code of the build command? For example, when I build an image with an error, I'll get an exit code of 1. A successful build returns exit code 0. If you're on some bash / zsh / similar, you can use
set -e
in the build script to fail the script at that point.You can also explicitly read the exit code as in
docker build ... if [ $? -ne 0 ]; then echo "Build failed" exit 1 fi
You can also inline it
docker build ... || { echo "failed to build"; exit 1 }
Worked like charm.
Description
docker build commands output general information lines to standard error instead of standard output when buildKit is enabled.
This is particularly problematic for extra tooling we have around docker which depend on lines on stderror to determine if the command was successful.
Following is the output of
docker build
command which is returned on the stderr instead of stdout. The process has exitcode=0 so, it shouldn't ideally put these lines on stderr.Steps to reproduce the issue:
DOCKER_BUILDKIT=1
docker build
command on any project.stderr
instead ofstdout
.Describe the results you received: General information lines are present on
stderr
.Describe the results you expected: General information lines should be present on
stdout
when there is no error.Additional information you deem important (e.g. issue happens only occasionally):
Output of
docker version
:Output of
docker info
:Additional environment details (AWS, VirtualBox, physical, etc.): Physical machine. Running docker commands through Containers Tools for Visual Studio.