Merge pull request #18582 from dvdksn/add-bestpractice

build: refresh ADD and COPY recommendations
This commit is contained in:
David Karlsson 2023-11-03 11:00:59 +01:00 committed by GitHub
commit 80e57e64a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 47 additions and 38 deletions

View File

@ -302,53 +302,62 @@ For more information about `ENV`, see [Dockerfile reference for the ENV instruct
### ADD or COPY ### ADD or COPY
Although `ADD` and `COPY` are functionally similar, generally speaking, `COPY` `ADD` and `COPY` are functionally similar. `COPY` supports basic copying of
is preferred. Thats because its more transparent than `ADD`. `COPY` only files into the container, from the [build context](../../build/building/context.md)
supports the basic copying of local files into the container, while `ADD` has or from a stage in a [multi-stage build](../../build/building/multi-stage.md).
some features (like local-only tar extraction and remote URL support) that are `ADD` supports features for fetching files from remote HTTPS and Git URLs, and
not immediately obvious. Consequently, the best use for `ADD` is local tar file extracting tar files automatically when adding files from the build context.
auto-extraction into the image, as in `ADD rootfs.tar.xz /`.
If you have multiple Dockerfile steps that use different files from your You'll mostly want to use `COPY` for copying files from one stage to another in
context, `COPY` them individually, rather than all at once. If a multi-stage build. If you need to add files from the build context to the
a specifically required file changes, then this ensures that container temporarily to execute a `RUN` instruction, you can often substitute
only that step's build cache is invalidated, forcing only that step to be run again. the `COPY` instruction with a bind mount instead. For example, to temporarily
add a `requirements.txt` file for a `RUN pip install` instruction:
For example:
```dockerfile ```dockerfile
COPY requirements.txt /tmp/ RUN --mount=type=bind,source=requirements.txt,target=/tmp/requirements.txt \
RUN pip install --requirement /tmp/requirements.txt pip install --requirement /tmp/requirements.txt
COPY . /tmp/
``` ```
Results in fewer cache invalidations for the `RUN` step, than if you put the Bind mounts are more efficient than `COPY` for including files from the build
`COPY . /tmp/` before it. context in the container. Note that bind-mounted files are only added
temporarily for a single `RUN` instruction, and don't persist in the final
image. If you need to include files from the build context in the final image,
use `COPY`.
Because image size matters, using `ADD` to fetch packages from remote URLs is The `ADD` instruction is best for when you need to download a remote artifact
strongly discouraged; you should use `curl` or `wget` instead. That way you can as part of your build. `ADD` is better than manually adding files using
delete the files you no longer need after they've been extracted and you don't something like `wget` and `tar`, because it ensures a more precise build cache.
have to add another layer in your image. For example, you should avoid doing `ADD` also has built-in support for checksum validation of the remote
things like: resources, and a protocol for parsing branches, tags, and subdirectories from
[Git URLs](../../engine/reference/commandline/build.md#git-repositories).
The following example uses `ADD` to download a .NET installer. Combined with
multi-stage builds, only the .NET runtime remains in the final stage, no
intermediate files.
```dockerfile ```dockerfile
ADD https://example.com/big.tar.xz /usr/src/things/ # syntax=docker/dockerfile:1
RUN tar -xJf /usr/src/things/big.tar.xz -C /usr/src/things
RUN make -C /usr/src/things all FROM scratch AS src
ARG DOTNET_VERSION=8.0.0-preview.6.23329.7
ADD --checksum=sha256:270d731bd08040c6a3228115de1f74b91cf441c584139ff8f8f6503447cebdbb \
https://dotnetcli.azureedge.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-runtime-$DOTNET_VERSION-linux-arm64.tar.gz /dotnet.tar.gz
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0.0-preview.6-bookworm-slim-arm64v8 AS installer
# Retrieve .NET Runtime
RUN --mount=from=src,target=/src <<EOF
mkdir -p /dotnet
tar -oxzf /src/dotnet.tar.gz -C /dotnet
EOF
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0.0-preview.6-bookworm-slim-arm64v8
COPY --from=installer /dotnet /usr/share/dotnet
RUN ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet
``` ```
And instead, do something like:
```dockerfile
RUN mkdir -p /usr/src/things \
&& curl -SL https://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
```
For other items, like files and directories, that don't require the tar
auto-extraction capability of `ADD`, you should always use `COPY`.
For more information about `ADD` or `COPY`, see the following: For more information about `ADD` or `COPY`, see the following:
- [Dockerfile reference for the ADD instruction](../../engine/reference/builder.md#add) - [Dockerfile reference for the ADD instruction](../../engine/reference/builder.md#add)
- [Dockerfile reference for the COPY instruction](../../engine/reference/builder.md#copy) - [Dockerfile reference for the COPY instruction](../../engine/reference/builder.md#copy)
@ -518,4 +527,4 @@ fails catastrophically if the new build's context is missing the resource being
added. Adding a separate tag, as recommended above, helps mitigate this by added. Adding a separate tag, as recommended above, helps mitigate this by
allowing the Dockerfile author to make a choice. allowing the Dockerfile author to make a choice.
For more information about `ONBUILD`, see [Dockerfile reference for the ONBUILD instruction](../../engine/reference/builder.md#onbuild). For more information about `ONBUILD`, see [Dockerfile reference for the ONBUILD instruction](../../engine/reference/builder.md#onbuild).