The difference between the COPY and ADD commands in a Dockerfile
Transferring files from host to container image is typical while creating container images, thus we have two options for moving files or directories to the container. However, while both options may provide the same outcome, the ADD command has a different use.
If you haven't already, I strongly suggest you read the previous post about Docker build and push:
COPY instruction
I'll use examples to demonstrate how the COPY command works. We often utilize copy for source code, assets, settings, and so forth...
The following example uses COPY in three ways:
FROM alpine:3.17 as base
WORKDIR /app
FROM ubuntu:22.10 as super_secret
RUN echo "you_should_not_use_secrets_here" > /secret.txt
FROM base as app
COPY --from=super_secret /secret.txt /app/secret.txt
COPY ./assets/hello.txt /app/hello.txt
COPY ./tools /app
RUN chmod +x /app/info.sh
ENTRYPOINT ["/app/info.sh"]
- COPY --from=super_secret /secret.txt /app/secret.txt, copy file from a stage called super_secret;
- COPY ./assets/hello.txt /app/hello.txt, copy the file from the host to the container;
- COPY ./tools /app, copy the directory from the host to the container;
That covers our discussion of the most common COPY applications.
ADD instruction
Although the ADD command behaves similarly to the COPY command in that it copies files, ADD has been developed to copy from local (host) or remote files (http) to the container image; if this file has been compressed (tar.gz), the content will be extracted and copied to the destination directory.
The following is an example of a Dockerfile that copies a compressed file and extracts it to the destination directory:
FROM alpine:3.17
WORKDIR /app
ADD ./assets/tools.tar.gz /app
RUN chmod +x /app/assets.sh
ENTRYPOINT ["/app/assets.sh"]
Following that, we have a Dockerfile containing a remote file that will be extracted to the target directory:
FROM alpine:3.17
WORKDIR /app
ADD https://github.com/williampsena/docker-recipes/raw/main/build/samples/assets/tools.tar.gz /app
RUN tar -xf tools.tar.gz
RUN chmod +x /app/assets.sh
ENTRYPOINT ["/app/assets.sh"]
Two builds will generate the identical files, but the first will use the host path and the second will use the remote path. The file tools.tar.gz will be present in the container using ADD remote example, which you should delete using the RUN command to save up space.
Permissions
COPY and ADD supports extra features such as chmod and chown to modify the permissions of transferred files, however only the Linux container supports these features.
COPY --chown foo:foo --chmod 644 ./assets /assets
ADD --chown foo:foo --chmod 644 ./assets/foo.tar.gz /assets
Recommendations
- As previously stated, ADD and COPY achieve the same result when transferring files, although Docker advises using COPY rather than ADD.
- Because image size matters, Docker recommends avoiding using ADD to download packages from remote URLs; instead, use curl or wget. That way, when the files have been extracted, you may remove them and avoid having to add another layer to your image. You should, for example, avoid doing the following:
# curl
RUN mkdir -p /tmp/assets && \
curl -SL https://github.com/williampsena/docker-recipes/raw/main/build/samples/assets/tools.tar.gz | tar xvfz - -C /tmp/assets
# wget
RUN mkdir -p /tmp/assets && \
wget -qO- https://github.com/williampsena/docker-recipes/raw/main/build/samples/assets/tools.tar.gz | tar xvfz - -C /tmp/assets
Final thoughts
⚠️ The Dockerfiles recipes and assets might be found on my Github repository.
With practical build samples, we learned the difference between COPY and AND today. I'll go through additional Docker instructions in future blogs.
Keep your 🧠 kernel up to date. God bless 🙏🏿 you.
Time for feedback!