Docker ENTRYPOINT vs CMD | Which To Use?

Docker entrypoint vs cmd

The Docker ENTRYPOINT vs CMD is a question that gets asked a lot. This article will first go over the differences between the two Dockerfile options, move to how they can be used together, and then finally go over when to use each one.

Docker ENTRYPOINT vs CMD Differences

Most people use ENTRYPOINT & CMD interchangeably, because for most use cases they will function in a similar manner. The goal of each is as specified:

  • ENTRYPOINT: Indicates a command that will ALWAYS be run when the container starts.
  • CMD: Specifies the arguments that will be passed to ENTRYPOINT.

Looking at those definitions you wouldn’t think they would act in a similar manner. The reason why ENTRYPOINT and CMD feel like they can be used interchangeable is because the default ENTRYPOINT on most images is ‘/bin/sh -c’. For example, if you set ENTRYPOINT to run `echo “hello”`, when your container starts up it will run: `echo “hello”`. If you set CMD to `echo “hello”` your container would run `/bin/sh -c ‘echo “hello”‘`. Both which produce the same result as shown in the bash terminal below.

$ echo "hello"
hello
$ /bin/sh -c 'echo "hello"'
hello

Now that you have the differences down, let’s move on to see how they can work together in harmony.

Using Docker ENTRYPOINT & CMD Together

In the last section we outlined that ENTRYPOINT is designed to receive arguments from CMD. Let’s a build a little docker image that follows those rules and scrapes a web page.

1.) First thing first let’s create a Dockerfile that has curl installed. For this tutorial we’ll just use the latest alpine linux image and add curl using the apk package manager.

FROM alpine:latest
RUN apk add curl

2.) Next up, let’s add our ENTRYPOINT. Since we know that this container’s sole purpose is to run curl for us we’ll set the ENTRYPOINT to the curl binary (/usr/bin/curl). You’ll notice that I put our curl command in a string within an array. This is called Docker ‘exec’ form and is a best practice to ensuring your ENTRYPOINT and CMD run as you intend them to.

FROM alpine:latest
RUN apk add curl
ENTRYPOINT ["/usr/bin/curl"]

3.) Now it’s time to add our CMD. Remembering the purpose of CMD it’s designed to be sent as an argument to our ENTRYPOINT, but can be overridden on docker run. For now we’ll set it to ‘https://swissarmydevops.com’ as that will be the default curl URL.

FROM alpine:latest
RUN apk add curl
ENTRYPOINT ["/usr/bin/curl"]
CMD ["https://swissarmydevops.com"]

4.) Time to build our docker image!

$ docker build -t curl-box:latest .
Sending build context to Docker daemon  4.096kB
Step 1/4 : FROM alpine:latest
 ---> d6e46aa2470d
Step 2/4 : RUN apk add curl
 ---> Using cache
 ---> 4ffcd2a0ab23
Step 3/4 : ENTRYPOINT ["/usr/bin/curl"]
 ---> Running in 115da3a26d7c
Removing intermediate container 115da3a26d7c
 ---> c82c9a30e1aa
Step 4/4 : CMD ["https://swissarmydevops.com"]
 ---> Running in 0899fd7d88fa
Removing intermediate container 0899fd7d88fa
 ---> b078cb9c4508
Successfully built b078cb9c4508
Successfully tagged curl-box:latest

5.) The moment of truth. Let’s run our container. For the sake of not overwhelming your screen with all of the html from the swissarmydevops.com homepage I’ve cut down the output. But we can see that it indeed scraped our site using ENTRYPOINT and CMD!

$ docker run curl-box:latest
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0<!DOCTYPE html><html class="no-js" lang="en-US"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="profile" href="https://gmpg.org/xfn/11" />

6.) Here’s where the flexible nature of these two Docker options come in handy. Let’s say I want to scrape a different page. Docker let’s you override the CMD option with the first argument you pass when you run the container. For example if I wanted to curl the URL ‘https://swissarmydevops.com/containers/docker/docker-cli-cheat-sheet‘ it would look like this.

$ docker run curl-box:latest https://swissarmydevops.com/containers/docker/docker-cli-cheat-sheet

When to use Docker CMD vs ENTRYPOINT

There are lots of opinions when it comes to this, so bear with me as I go off the books for a second. I generally follow the paradigm that if you’re building a container that is designed to run like a binary then use ENTRYPOINT & CMD together. Every other instance I recommend using CMD.

When I say that your app “runs like a binary” I mean it is designed with one purpose and expects to receive arguments from the user. Our minimalist curl app was a great example, it had one purpose and expected an argument. Other examples might be if you have a database backup script you want to run in a docker container. You could point ENTRYPOINT to the location of your script and then pass the database name in as a CMD when you run the container (i.e. `docker run db-backup:latest my-db-name`).

Wrap up

Thanks for reading! Hopefully this clarified any Docker CMD vs ENTRYPOINT questions you had. If you’re an avid Docker user I’d highly recommend checking out our Docker Cheat Sheet that outlines common Docker commands in an organized way.

Leave a Reply

Your email address will not be published. Required fields are marked *