I am trying to build a docker image for my sample-go app.
I am running it from the sample-app folder itself and using the goland editor's terminal. But the build is failing and giving me certain errors.
My docker file looks like this:
FROM alpine:latest
RUN mkdir -p /src/build
WORKDIR /src/build
RUN apk add --no-cache tzdata ca-certificates
COPY ./configs /configs
COPY main /main
EXPOSE 8000
CMD ["/main"]
command for building:
docker build --no-cache --progress=plain - < Dockerfile
Error And Logs:
#1 [internal] load build definition from Dockerfile
#1 sha256:8bb9ee83603259cf748d90ce42602f12527fa720d7417da22799b2ad4e503497
#1 transferring dockerfile: 222B done
#1 DONE 0.0s
#2 [internal] load .dockerignore
#2 sha256:f93d938488588cd0e0a94d9d343fe69dcfd28d0cb1da95ad7aab00aac50235c3
#2 transferring context: 2B done
#2 DONE 0.0s
#3 [internal] load metadata for docker.io/library/alpine:latest
#3 sha256:13549c58a76bcb5dac9d52bc368a8fb6b5cf7659f94e3fa6294917b85546978d
#3 DONE 0.0s
#10 [1/6] FROM docker.io/library/alpine:latest
#10 sha256:d20daa00e252bfb345a1b4f53b6bb332aafe702d8de5e583a76fcd09ba7ea1c1
#10 CACHED
#7 [internal] load build context
#7 sha256:0f7a8a6082a837c139acc2855e1b745bba9f28cc96709d45cd0b7be42442c0e8
#7 transferring context: 2B done
#7 DONE 0.0s
#4 [2/6] RUN mkdir -p /src/build
#4 sha256:b9fa3007a44471d47414dd29b3ff07ead6af28ede820a2b4bae0ce84cf2c5a83
#4 CACHED
#5 [3/6] WORKDIR /src/build
#5 sha256:b2ec58a365fdd74c4f9030b0caff2e2225eea33617da306678ad037fce675388
#5 CACHED
#6 [4/6] RUN apk add --no-cache tzdata ca-certificates
#6 sha256:0966097abf956d5781bc2330d49cf715cd52c3807e8fedfff07dec50907ff03b
#6 CACHED
#9 [6/6] COPY main /main
#9 sha256:f4b81960427c014a020361bea0903728f289e1d796892fe0adc6409434f3ca76
#9 ERROR: "/main" not found: not found
#8 [5/6] COPY ./configs /configs
#8 sha256:630f272dd60dd307f40dbbdaef277ee0dfc24b71fa11e10a3b8efd64d3c05086
#8 ERROR: "/configs" not found: not found
#4 [2/6] RUN mkdir -p /src/build
#4 sha256:b9fa3007a44471d47414dd29b3ff07ead6af28ede820a2b4bae0ce84cf2c5a83
#4 DONE 0.2s
------
> [5/6] COPY ./configs /configs:
------
------
> [6/6] COPY main /main:
------
failed to compute cache key: "/main" not found: not found
PS: I am not able to find where is the problem? Help Please
The two folders /main and /configs does not exist.
The COPY command can't copy into this folders.
1. Solution
Create the folders on build
RUN mkdir -p /main
RUN mkdir -p /configs
And than use COPY
2. Solution
Try to build without COPY and CMD
Than run the the new image
exec into running container with bash or sh
Create the folders
Exit exec container
Create a new image of the running container with docker run commit
Stop the container and delete it
Build again with your new image and include COPY and CMD
This is a basic mistake.
COPY ./configs /configs: copy the folder configs from the host to the Docker image.
COPY main /main: copy the executable file main from the host to the Docker image.
The problems are:
The base Docker images do not have these folders /configs, /main. You must create them manually (Docker understood your command this way).
But I have some advice:
Create 2 Docker images for 2 purposes: build, production.
Copy the source code into Docker builder image which is use for building your app.
Copy necessary output files from the Docker builder image into the Docker production image.
In my case, the issue was the connected vpn/proxy network from my machine.
It worked after I disconnecting the vpn/proxy network.
In my case I missed the folder entry in .dockerignore file. Do something like that.
**/*
!docker-images
!configs
!main
Related
I'm building my docker images in GitLab CI and trying to cache the build so that if the app dependencies don't change, I don't need to re-build the entire image, but for some reason the Docker layer caching isn't working.
Dockerfile
FROM public.ecr.aws/lambda/python:3.9
RUN pip install poetry==1.3.2
WORKDIR /app
COPY ./pyproject.toml ./poetry.lock ./
RUN poetry config virtualenvs.create false && poetry install \
--no-interaction --no-ansi --without dev
ENV PYTHONPATH=/app
COPY . .
CMD ["app.handler"]
GitLab CI Log Output
$ docker build --cache-from "${CI_REGISTRY_IMAGE}:latest" -t $IMAGE_NAME .
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 321B done
#1 DONE 0.0s
#2 [internal] load .dockerignore
#2 transferring context: 145B done
#2 DONE 0.0s
#3 [internal] load metadata for public.ecr.aws/lambda/python:3.9
#3 DONE 0.5s
#4 importing cache manifest from registry.gitlab.com/foo/bar:latest
#4 DONE 0.0s
#5 [1/6] FROM public.ecr.aws/lambda/python:3.9#sha256:7e3bcdc955c2c3cab1101bbbfd55849c0f56a6b5a21a149d50df91deacad6aac
#5 resolve public.ecr.aws/lambda/python:3.9#sha256:7e3bcdc955c2c3cab1101bbbfd55849c0f56a6b5a21a149d50df91deacad6aac 0.0s done
#5 sha256:ebf75d2390460a5a59d7c52cc4d6e7f6840c610b399c069b0ccf531792d77c7d 3.00kB / 3.00kB done
#5 sha256:7e3bcdc955c2c3cab1101bbbfd55849c0f56a6b5a21a149d50df91deacad6aac 772B / 772B done
#5 sha256:e3d5decbab4ddca757c7de36637b50826165efddecfe8b7ef76db761f51b790d 1.58kB / 1.58kB done
#5 DONE 0.3s
#6 [internal] load build context
#6 transferring context: 1.16MB 0.2s done
#6 DONE 0.3s
...
The pipeline is successfully picking up on the latest build as you can see from the importing cache manifest from registry.gitlab.com/foo/bar:latest line. However, it doesn't seem to be caching any of the build steps.
Can anyone see a reason why the cache might be missing in this case?
I have two ContainerApps in the same solution, both build and run locally in Docker desktop, and 1 of them publishes to an Azure ContainerApp properly. The other one appears identical structurally and w.r.t. dockerfile/projectFile but fails to publish with the "failed to compute cache key" project copy error
Windows 11
VisualStudio 17.3.4
Docker Desktop 4.12.0 / WSL2
\SolutionDir
\FR911.Worker.Project1
Dockerfile
FR911.Worker.Project1.csproj
\FR911.Worker.Project2
Dockerfile
FR911.Worker.Project2.csproj
Dockerfile for Project1 (publishes correctly)
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["FR911.Worker.Project1/FR911.Worker.Project1.csproj", "FR911.Worker.Project1/"]
RUN dotnet restore "FR911.Worker.Project1/FR911.Worker.Project1.csproj"
COPY . .
WORKDIR "/src/FR911.Worker.Project1"
RUN dotnet build "FR911.Worker.Project1.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "FR911.Worker.Project1.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "FR911.Worker.Project1.dll"]
Dockerfile for Project2 (does not publish)
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["FR911.Worker.Project2/FR911.Worker.Project2.csproj", "FR911.Worker.Project2/"]
RUN dotnet restore "FR911.Worker.Project2/FR911.Worker.Project2.csproj"
COPY . .
WORKDIR "/src/FR911.Worker.Project2"
RUN dotnet build "FR911.Worker.Project2.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "FR911.Worker.Project2.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "FR911.Worker.Project2.dll"]
Log for Project1 Publish (publishes correctly)
FR911.Worker.Project1 -> G:\FR911Cloud\FR911.Worker.Project1\bin\Release\net6.0\FR911.Worker.Project1.dll
FR911.Worker.Project1 -> G:\FR911Cloud\FR911.Worker.Project1\obj\Docker\publish\
Docker version 20.10.17, build 100c701
docker build -f "G:\FR911Cloud\FR911.Worker.Project1\Dockerfile" --force-rm -t fr911workerProject1 --label "com.microsoft.created-by=visual-studio" --label "com.microsoft.visual-studio.project-name=FR911.Worker.Project1" "G:\FR911Cloud"
#1 [internal] load build definition from Dockerfile
#1 sha256:f35cad84d8f344f22ff5c01ec0f2b5593a1e8e8106c5a291cbb81d75702e8f4b
#1 transferring dockerfile: 980B done
#1 DONE 0.0s
#2 [internal] load .dockerignore
#2 sha256:773696df5d1b3a2e3082d19ade268ad9cee78057bcc7d5bf617dbf42632a68c3
#2 transferring context: 35B 0.0s done
#2 DONE 0.0s
#4 [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:6.0
#4 sha256:ac4494cbca04ddb415c76edcbcc7688784c2a6ea65dd656286c013738aa3b75f
#4 DONE 0.0s
#3 [internal] load metadata for mcr.microsoft.com/dotnet/sdk:6.0
#3 sha256:9eb4f6c3944cfcbfe18b9f1a753c769fc35341309a8d4a21f8937f47e94c712b
#3 DONE 0.3s
#8 [build 1/7] FROM mcr.microsoft.com/dotnet/sdk:6.0#sha256:a788c58ec0604889912697286ce7d6a28a12ec28d375250a7cd547b619f19b37
#8 sha256:fff7c57bbc14150de4574cecfd040bdf8a628dc4f5265c2e038bd3fd64bdd55a
#8 DONE 0.0s
#5 [base 1/2] FROM mcr.microsoft.com/dotnet/aspnet:6.0
#5 sha256:50f1ddc10932c4a74c7af5704e931a9489c710faea4f2381fe2380827a900e00
#5 DONE 0.0s
#10 [internal] load build context
#10 sha256:a7dbe6d5c5594ebe893dc072a634555501969a46c9ae9d648db74ea23d0ee810
#10 transferring context: 673.15kB 1.4s done
#10 DONE 1.4s
#9 [build 2/7] WORKDIR /src
#9 sha256:fd721b9ab8612450c39dfab43831d16b893f71b294b4d92a8c1d6fdaf0c47a22
#9 CACHED
#11 [build 3/7] COPY [FR911.Worker.Project1/FR911.Worker.Project1.csproj, FR911.Worker.Project1/]
#11 sha256:91f73142833c22e9b36d6dfb095a3421596ba684c3076da61c19a7d7aae5f1bc
#11 CACHED
... continues until success
Log for Project2 Publish (fails)
FR911.Worker.Project2 -> G:\FR911Cloud\FR911.Worker.Project2\bin\Release\net6.0\FR911.Worker.Project2.dll
FR911.Worker.Project2 -> G:\FR911Cloud\FR911.Worker.Project2\obj\Docker\publish\
Docker version 20.10.17, build 100c701
docker build -f "G:\FR911Cloud\FR911.Worker.Project2\Dockerfile" --force-rm -t fr911workerProject2 --label "com.microsoft.created-by=visual-studio" --label "com.microsoft.visual-studio.project-name=FR911.Worker.Project2" "G:\FR911Cloud"
#1 [internal] load build definition from Dockerfile
#1 sha256:69dc10bf751883ff6fa38a281a2a6e3570552aeded8c5f82fc34e54ad9c820c0
#1 transferring dockerfile: 32B done
#1 DONE 0.0s
#2 [internal] load .dockerignore
#2 sha256:5089ff4c45602d16118aed124a38ee56bbe29b79f636b726f36a16f813470f64
#2 transferring context: 35B 0.0s done
#2 DONE 0.0s
#4 [internal] load metadata for mcr.microsoft.com/dotnet/aspnet:6.0
#4 sha256:ac4494cbca04ddb415c76edcbcc7688784c2a6ea65dd656286c013738aa3b75f
#4 DONE 0.0s
#3 [internal] load metadata for mcr.microsoft.com/dotnet/sdk:6.0
#3 sha256:9eb4f6c3944cfcbfe18b9f1a753c769fc35341309a8d4a21f8937f47e94c712b
#3 DONE 0.3s
#8 [build 1/7] FROM mcr.microsoft.com/dotnet/sdk:6.0#sha256:a788c58ec0604889912697286ce7d6a28a12ec28d375250a7cd547b619f19b37
#8 sha256:fff7c57bbc14150de4574cecfd040bdf8a628dc4f5265c2e038bd3fd64bdd55a
#8 DONE 0.0s
#9 [build 2/7] WORKDIR /src
#9 sha256:fd721b9ab8612450c39dfab43831d16b893f71b294b4d92a8c1d6fdaf0c47a22
#9 CACHED
#5 [base 1/2] FROM mcr.microsoft.com/dotnet/aspnet:6.0
#5 sha256:50f1ddc10932c4a74c7af5704e931a9489c710faea4f2381fe2380827a900e00
#5 DONE 0.0s
#10 [internal] load build context
#10 sha256:193c5f727995c82adbaa58aed42c8a05308b1cbab22f31bea74fad6ffe5c2e83
#10 transferring context: 673.11kB 1.4s done
#10 DONE 1.4s
#11 [build 3/7] COPY [FR911.Worker.Project2/FR911.Worker.Project2.csproj, FR911.Worker.Project2/]
#11 sha256:687c29b5b257b0efc68aa34321eca5a6576a579c63371f320e619daa0c9c705c
#11 ERROR: "/FR911.Worker.Project2/FR911.Worker.Project2.csproj" not found: not found
------
> [build 3/7] COPY [FR911.Worker.Project2/FR911.Worker.Project2.csproj, FR911.Worker.Project2/]:
------
failed to compute cache key: "/FR911.Worker.Project2/FR911.Worker.Project2.csproj" not found: not found
The publish profiles are also identical except for the container & environment names, and the project files both target net6.0 and Linux. The Docker command that VisualStudio runs to build each also seems identical(except for the path & name):
docker build -f "G:\FR911Cloud\FR911.Worker.Project2\Dockerfile" --force-rm -t fr911workerProject2 --label "com.microsoft.created-by=visual-studio" --label "com.microsoft.visual-studio.project-name=FR911.Worker.Project2" "G:\FR911Cloud"
I'm having trouble finding out why one works and the other fails - presumably because it cannot find the project at step 3 of the build from the dockerfile COPY ["FR911.Worker.Project2/FR911.Worker.Project2.csproj", "FR911.Worker.Project2/"]
It was a casing issue in the Dockerfile on the project file name.
COPY ["FR911.Worker.Project2/FR911.Worker.Project2.csproj", "FR911.Worker.Project2/"]
is not the same as
COPY ["FR911.Worker.Project2/FR911.Worker.project2.csproj", "FR911.Worker.Project2/"]
I use Gitpod as my online IDE. Gitpod builds a Docker container from a user-provided Dockerfile. The user doesn't have access to the terminal which runs the docker build command and thus no flags can be passed. At the moment, my Dockerfile fails build because Docker incorrectly caches instructions, including mkdir commands. Specifically, given the Dockerfile:
# Base image is one of Ubuntu's official distributions.
FROM ubuntu:20.04
# Install curl.
RUN apt-get update
RUN apt-get -y install sudo
RUN sudo apt-get install -y curl
RUN sudo apt-get install -y python3-pip
# Download Google Cloud CLI installation script.
RUN mkdir -p /tmp/google-cloud-download
RUN curl -sSL https://sdk.cloud.google.com > /tmp/google-cloud-download/install.sh
# Install Google Cloud CLI.
RUN mkdir -p /tmp/google-cloud-cli
RUN bash /tmp/gcloud.sh --install-dir=/tmp/google-cloud-cli --disable-prompts
# Move the content of /tmp/gcloud into the container.
COPY /tmp/google-cloud-cli /google-cloud-cli
The build fails with the following log:
#1 [internal] load .dockerignore
#1 transferring context: 114B done
#1 DONE 0.0s
#2 [internal] load build definition from Dockerfile
#2 transferring dockerfile: 1.43kB done
#2 DONE 0.0s
#3 [internal] load metadata for docker.io/library/ubuntu:20.04
#3 DONE 1.2s
#4 [ 1/13] FROM docker.io/library/ubuntu:20.04#sha256:af5efa9c28de78b754777af9b4d850112cad01899a5d37d2617bb94dc63a49aa
#4 resolve docker.io/library/ubuntu:20.04#sha256:af5efa9c28de78b754777af9b4d850112cad01899a5d37d2617bb94dc63a49aa done
#4 sha256:3b65ec22a9e96affe680712973e88355927506aa3f792ff03330f3a3eb601a98 0B / 28.57MB 0.1s
#4 ...
#5 [internal] load build context
#5 transferring context: 1.70MB 0.1s done
#5 DONE 0.1s
#6 [ 5/13] RUN sudo apt-get install -y python3-pip
#6 CACHED
#7 [ 9/13] RUN bash /tmp/gcloud.sh --install-dir=/tmp/google-cloud-cli --disable-prompts
#7 CACHED
#8 [ 4/13] RUN sudo apt-get install -y curl
#8 CACHED
#9 [ 7/13] RUN curl -sSL https://sdk.cloud.google.com > /tmp/google-cloud-download/install.sh
#9 CACHED
#10 [ 8/13] RUN mkdir -p /tmp/google-cloud-cli
#10 CACHED
#11 [ 3/13] RUN apt-get -y install sudo
#11 CACHED
#12 [ 6/13] RUN mkdir -p /tmp/google-cloud-download
#12 CACHED
#13 [10/13] COPY /tmp/google-cloud-cli /google-cloud-cli
#13 ERROR: failed to calculate checksum of ref j0t2zzxkw0572xeibprcp5ebn::w8exf03p6f5luerwcumrkxeii: "/tmp/google-cloud-cli": not found
#14 [ 2/13] RUN apt-get update
#14 CANCELED
------
> [10/13] COPY /tmp/google-cloud-cli /google-cloud-cli:
------
Dockerfile:22
--------------------
20 |
21 | # Move the content of /tmp/gcloud into the container.
22 | >>> COPY /tmp/google-cloud-cli /google-cloud-cli
23 |
24 | # Copy local code to the container image.
--------------------
error: failed to solve: failed to compute cache key: failed to calculate checksum of ref j0t2zzxkw0572xeibprcp5ebn::w8exf03p6f5luerwcumrkxeii: "/tmp/google-cloud-cli": not found
{"#type":"type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent","command":"build","error":"exit status 1","level":"error","message":"build failed","serviceContext":{"service":"bob","version":""},"severity":"ERROR","time":"2022-08-28T05:31:11Z"}
exit
headless task failed: exit status 1
Other than stop using Gitpod altogheter, which I'm considering, how could I solve this issue?
When you COPY /tmp/google-cloud-cli /google-cloud-cli, it tries to copy a file from outside of Docker space (the build context, the directory argument to docker build, frequently the same directory as the Dockerfile) into the image.
In your case, you already have the file inside the image, so you need to RUN cp or mv or another command to relocate the existing file.
RUN bash /tmp/gcloud.sh --install-dir=/tmp/google-cloud-cli --disable-prompts
RUN mv /tmp/google-cloud-cli /google-cloud-cli
A way to invalidate caches of docker layers in Gitpod is to put in an environment variable above all the layers you want to invalidate and change its value.
FROM gitpod/workspace-full
ENV INVALIDATE_CACHE=1
...
(If this doesn't help, please share a repository with the mentioned Dockerfile to reproduce)
I have a simple application that uses github.com/go-sql-driver/mysql to connect to a MySQL database and execute simple queries. This all works fine on my local machine, however when I try to build it using docker build I get the following output:
[+] Building 4.1s (9/10)
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 104B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/golang:onbuild 1.3s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 5.63kB 0.0s
=> CACHED [1/2] FROM docker.io/library/golang:onbuild#sha256:c0ec19d49014d604e4f62266afd490016b11ceec103f0b7ef44 0.0s
=> [2/2] COPY . /go/src/app 0.1s
=> [3/2] RUN go-wrapper download 2.0s
=> ERROR [4/2] RUN go-wrapper install 0.6s
------
> [4/2] RUN go-wrapper install:
#8 0.465 + exec go install -v
#8 0.535 github.com/joho/godotenv
#8 0.536 github.com/go-sql-driver/mysql
#8 0.581 # github.com/go-sql-driver/mysql
#8 0.581 ../github.com/go-sql-driver/mysql/driver.go:88: undefined: driver.Connector
#8 0.581 ../github.com/go-sql-driver/mysql/driver.go:99: undefined: driver.Connector
#8 0.581 ../github.com/go-sql-driver/mysql/nulltime.go:36: undefined: sql.NullTime
------
executor failed running [/bin/sh -c go-wrapper install]: exit code: 2
My go version is up to date and I am using the following dockerfile:
FROM golang:onbuild
To my knowledge this should go get all the packages it requires. I've also tried it this way:
FROM golang:onbuild
RUN go get "github.com/go-sql-driver/mysql"
This had the same output.
Note that in my code I import the package like this:
import _ "github.com/go-sql-driver/mysql"
I also use other packages from github, these seem to work fine.
The Docker community has generally been steering away from the Dockerfile ONBUILD directive, since it makes it very confusing what will actually happen in derived images (see the various comments around "is that really the entire Dockerfile?"). If you search Docker Hub for the golang:onbuild image you'll discover that this is Go 1.7 or 1.8; Go modules were introduced in Go 1.11.
You'll need to update to a newer base image, and that means writing out the Dockerfile steps by hand. For a typical Go application this would look like
FROM golang:1.18 AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY ./ ./
RUN go build -o myapp .
FROM ubuntu:20.04
COPY --from=build /app/myapp /usr/local/bin
CMD ["myapp"]
(In the final stage you may need to RUN apt-get update && apt-get install ... a MySQL client library or other tools.)
My working directory contains two files:
Dockerfile given below
FROM ubuntu:20.04
COPY --chmod=755 ./hello.txt /opt/
an empty hello.txt file with 644 chmod permissions
I ran the following sequence of commands, using Docker 20.10.8:
docker build . first build, nothing is re-used from the cache
#6 [2/2] COPY --chmod=755 ./hello.txt /opt/
#6 sha256:2cb62e01e8edffaed06aeda7d8fa85b5f89850564f7458ab0be5cbe3d90478bf
#6 DONE 0.0s
docker build . second build without any change, all layers are re-used from the cache
#6 [2/2] COPY --chmod=755 ./hello.txt /opt/
#6 sha256:7d6fd54f3d6cc543bd4d186861d7ae116c5ed16c7ebca40a37fdbe027bce9ecc
#6 CACHED
chmod 777 hello.txt change permissions from 644 to 777
docker build . => another build after changing permissions, COPY --chmod layer is not re-used from the cache
#4 [2/2] COPY --chmod=755 ./hello.txt /opt/
#4 sha256:3f74f87506d9be5cbb722a723bf1422ce0a24b538201d719f712bbb4915de5a6
#4 DONE 0.0s
Why is the command 4 not re-using the build cache like command 2, even though the permissions and the content of the file are identical in the image due to the --chmod flag in the COPY instruction?