Docker Curl


When creating a Dockerfile, there are two commands that you can use to copy files/directories into it – ADD and COPY. Although there are slight differences in the scope of their function, they essentially perform the same task.

So, why do we have two commands, and how do we know when to use one or the other?

The Swiss Army Knife of Embedded Linux. Coming in somewhere between 1 and 5 Mb in on-disk size (depending on the variant), BusyBox is a very good ingredient to craft space-efficient distributions. BusyBox combines tiny versions of many common UNIX utilities into a single small executable.

In this article, we explain each command, analyze Docker ADD vs COPY, and tell you which one to use.

Let’s start by noting that the ADD command is older than COPY. Since the launch of the Docker platform, the ADD instruction has been part of its list of commands.

  • Docker sees the initial and modified instructions as identical and reuses the cache from previous steps. As a result the apt-get update is not executed because the build uses the cached version. Because the apt-get update is not run, your build can potentially get an outdated version of the curl and nginx packages.
  • We and third parties use cookies or similar technologies ('Cookies') as described below to collect and process personal data, such as your IP address or browser information.

The command copies files/directories to a file system of the specified container.

The basic syntax for the ADD command is:

It includes the source you want to copy (<src>) followed by the destination where you want to store it (<dest>). If the source is a directory, ADD copies everything inside of it (including file system metadata).

For instance, if the file is locally available and you want to add it to the directory of an image, you type:

ADDcan also copy files from a URL. It can download an external file and copy it to the wanted destination. For example:

An additional feature is that it copies compressed files, automatically extracting the content in the given destination. This feature only applies to locally stored compressed files/directories.

Type in the source and where you want the command to extract the content as follows:

Bear in mind that you cannot download and extract a compressed file/directory from a URL. The command does not unpack external packages when copying them to the local filesystem.

Note: The ADDcommand extracts a compressed source only if it is in a recognized compression format which is solely based on the contents of the file (not on the file name). The recognized compression formats include identity, gzip, bzip, and xz.

Due to some functionality issues, Docker had to introduce an additional command for duplicating content – COPY.

Unlike its closely related ADD command, COPY only has only one assigned function. Its role is to duplicate files/directories in a specified location in their existing format. This means that it doesn’t deal with extracting a compressed file, but rather copies it as-is.

The instruction can be used only for locally stored files. Therefore, you cannot use it with URLs to copy external files to your container.

To use the COPY instruction, follow the basic command format:

For example:

Why was there a need to add a new, similar command?

Docker curl

The fact that ADD had so many functionalities proved to be problematic in practice, as it behaved extremely unpredictable. The result of such unreliable performance often came down to copying when you wanted to extract and extracting when you wanted to copy.

Docker couldn’t completely replace the command due to its many existing usages. To avoid backward compatibility, the safest option was to add the COPY command – a less diverse yet more reliable command.

Considering the circumstances in which the COPY command was introduced, it is evident that keeping ADD was a matter of necessity. Docker released an official document outlining best practices for writing Dockerfiles, which explicitly advises against using the ADD command.

Docker’s official documentation notes that COPY should always be the go-to instruction as it is more transparent than ADD.

If you need to copy from the local build context into a container, stick to using COPY.

The Docker team also strongly discourages using ADD to download and copy a package from a URL. Instead, it’s safer and more efficient to use wget or curl within a RUN command. By doing so, you avoid creating an additional image layer and save space.


Let’s say you want to download a compressed package from a URL, extract the content, and clean up the archive.

Instead of using ADD and running the following command:

Docker Compose Curl

You should use:

Note: The only time you would need to use the ADD command is when extracting local tar files into the image.

To sum up – use COPY. As Docker itself suggests, avoid the ADD command unless you need to extract a local tar file.

Docker curl another container

To learn more about creating Dockerfiles check out this article on How to Create Docker Images With Dockerfile.

Next you should also read

Docker allows users to run a container based on an existing image. This feature is both time efficient and…

Docker images and containers are elements in Docker's platform-as-a-service software. They are both essential…

A Dockerfile offers a simpler and faster way of creating Docker images. They go through the script with all…


Docker allows users to create a container in which an application or process can run. In this guide, you will…

Healthchecks are an important feature in Docker. They let you tell the platform how to test that your application is healthy, and the instructions for doing that are captured as part of your application package.

When Docker starts a container, it monitors the process that the container runs. If the process ends, the container exits. That's just a basic liveness check, because Docker doesn't know or care what your app is actually doing.

The container process could be running, but it could be maxed out - so a web process might respond 503 to every request, but it's still running so the container stays up.

A healthcheck is how you tell Docker to test your app is really healthy, so if your web process is maxing out, Docker can mark the container as unhealthy and take evasive action (in swarm mode Docker replaces unhealthy containers by spinning up replacements).

Sounds good, let's do it with curl

The healthcheck is captured in the image with a HEALTHCHECK instruction in the Dockerfile. There are some greatblogposts on using healthchecks, and the typical example looks like this:

That uses the curl command to make an HTTP request inside the container, which checks that the web app in the container does respond. It exits with a 0 if the response is good, or a 1 if not - which tells Docker the container is unhealthy.

Windows has a curl alias for Invoke-WebRequest, but it's not exactly the same. And PowerShell handles exit codes slightly differently, so in a Windows Dockerfile the equivalent is this:

Neither of those options is great. Instead you should look at writing a custom healthchecking app.

The problem with curl and iwr

The curl/iwr option is nice and simple, but it has some pretty significant drawbacks when you're working on a production-grade Docker image.

  1. In Linux images, you need to have curl available. You can start FROM alpine and have a 4MB base image. That doesn't have curl installed, and as soon as you RUN apk --update --no-cache add curl you add 2.5MB to the image. And all the attack surface of curl.

  2. In Windows images, you need to have PowerShell installed. The latest Nano Server images lose PowerShell in favour of image size and attack surface, and it would be a shame to lose that just to get iwr.

  3. If you rely on a specific tool, your Dockerfile becomes less portable. If your apps are cross-platform and you use multi-arch images, a healthcheck that relies on an OS-specific tool breaks your cross-platformness. Best case - your image fails to build. Worst case - the image builds, but it has a healthcheck that always fails on one platform (because it's trying to use curl on Windows or vice versa).

  4. There's a limit to what you can do with a simple HTTP tool. To flex your app and prove key features work, you can end up writing a /diagnostics endpoint which you curl. Diagnostics endpoints are a good thing to have, but you need to make sure that endpoint stays private.

By using an external tool to power your healthcheck, you take on the cost of installing that tool in your image, and maintaining that tool - suddenly you need to patch your app image if the healthcheck tool gets an update.

Instead you should think about writing your own healthcheck app, using the same application runtime as your own app.

Writing a custom healthchecker

The custom healthcheck app gets over all the issues of using an external tool:

  • you're using the same runtime as your actual app, so there are no additional prerequisites for your healthcheck

  • if your app runtime is cross-platform, so is your healthcheck

  • you can put whatever logic you want into your healthcheck and it can stay private, so only the Docker platform can execute that code.

The downside is that you now have a separate thing to write, maintain and package alongside your app. But it will be a thing written in the same language, and it should be simpler than crafting a complex curl statement.

Sample healthcheck in Node.js

Docker Curl Empty Reply From Server

This blog runs in Ghost with an Nginx front end, on a Docker swarm running in Azure. Ghost is a Node.js app - and the healthcheck for the blog containers uses a very simple script, healthcheck.js:

There's not a huge amount of code here, but I have a lot of control over how the check runs. I set a timeout for the request call, I check the HTTP status code of the response, and I write log entries on success or failure (which get recorded by Docker and you can see them in docker container inspect).

In the Dockerfile, the healthcheck just runs that script:

The HEALTHCHECK instruction is very clear. The CMD is simple so the configuration of the check doesn't get swamped in the actual check code.

Node.js is an interpreted language, but for compiled languages you can compile a healthchecker as part of your multi-stage Dockerfile and bundle it alongside your app image.

Book Plug

I almost certainly talk about healthchecks in my book, Docker on Windows.