Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker Here-Documents line endings #3329

Closed
Forinil opened this issue Nov 28, 2022 · 3 comments
Closed

Docker Here-Documents line endings #3329

Forinil opened this issue Nov 28, 2022 · 3 comments

Comments

@Forinil
Copy link

Forinil commented Nov 28, 2022

Problem description

Scripts either passed to RUN or created by COPY do not work if the image is built on Windows.

Steps to recreate

  1. Create Dockerfile as specified in the documentation Running a multi-line script
  2. Attempt to build the image on Windows: docker build -t here-file-test:latest .

Expected outcome

The image is built.

Actual outcome:

[+] Building 3.0s (9/9) FINISHED
 => [internal] load build definition from Dockerfile                                                                    0.0s
 => => transferring dockerfile: 147B                                                                                        0.0s 
 => => transferring context: 35B                                                                                            0.0s 
 => resolve image config for docker.io/docker/dockerfile:1                                                                  1.5s 
 => CACHED docker-image://docker.io/docker/dockerfile:1@sha256:9ba7531bd80fb0a858632727cf7a112fbfd19b17e94c4e84ced81e24ef1  0.0s
 => [internal] load build definition from Dockerfile                                                                   0.0s
 => [internal] load metadata for docker.io/library/debian:latest                                                            0.9s 
 => CACHED [1/2] FROM docker.io/library/debian@sha256:3066ef83131c678999ce82e8473e8d017345a30f5573ad3e44f62e5c9c46442b      0.0s
 => ERROR [2/2] RUN <<EOT bash                                                                                              0.3s 
------
 > [2/2] RUN <<EOT bash:
#9 0.316 E: Invalid operation update
#9 0.321 Reading package lists...
#9 0.326 Building dependency tree...
#9 0.326 Reading state information...
#9 0.327 E: Unable to locate package vim
------
executor failed running [/bin/sh -c <<EOT bash
  apt-get update
  apt-get install -y vim
EOT]: exit code: 100

Reason for build failure

If a Dockerfile is created - or checked out from Git - on Windows, chances are that it has CLRF line endings, as those are the Windows default. The current implementation of Here-Documents uses whatever line endings Dockerfile has when creating those files. This breaks the build as Linux shells cannot correctly run scripts with CLRF line endings for some reason - although there's a patch for Bash that fixes that.

Possible solution

I don't know what the proper solution for this issue should be or is possible to implement. Still, I'd expect BuildKit, instead of using whatever line endings are in the Dockerfile, would use the default line endings for the architecture reported by Docker Engine as even on Windows docker version correctly reports its architecture as linux/amd64.

At the very least it should be mentioned in the documentation as a possible problem.

@jedevc
Copy link
Member

jedevc commented Jan 17, 2023

Thanks for the bug report 🎉 Sorry it's taken so long to get round to, the v0.11 release has made things a bit busy 👍

This is tricky 😬

One of the things discussed when designing the original heredocs syntax was that it's important to preserve the contents of the heredoc as much as possible. For the most part, the heredocs really aren't processed by buildkit - except to detect the end of them, and pass them to the shell, in your case, bash.

Now, we could potentially strip away the CLRF newlines, and replace them with LF newlines ('\n'). However, in doing that we'd be making assumptions about how a given shell works. We've tried to avoid this kind of assumption as much as possible - to do this properly, we'd actually need to implement full-on quote parsing, something we really want to avoid doing (mostly because writing sh-compliant quote parsing is a misery, and very easy to screw up).

For example:

RUN <<EOT
  echo "foo
  bar"
EOT

If we perform CLRF replacement here, it's probably not alright to remove it in the middle of the echo - but to know that, we'd need to implement the quote parsing.

I think we probably want to fix this with docs/tooling changes, as opposed to manipulating the contents of the heredoc. I think it's probably something we can add in the docs somewhere, at the very least clarifying how heredoc content is captured and passed to the shell. I'm not sure if we would want a warning: it could be valid for a shell to accept CRLF line endings - for example, powershell both on windows and linux allows it (I think?).

Maybe long-term this is information to be captured by a linter - there has been discussion as to whether there should be an official dockerfile linter, and maybe one of the rules should be to detect if CRLF endings are being used.

TL;DR: I think a docs change here is reasonable, anything else is probably out-of-scope for now.

@jedevc
Copy link
Member

jedevc commented Jan 17, 2023

As a workaround if you want to continue to use CRLF endings, you could use something like the following:

RUN cat <<EOT | tr -d '\r' | sh
...
EOT

However, I'd probably lean towards a solution that removes windows-line endings from the Dockerfile in the first place.

@tonistiigi
Copy link
Member

moving tracking for this issue to #4282

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants