Skip to content

builder: produce error when using unsupported Dockerfile option#41912

Merged
tiborvass merged 1 commit intomoby:masterfrom
thaJeztah:improve_build_errors
Mar 24, 2021
Merged

builder: produce error when using unsupported Dockerfile option#41912
tiborvass merged 1 commit intomoby:masterfrom
thaJeztah:improve_build_errors

Conversation

@thaJeztah
Copy link
Copy Markdown
Member

@thaJeztah thaJeztah commented Jan 21, 2021

fixes #41911

depends on

builder: produce error when using unsupported Dockerfile option

With the promotion of the experimental Dockerfile syntax to "stable", the Dockerfile
syntax now includes some options that are supported by BuildKit, but not (yet)
supported in the classic builder.

As a result, parsing a Dockerfile may succeed, but any flag that's known to BuildKit,
but not supported by the classic builder is silently ignored;

$ mkdir buildkit_flags && cd buildkit_flags
$ touch foo.txt

For example, RUN --mount:

DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
FROM busybox
RUN --mount=type=cache,target=/foo echo hello
EOF

Sending build context to Docker daemon  2.095kB
Step 1/2 : FROM busybox
 ---> 219ee5171f80
Step 2/2 : RUN --mount=type=cache,target=/foo echo hello
 ---> Running in 022fdb856bc8
hello
Removing intermediate container 022fdb856bc8
 ---> e9f0988844d1
Successfully built e9f0988844d1

Or COPY --chmod (same for ADD --chmod):

DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
FROM busybox
COPY --chmod=0777 /foo.txt /foo.txt
EOF

Sending build context to Docker daemon  2.095kB
Step 1/2 : FROM busybox
 ---> 219ee5171f80
Step 2/2 : COPY --chmod=0777 /foo.txt /foo.txt
 ---> 8b7117932a2a
Successfully built 8b7117932a2a

Note that unknown flags still produce and error, for example, the below fails because --hello is an unknown flag;

DOCKER_BUILDKIT=0 docker build -<<EOF
FROM busybox
RUN --hello echo hello
EOF

Sending build context to Docker daemon  2.048kB
Error response from daemon: dockerfile parse error line 2: Unknown flag: hello

With this patch applied

With this patch applied, flags that are known in the Dockerfile spec, but are not
supported by the classic builder, produce an error, which includes a link to the
documentation how to enable BuildKit:

DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
FROM busybox
RUN --mount=type=cache,target=/foo echo hello
EOF

Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM busybox
 ---> b97242f89c8a
Step 2/2 : RUN --mount=type=cache,target=/foo echo hello
the --mount option BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled.


DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
FROM busybox
COPY --chmod=0777 /foo.txt /foo.txt
EOF

Sending build context to Docker daemon  2.095kB
Step 1/2 : FROM busybox
 ---> b97242f89c8a
Step 2/2 : COPY --chmod=0777 /foo.txt /foo.txt
the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled.

- Description for the changelog

Fix classic builder silently ignoring unsupported Dockerfile options

@thaJeztah thaJeztah added this to the 20.10.3 milestone Jan 21, 2021
Comment on lines 112 to 118
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Temporary patch; perhaps there's a cleaner approach for this, but thought I'd open a PR to discuss the best approach.

Comment thread builder/dockerfile/dispatchers.go Outdated
Comment on lines 117 to 119
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps all command should take the same approach; COPY and ADD have some additional properties to store the Chmod, Chown values, but other commands may not; perhaps using the FlagsUsed approach could make it more generic (we could make a supportedOptions variable, containing the supported options per command.

@thaJeztah
Copy link
Copy Markdown
Member Author

@tonistiigi @tiborvass PTAL; let me know what approach you think is best for this

@AkihiroSuda
Copy link
Copy Markdown
Member

AkihiroSuda commented Jan 21, 2021

Can we continue ignoring cache mounts? (With warning)

@thaJeztah
Copy link
Copy Markdown
Member Author

Can we continue ignoring cache mounts? (With warning)

I initially proposed doing so in moby/buildkit#799, but I know @tonistiigi didn't agree on silently ignoring them; moby/buildkit#799 (comment)

Also wondering if we have a mechanism to return warnings back to the CLI; we can of course log them, but daemon logs won't be visible to the user (unless explicitly looking for them), or do you know a way to return warnings?

Alternative would be to parse the Dockerfile on the client-side before starting the build, but that would complicate things (especially if client and daemon are different versions).

@thaJeztah
Copy link
Copy Markdown
Member Author

or do you know a way to return warnings?

Would writing to builder.Stdout / builder.Stderr work for that?

if err := d.builder.containerManager.Run(d.builder.clientCtx, cID, d.builder.Stdout, d.builder.Stderr); err != nil {

@thaJeztah
Copy link
Copy Markdown
Member Author

Yes, that looks to work to print warnings if we want to;

Sending build context to Docker daemon  2.095kB
Step 1/2 : FROM busybox
 ---> b97242f89c8a
Step 2/2 : RUN --mount=type=cache,target=/foo echo hello
 ---> [Warning] RUN --mount requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled.
 ---> Running in af2590e5f0d0
hello
Removing intermediate container af2590e5f0d0
 ---> e86a5e0157b2
Successfully built e86a5e0157b2

@thaJeztah
Copy link
Copy Markdown
Member Author

Perhaps needs a nolint;

 builder/dockerfile/dispatchers.go:96:21: error strings should not be capitalized or end with punctuation or a newline (golint)
 		return errors.New("ADD --chmod requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled.")
 		                  ^
 builder/dockerfile/dispatchers.go:118:21: error strings should not be capitalized or end with punctuation or a newline (golint)
 		return errors.New("COPY --chmod requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled.")

@thaJeztah thaJeztah force-pushed the improve_build_errors branch from 9d635e1 to 848c076 Compare March 4, 2021 18:01
@thaJeztah thaJeztah marked this pull request as ready for review March 4, 2021 18:02
@thaJeztah thaJeztah requested a review from tonistiigi as a code owner March 4, 2021 18:02
@thaJeztah thaJeztah force-pushed the improve_build_errors branch from 848c076 to b7ce94d Compare March 4, 2021 18:05
@thaJeztah
Copy link
Copy Markdown
Member Author

This should be ready for review now; @tonistiigi @AkihiroSuda @cpuguy83 ptal

@thaJeztah
Copy link
Copy Markdown
Member Author

@tonistiigi @AkihiroSuda @cpuguy83 ptal

Comment thread builder/dockerfile/dispatchers.go Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bit weird to have a return in a for loop. Would be slightly better with an if len(c.FlagsUsed) > 0 { return errors.Errorf(..., c.FlagsUsed[0]) }

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes, I think I started with creating an error-message for all flags or to have a "whitelist", but then decided "meh, just return an error for the first one"; I'll update

@tiborvass
Copy link
Copy Markdown
Contributor

Overall looks good to me

With the promotion of the experimental Dockerfile syntax to "stable", the Dockerfile
syntax now includes some options that are supported by BuildKit, but not (yet)
supported in the classic builder.

As a result, parsing a Dockerfile may succeed, but any flag that's known to BuildKit,
but not supported by the classic builder is silently ignored;

    $ mkdir buildkit_flags && cd buildkit_flags
    $ touch foo.txt

For example, `RUN --mount`:

    DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
    FROM busybox
    RUN --mount=type=cache,target=/foo echo hello
    EOF

    Sending build context to Docker daemon  2.095kB
    Step 1/2 : FROM busybox
     ---> 219ee5171f80
    Step 2/2 : RUN --mount=type=cache,target=/foo echo hello
     ---> Running in 022fdb856bc8
    hello
    Removing intermediate container 022fdb856bc8
     ---> e9f0988844d1
    Successfully built e9f0988844d1

Or `COPY --chmod` (same for `ADD --chmod`):

    DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
    FROM busybox
    COPY --chmod=0777 /foo.txt /foo.txt
    EOF

    Sending build context to Docker daemon  2.095kB
    Step 1/2 : FROM busybox
     ---> 219ee5171f80
    Step 2/2 : COPY --chmod=0777 /foo.txt /foo.txt
     ---> 8b7117932a2a
    Successfully built 8b7117932a2a

Note that unknown flags still produce and error, for example, the below fails because `--hello` is an unknown flag;

    DOCKER_BUILDKIT=0 docker build -<<EOF
    FROM busybox
    RUN --hello echo hello
    EOF

    Sending build context to Docker daemon  2.048kB
    Error response from daemon: dockerfile parse error line 2: Unknown flag: hello

With this patch applied
----------------------------

With this patch applied, flags that are known in the Dockerfile spec, but are not
supported by the classic builder, produce an error, which includes a link to the
documentation how to enable BuildKit:

    DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
    FROM busybox
    RUN --mount=type=cache,target=/foo echo hello
    EOF

    Sending build context to Docker daemon  2.048kB
    Step 1/2 : FROM busybox
     ---> b97242f89c8a
    Step 2/2 : RUN --mount=type=cache,target=/foo echo hello
    the --mount option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled

    DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<EOF
    FROM busybox
    COPY --chmod=0777 /foo.txt /foo.txt
    EOF

    Sending build context to Docker daemon  2.095kB
    Step 1/2 : FROM busybox
     ---> b97242f89c8a
    Step 2/2 : COPY --chmod=0777 /foo.txt /foo.txt
    the --chmod option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled

Signed-off-by: Sebastiaan van Stijn <[email protected]>
@thaJeztah thaJeztah force-pushed the improve_build_errors branch from b7ce94d to a09c027 Compare March 14, 2021 13:11
@thaJeztah
Copy link
Copy Markdown
Member Author

@tiborvass @AkihiroSuda updated; PTAL

Copy link
Copy Markdown
Member

@AkihiroSuda AkihiroSuda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but a nit

for _, f := range []string{"mount", "network", "security", "any-flag"} {
cmd.FlagsUsed = []string{f}
err := dispatch(sb, cmd)
assert.Error(t, err, fmt.Sprintf("the --%s option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled", f))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"the --any-flag option requires BuildKit" is slightly inaccurate. What about "the --%s option is not supported on legacy mode"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm... yes, that's a bit tricky; it would indeed suggest that in case someone made an actual RUN --i-made-a-typo, it would print the standard message; do you think we should keep an actual list of known options?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, actually, that should already be handled, because the frontend will produce an error;

DOCKER_BUILDKIT=0 docker build -<<EOF
FROM busybox
RUN --no-such-flag echo hello
EOF
Sending build context to Docker daemon  2.048kB
Error response from daemon: dockerfile parse error line 2: Unknown flag: no-such-flag

@thaJeztah
Copy link
Copy Markdown
Member Author

@tiborvass PTAL

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[20.10] Classic builder silently ignores unsupported Dockerfile command flags

3 participants