From 847aef321eb5f6b0b5101135788cccbfd8b84cd3 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Tue, 10 Aug 2021 23:13:00 +0200 Subject: [PATCH] build: fix AddDockerfileToBuildContext not de-referencing tar header template Commit https://github.com/docker/docker/commit/73aef6edfe5ae533f9cf547f924c98a9b0f7be59 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 --- cli/command/image/build/context.go | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/cli/command/image/build/context.go b/cli/command/image/build/context.go index 2509f66de4..ccf2e9ec75 100644 --- a/cli/command/image/build/context.go +++ b/cli/command/image/build/context.go @@ -378,26 +378,32 @@ func AddDockerfileToBuildContext(dockerfileCtx io.ReadCloser, buildCtx io.ReadCl return nil, "", err } 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] buildCtx = archive.ReplaceFileTarWrapper(buildCtx, map[string]archive.TarModifierFunc{ // Add the dockerfile with a random filename - randomName: func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) { - return hdrTmpl, file, nil + randomName: func(_ string, _ *tar.Header, _ io.Reader) (*tar.Header, []byte, error) { + 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 ".dockerignore": func(_ string, h *tar.Header, content io.Reader) (*tar.Header, []byte, error) { if h == nil { - h = hdrTmpl + h = &tar.Header{ + Name: ".dockerignore", + Mode: 0600, + ModTime: now, + Typeflag: tar.TypeReg, + AccessTime: now, + ChangeTime: now, + } } b := &bytes.Buffer{}