{"id":1127,"date":"2024-08-08T13:39:53","date_gmt":"2024-08-08T13:39:53","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2024\/08\/08\/docker-best-practices-understanding-the-differences-between-add-and-copy-instructions-in-dockerfiles\/"},"modified":"2024-08-08T13:39:53","modified_gmt":"2024-08-08T13:39:53","slug":"docker-best-practices-understanding-the-differences-between-add-and-copy-instructions-in-dockerfiles","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2024\/08\/08\/docker-best-practices-understanding-the-differences-between-add-and-copy-instructions-in-dockerfiles\/","title":{"rendered":"Docker Best Practices: Understanding the Differences Between ADD and COPY Instructions in Dockerfiles"},"content":{"rendered":"<p><a href=\"https:\/\/www.docker.com\/#tldr\"><strong>COPY vs. ADD tl;dr:<\/strong><\/a><\/p>\n<p>When you search for \u201c<a href=\"https:\/\/docs.docker.com\/reference\/dockerfile\/\" target=\"_blank\" rel=\"noopener\">Dockerfile<\/a> best practices,\u201d one of the suggestions you will find is that you always use the COPY instruction instead of the ADD instruction when adding files into your Docker image.<\/p>\n<p>This blog post will explore why this suggestion exists by providing additional detail on the functionality of these two instructions. Once you understand these concepts, you may find scenarios where you can benefit from ignoring the suggestion and using the ADD command instead of COPY.<\/p>\n<h2 class=\"wp-block-heading\">Understanding file system build context<\/h2>\n<p>Before diving into the differences between ADD and COPY, it\u2019s important to understand the concept of <a href=\"https:\/\/docs.google.com\/document\/d\/1zxZ1eHIh_JzQKJ3CC27p6ayxq0mbHGG3FmMx2L8V9L8\/edit\" target=\"_blank\" rel=\"noopener\">build context<\/a>. The build context is the set of files and directories that are accessible to the Docker engine when building an image. When you run a docker build command, Docker sends the content of the specified context directory (and its subdirectories) to the Docker daemon. This context forms the scope within which the COPY and ADD instructions operate.<\/p>\n<h2 class=\"wp-block-heading\">COPY instruction<\/h2>\n<p>The COPY instruction is straightforward and does exactly what its name implies: It copies files and directories from a source within the build context to a destination layer in the Docker image. This instruction can be used to copy both files and directories, and all paths on the host are relative to the root of the build context.<\/p>\n<p><strong>Syntax:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nCOPY &lt;src&gt;&#8230; &lt;dest&gt;\n<\/div>\n<p>&lt;src&gt;: The source files or directories on the host.<\/p>\n<p>&lt;dest&gt;: The destination path inside the Docker image.<\/p>\n<h3 class=\"wp-block-heading\">Key points<\/h3>\n<p><strong>Basic functionality<\/strong>: COPY only supports copying files and directories from the host file system. It does not support URLs or automatic unpacking of compressed files.<\/p>\n<p><strong>Security<\/strong>: Because COPY only handles local files, it tends to be more predictable and secure than ADD, reducing the risk of unintentionally introducing files from external sources.<\/p>\n<p><strong>Use case<\/strong>: Best used when you need to include files from your local build context into the Docker image without any additional processing.<\/p>\n<p><strong>Example:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nCOPY .\/app \/usr\/src\/app<br \/>\nCOPY requirements.txt \/usr\/src\/app\/\n<\/div>\n<p>In this example, the contexts of the local app directory are copied into the \/usr\/src\/app directory inside the Docker image being built. The second command copies the requirements.txt file into the \/usr\/src\/app directory as well.<\/p>\n<h2 class=\"wp-block-heading\">ADD instruction<\/h2>\n<p>The ADD instruction provides the same functionality that the COPY instruction does, but it also has additional functionality that, if misunderstood, can introduce complexity and potential security risks.<\/p>\n<p><strong>Syntax:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nADD &lt;src&gt;&#8230; &lt;dest&gt;\n<\/div>\n<p>&lt;src&gt;: The source files (directories or URLs).<\/p>\n<p>&lt;dest&gt;: The destination path inside the Docker image.<\/p>\n<h3 class=\"wp-block-heading\">Key points<\/h3>\n<p><strong>Extended functionality<\/strong>: In addition to copying local files and directories from the build context, ADD provides the following advanced functionality:<\/p>\n<p><strong>Handle URLs:<\/strong> When supplied as a source, the file referenced by a URL will be downloaded to the current Docker image layer at the supplied destination path.<\/p>\n<p><strong>Extract archives:<\/strong> When supplied as a source, ADD will automatically unpack and expand archives to the current Docker image layer at the supplied destination path.<\/p>\n<p><strong>Flexibility vs. security<\/strong>: Although ADD is more flexible, it does introduce risk. Downloading external URLs into the build process may allow malicious code or contents to be brought into the process. Using ADD with archives may result in unintended consequences if you do not understand how it handles archives.<\/p>\n<p><strong>Use case<\/strong>: ADD should only be used when you need specific functionality that it provides and are willing to manage the potential security issues arising from this usage.<\/p>\n<p><strong>Example:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\nADD https:\/\/example.com\/file.tar.gz \/usr\/src\/app\/<br \/>\nADD my-archive.tar.gz \/usr\/src\/app\/\n<\/div>\n<p>In this example, the build process first downloads https:\/\/example.com\/file.tar.gz and extracts the contents into \/usr\/src\/app in the Docker image layer. In the next step, it takes the local file my-archive.tar.gz and extracts it into the Docker image layer under \/usr\/src\/app.<\/p>\n<h2 class=\"wp-block-heading\">When to use COPY vs. ADD<\/h2>\n<p>For most use cases, COPY is the better choice due to its simplicity and security. This instruction allows you to transfer files and directories from your local context into the Docker image you are building.<\/p>\n<p>Use ADD only when you need the additional capabilities it offers, but be mindful of potential security implications.<\/p>\n<h3 class=\"wp-block-heading\">Remote contexts <\/h3>\n<p>In addition to traditional file system contexts, Docker also supports <a href=\"https:\/\/docs.docker.com\/build\/building\/context\/#remote-context\" target=\"_blank\" rel=\"noopener\">remote contexts<\/a>, which can be particularly useful in cloud environments or for building images from code repositories directly. These include:<\/p>\n<p><strong>Git repositories:<\/strong> You can specify a Git repository URL as the build context, allowing Docker to clone the repository and use its content as the context.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker build https:\/\/github.com\/username\/repository.git#branch\n<\/div>\n<p><strong>Remote URLs:<\/strong> Docker can use remote URLs for the build context. This is useful for building images directly from archives available online.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker build http:\/\/example.com\/context.tar.gz\n<\/div>\n<p><strong>OCI images:<\/strong> You can use an OCI image as the build context, which is useful for using pre-built images as the starting point for new builds.<\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\ndocker build oci:\/\/registry.example.com\/image:tag\n<\/div>\n<h3 class=\"wp-block-heading\">How ADD and COPY behave in remote contexts<\/h3>\n<p>Note that both ADD and COPY behave slightly differently when used in a remote context.<\/p>\n<h3 class=\"wp-block-heading\">Using COPY with remote contexts<\/h3>\n<p>COPY still operates within the scope of the build context, and can copy files and directories from the cloned repository into the Docker image. For example, when using a Git repository as the build context, COPY can copy files and directories from the cloned repository into the Docker image. It does not support copying files from URLs or other remote sources directly.<\/p>\n<p><strong>Example with Git repository as build context:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Using a Git repository as build context<br \/>\nCOPY .\/src \/app\/src\n<\/div>\n<p>In this case, COPY will copy the src directory from the Git repository (the build context) to \/app\/src in the Docker image.<\/p>\n<p><strong>Example with URL build context:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Using an archive from a URL<br \/>\nCOPY .\/src \/app\/src\n<\/div>\n<p>In this case, COPY will copy the src directory from the extracted archive (the build context) to \/app\/src in the Docker image.<\/p>\n<p><strong>Example with OCI image as build context:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Using an OCI image as build context<br \/>\nCOPY \/path\/in\/oci\/image \/app\/path\n<\/div>\n<p>In this case, COPY will copy the contents from the specified path within the OCI image to the specified destination path in the Docker image.<\/p>\n<h3 class=\"wp-block-heading\">Using ADD with remote contexts<\/h3>\n<p>The ADD instruction can still be used to download files and extract archives as well as copy files from the build context. Note that all the caveats provided about the ADD instruction above apply here as well.<\/p>\n<p><strong>Example with Git repository as build context:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Using a Git repository as build context<br \/>\nADD https:\/\/example.com\/data.tar.gz \/data<br \/>\nADD .\/src \/app\/src\n<\/div>\n<p>In this example, ADD will download and extract data.tar.gz from the URL into the \/data directory in the Docker image. It will also copy the src directory from the Git repository (the build context) to \/app\/src in the Docker image.<\/p>\n<p><strong>Example with URL build context:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Using an archive from a URL<br \/>\nADD https:\/\/example.com\/data.tar.gz \/data<br \/>\nADD .\/src \/app\/src\n<\/div>\n<p>In this example, ADD will download and extract data.tar.gz from the URL into the \/data directory in the Docker image. It will also copy the src directory from the downloaded\/unpacked URL (the build context) to \/app\/src in the Docker image.<\/p>\n<p><strong>Example with OCI image as build context:<\/strong><\/p>\n<div class=\"wp-block-syntaxhighlighter-code \">\n# Using an OCI image as build context<br \/>\nADD https:\/\/example.com\/data.tar.gz \/data<br \/>\nADD \/path\/in\/oci\/image \/app\/path\n<\/div>\n<p>In this scenario, ADD will download and extract data.tar.gz from the URL into the \/data directory in the Docker image. It will also copy the contents from the specified path within the OCI image to the specified destination path in the Docker image.<\/p>\n<h2 class=\"wp-block-heading\">COPY vs. ADD tl;dr:<\/h2>\n<p><strong>Prefer COPY<\/strong>: For most use cases, COPY is the better choice due to its simplicity and security. Use it to transfer files and directories from your local context or a remote context like a Git repository to the Docker image.<\/p>\n<p><strong>Use ADD with caution<\/strong>: Opt for ADD only when you need its additional functionalities, like downloading files from URLs or automatically extracting archives (Figure 1). Always be mindful of the potential security implications when using ADD.<\/p>\n<p><a href=\"https:\/\/www.docker.com\/wp-content\/uploads\/2024\/08\/2400x1260_diagram_understanding-the-differences-between-add-and-copy-instructions-in-dockerfiles.png\"><\/a><\/p>\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n<p>Understanding the differences between ADD and COPY instructions in Dockerfiles and how they can be affected by build context can help you build more efficient and secure Docker images. Although COPY offers a straightforward way to include local files, ADD provides additional flexibility with the cost of increased complexity and potential security risks.<\/p>\n<h2 class=\"wp-block-heading\">Learn more<\/h2>\n<p>Read the <a href=\"https:\/\/docs.docker.com\/reference\/dockerfile\/\" target=\"_blank\" rel=\"noopener\">Dockerfile reference documentation<\/a>.<\/p>\n<p>Subscribe to the <a href=\"https:\/\/www.docker.com\/newsletter-subscription\/\">Docker Newsletter<\/a>.\u00a0<\/p>\n<p>Get the latest release of <a href=\"https:\/\/www.docker.com\/products\/docker-desktop\/\">Docker Desktop<\/a>.<\/p>\n<p>Vote on what\u2019s next! Check out our <a href=\"https:\/\/github.com\/docker\/roadmap\" target=\"_blank\" rel=\"noopener\">public roadmap<\/a>.<\/p>\n<p>Have questions? The <a href=\"https:\/\/www.docker.com\/community\/\">Docker community is here to help<\/a>.<\/p>\n<p>New to Docker? <a href=\"https:\/\/docs.docker.com\/desktop\/\" target=\"_blank\" rel=\"noopener\">Get started<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>COPY vs. ADD tl;dr: When you search for \u201cDockerfile best practices,\u201d one of the suggestions you will find is that [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[4],"tags":[],"class_list":["post-1127","post","type-post","status-publish","format-standard","hentry","category-docker"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1127","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=1127"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/1127\/revisions"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=1127"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=1127"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=1127"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}