The difference between COPY and ADD in dockerfile
Tags: docker, devops, tutorial, linux
Published: 2020-12-13 14:55:32

When I was seeing some examples for docker file image building, I came across two things of same functionalities. They are COPY and ADD instructions. This article gives the difference between ADD and COPY in dockerfile. Next it explains how similar they are, then the best practice for using the RUN instead of ADD instruction.
<h3>ADD instruction</h3>
<code>ADD</code> instruction is an older one, which job is to copy the file or directory from a source to destination.
The <code>ADD</code> instruction can also do operations such as extraction of compressed files or download from an URL path.
Here the source may be a local compressed tar file or the URL path.
If it is a tar file, it extracts the contents to the destination else if it is an URL, then it download the file and extract to the destination in a similar way.
If authentication needs for URL file we can use <code>RUN</code> with <code>curl</code> or <code>wget</code> to download the files.
Since, <code>ADD</code> degrades in performance of the docker containers, <code>COPY</code> is been introduced for simple job.
<i><u>Syntax for ADD:</u></i>
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">ADD</span> <span class="bash">&lt;src&gt; &lt;dest&gt;</span></pre>
A simple example to ADD used for local tar file called source.tar.xz to the destination folder /dest.
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">ADD</span> <span class="bash">sourcefile.tar.xz /dest</span></pre>
This syntax example gives how the URL path called https://example.com/source.tar.xz file is downloaded and copied to the /dest.
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">ADD</span> <span class="bash">https://example.com/source.tar.xz /dest</span></pre>
<h3>COPY instruction</h3>
<code>COPY</code> instruction copies the file or directory from a source path to the destination.
Its job is simple as it duplicates the source file or directory to the destination.
It doesn't include the operation of extraction or downloading files as <code>ADD</code> instruction.
<i><u>Syntax for COPY:</u></i>
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">COPY</span> <span class="bash">&lt;src&gt; &lt;dest&gt;</span></pre>
An example to COPY a file called source.txt to the destination folder /dest.
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">COPY</span> <span class="bash">sourcefile.txt /dest</span></pre>
<h3>What to use either COPY or ADD?</h3>
In dockerfile we use <code>COPY</code> many time because it only copies the file from a source to destination.<code>ADD</code> used when there is a purpose such as local tar files or URL file source.
For best docker practice, we can use <code>RUN</code> instruction instead of creating an extra layer.
<code>RUN</code> instruction with <code>curl</code> or <code>wget</code> used to get the file direct into the destination.
The <code>RUN</code> instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">ADD</span> <span class="bash">https://example.com/source.tar.xz /usr/src/things/
</span><span class="hljs-keyword" style="font-weight: bold;">RUN</span> <span class="bash">tar -xJf /usr/src/things/source.tar.xz -C /usr/src/things
</span></pre>
For instance take the above sentence, where a file called source.tar.gz is downloaded using <code>ADD</code> and extracted using tar with <code>RUN</code> instruction.
This makes two layers that worse the docker performance.
It simply done using <code>RUN</code> with curl tool as follows within a single layer.
If, there is direct copy operation needed than <code>COPY</code> instruction is recommended.
The below dockerfile only takes single layer of operation of file download using curl and then extraction of file using tar with <code>RUN</code> instruction.
<pre class="hljs" style="display: block; overflow-x: auto; padding: 0.5em; background: #f0f0f0; color: #444444;"><span class="hljs-keyword" style="font-weight: bold;">RUN</span> <span class="bash">mkdir -p /usr/src/things \
    &amp;&amp; curl -SL https://example.com/source.tar.xz \
    | tar -xJC /usr/src/things </span></pre>
Reference to the Best docker practices -&gt; <a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy">go</a>.
For my docker archives click here -&gt; <a href="https://developersdoors.xyz/category/programming/docker/">go</a>.
If any queries please comment it.