build: fix AddDockerfileToBuildContext not de-referencing tar header template

Commit 73aef6edfe
modified archive.ReplaceFileTarWrapper to set the Name field in the tar header,
if the field was not set.

That change exposed an issue in how a Dockerfile from stdin was sent to the daemon.
When attempting to build using a build-context, and a Dockerfile from stdin, the
following happened:

```bash
mkdir build-stdin && cd build-stdin && echo hello > hello.txt

DOCKER_BUILDKIT=0 docker build --no-cache -t foo -f- . <<'EOF'
FROM alpine
COPY . .
EOF

Sending build context to Docker daemon  2.607kB
Error response from daemon: dockerfile parse error line 1: unknown instruction: .DOCKERIGNORE
```

Removing the `-t foo`, oddly lead to a different failure:

```bash
DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<'EOF'
FROM alpine
COPY . .
EOF

Sending build context to Docker daemon  2.581kB
Error response from daemon: Cannot locate specified Dockerfile: .dockerfile.701d0d71fb1497d6a7ce
```

From the above, it looks like the tar headers got mangled, causing (in the first
case) the daemon to use the build-context tar as a plain-text file, and therefore
parsing it as Dockerfile, and in the second case, causing it to not being able to
find the Dockerfile in the context.

I noticed that both TarModifierFuncs were using the same `hdrTmpl` struct, which
looks to caused them to step on each other's toes. Changing them to each initialize
their own struct made the issue go away.

After this change:

```bash
DOCKER_BUILDKIT=0 docker build --no-cache -t foo -f- . <<'EOF'
FROM alpine
COPY . .
EOF
Sending build context to Docker daemon  2.607kB
Step 1/2 : FROM alpine
 ---> d4ff818577bc
Step 2/2 : COPY . .
 ---> 556f745e6938
Successfully built 556f745e6938
Successfully tagged foo:latest

DOCKER_BUILDKIT=0 docker build --no-cache -f- . <<'EOF'
FROM alpine
COPY . .
EOF

Sending build context to Docker daemon  2.607kB
Step 1/2 : FROM alpine
 ---> d4ff818577bc
Step 2/2 : COPY . .
 ---> aaaee43bec5e
Successfully built aaaee43bec5e
```

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn 2021-08-10 23:13:00 +02:00
parent f1e5329713
commit 847aef321e
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
1 changed files with 18 additions and 12 deletions

View File

@ -378,26 +378,32 @@ func AddDockerfileToBuildContext(dockerfileCtx io.ReadCloser, buildCtx io.ReadCl
return nil, "", err return nil, "", err
} }
now := time.Now() now := time.Now()
hdrTmpl := &tar.Header{
Mode: 0600,
Uid: 0,
Gid: 0,
ModTime: now,
Typeflag: tar.TypeReg,
AccessTime: now,
ChangeTime: now,
}
randomName := ".dockerfile." + stringid.GenerateRandomID()[:20] randomName := ".dockerfile." + stringid.GenerateRandomID()[:20]
buildCtx = archive.ReplaceFileTarWrapper(buildCtx, map[string]archive.TarModifierFunc{ buildCtx = archive.ReplaceFileTarWrapper(buildCtx, map[string]archive.TarModifierFunc{
// Add the dockerfile with a random filename // Add the dockerfile with a random filename
randomName: func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) { randomName: func(_ string, _ *tar.Header, _ io.Reader) (*tar.Header, []byte, error) {
return hdrTmpl, file, nil header := &tar.Header{
Name: randomName,
Mode: 0600,
ModTime: now,
Typeflag: tar.TypeReg,
AccessTime: now,
ChangeTime: now,
}
return header, file, nil
}, },
// Update .dockerignore to include the random filename // Update .dockerignore to include the random filename
".dockerignore": func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) { ".dockerignore": func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) {
if h == nil { if h == nil {
h = hdrTmpl h = &tar.Header{
Name: ".dockerignore",
Mode: 0600,
ModTime: now,
Typeflag: tar.TypeReg,
AccessTime: now,
ChangeTime: now,
}
} }
b := &bytes.Buffer{} b := &bytes.Buffer{}