moby / buildkit

concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit
https://github.com/moby/moby/issues/34227
Apache License 2.0
8.14k stars 1.15k forks source link

"error from receiver: failed to rename .git\objects..." when outputting an existing file in git on Windows #2164

Open tomhoward87 opened 3 years ago

tomhoward87 commented 3 years ago

Apologies if this is the wrong place but I believe the issue lies with the output mode of buildkit on Windows when inside a git folder. I have made a simple Dockerfile that demonstrates the issue.

FROM alpine:3.13 AS base

WORKDIR /src
COPY . .
RUN echo "bla" >> /src/bla

FROM scratch AS end
COPY --from=base /src/ /

When I run docker build . --output=. the first time it runs with no issues, creating a file called bla.

However if I run git init, then git add Dockerfile and try building again, I get the following error:

#10 exporting to client
#10 sha256:b60a1292d407630dbb741f28ab6ea4ce3cca872ac28eeee56f4e66a182eca4bc
#10 copying files 11.64kB 0.1s
#10 copying files 25.41kB 0.2s done
#10 ERROR: error from receiver: failed to rename .git\objects\6d\.tmp.943549809 to .git\objects\6d\3ed2f8a87e63b5c06c7a08c2ab46b7b044c0e9: rename .git\objects\6d\.tmp.943549809 .git\objects\6d\3ed2f8a87e63b5c06c7a08c2ab46b7b044c0e9: Access is denied.
------
 > exporting to client:
------
error from receiver: failed to rename .git\objects\6d\.tmp.943549809 to .git\objects\6d\3ed2f8a87e63b5c06c7a08c2ab46b7b044c0e9: rename .git\objects\6d\.tmp.943549809 .git\objects\6d\3ed2f8a87e63b5c06c7a08c2ab46b7b044c0e9: Access is denied.

This does not happen on other platforms, nor does it happen if the directory is not initialised for git or if git is initialised but no files have been added.

tonistiigi commented 3 years ago

@TBBle ideas?

TBBle commented 3 years ago

I can reproduce this, but only if I build with

docker build . --output .

If I have the Dockerfile somewhere else, I can run

docker build ..\context\ --output .

repeatedly, and it happily overwrites the file.

My guess is that the .git directory is being included in the context, carried through COPY . . and COPY --from=base, and is then trying to be written out in --output, but cannot overwrite the file because it is read-only.

Before run:

C:\Users\paulh\bkbug\git
> ls -Recurse .\.git\objects\

    Directory: C:\Users\paulh\bkbug\git\.git\objects

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          12/06/2021  4:00 PM                74
d----          12/06/2021  4:00 PM                info
d----          12/06/2021  4:00 PM                pack

    Directory: C:\Users\paulh\bkbug\git\.git\objects\74

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-ar--          12/06/2021  4:00 PM            119 bc6cf0dcb2d1f66ba26e6c32888a302240de3f

After run

C:\Users\paulh\bkbug\git
> ls -Recurse .\.git\objects\

    Directory: C:\Users\paulh\bkbug\git\.git\objects

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          12/06/2021  4:01 PM                74
d----          12/06/2021  4:00 PM                info
d----          12/06/2021  4:00 PM                pack

    Directory: C:\Users\paulh\bkbug\git\.git\objects\74

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-ar--          12/06/2021  3:58 PM              0 .tmp.686810237
-ar--          12/06/2021  4:00 PM            119 bc6cf0dcb2d1f66ba26e6c32888a302240de3f

It works if I create .dockerignore

.git

And it reproduces without git if I have separate context and output directories with the given Dockerfile, and have a read-only bla in the latter:

> dir .\context\

    Directory: C:\Users\paulh\bkbug\context

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          12/06/2021  3:52 PM            129 Dockerfile
> dir .\output\

    Directory: C:\Users\paulh\bkbug\output

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-ar--          12/06/2021  3:53 PM              4 bla
-a---          12/06/2021  3:52 PM              0 Dockerfile
> docker build .\context\ --output .\output\
[+] Building 1.5s (10/10) FINISHED
 => [internal] load build definition from Dockerfile                                                                                                                                                                              0.0s
 => => transferring dockerfile: 32B                                                                                                                                                                                               0.0s
 => [internal] load .dockerignore                                                                                                                                                                                                 0.0s
 => => transferring context: 2B                                                                                                                                                                                                   0.0s
 => [internal] load metadata for docker.io/library/alpine:3.13                                                                                                                                                                    1.3s
 => [internal] load build context                                                                                                                                                                                                 0.0s
 => => transferring context: 32B                                                                                                                                                                                                  0.0s
 => [base 1/4] FROM docker.io/library/alpine:3.13@sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f                                                                                                         0.0s
 => CACHED [base 2/4] WORKDIR /src                                                                                                                                                                                                0.0s
 => CACHED [base 3/4] COPY . .                                                                                                                                                                                                    0.0s
 => CACHED [base 4/4] RUN echo "bla" >> /src/bla                                                                                                                                                                                  0.0s
 => CACHED [end 1/1] COPY --from=base /src/ /                                                                                                                                                                                     0.0s
 => ERROR exporting to client                                                                                                                                                                                                     0.0s
 => => copying files 52B                                                                                                                                                                                                          0.0s
------
 > exporting to client:
------
error from receiver: failed to rename output\.tmp.832333578 to output\bla: rename output\.tmp.832333578 output\bla: Access is denied.
C:\Users\paulh\bkbug
> dir .\output\

    Directory: C:\Users\paulh\bkbug\output

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a---          12/06/2021  3:53 PM              0 .tmp.832333578
-ar--          12/06/2021  3:53 PM              4 bla
-a---          12/06/2021  3:52 PM              0 Dockerfile

I'm not sure if --output is supposed to successfully overwrite read-only files, though, so I don't know if this is user-error or a buildkit bug.

Apparently git objects are always read-only, so this shouldn't be a Windows-specific behaviour; so I'd guess that on Linux, BuildKit does overwrite the output files successfully, even if read-only.

It's also possible this is a problem due to interaction of read-only with the WSL2-based Docker setup, in which case it might be a Docker problem, rather than a BuildKit problem (or even a WSL2 problem...).

It's also possible that "rename over the top if a read-only file" is invalid as an operation on Windows, but valid on Linux, due to different permission semantics, and so we need to always unlink the target first (since we don't know this is Windows underneath in the context of BuildKit).