Let me explain the difference between Docker RUN, CMD and ENTRYPOINT

Here’s my attempt in explaining the difference between the three!

RUN

RUN executes during the container build ie. RUN apt-get install mysql-server

CMD

CMD is when you want to execute something AFTER container has been built. ie. CMD ["app.py", "start"].

Make this clear for yourself, any command, server, or service that must run AFTER the build can be specified in CMD.

For example php artisan serve --host=0.0.0.0 or php artisan migrate --seed. This should be clear by now? Build container, after it’s built run the CMD.

Another example say we have CMD ["app.py", "fetch_all"]. fetch_all is default arg.

So now what if you want to override the command via CLI? if you provide a new cmd during docker run ie docker run container app.py fetch_single, (app.py fetch_single is new cmd) it will override the CMD ["app.py", "fetch_all"] as a result execute app.py fetch_single

Yet another example:
php artisan serve --host=0.0.0.0 as a docker CMD would look like: CMD["php", "artisan", "serve", "--host=0.0.0.0"] can be overridden like this: docker run container_name php artisan serve --host=127.0.0.1. Which would run php artisan serve --host=127.0.0.1

This means you can control whatever is happening inside container via CLI when starting the container! This is very cool!

Most of the time the commands that run in CMD should have flexibility to be overridden or you’ll have to modify the image each time, build it and start new container.

Finally note that there’s two different syntax to define a command. One is setting it using CMD ["executable","param1","param2"] another is: CMD command param1 param2.

Entrypoint

ENTRYPOINT is similar to CMD except you can’t override it..

Basically it will always execute no matter what, you can’t pass nothing via CLI that’d affect this.

This is the MAJOR difference, you can’t pass params here! the command will run in the END like CMD. You could also call it main command!

Example.. say you ALWAYS want php artisan serve to run. Obviously you can add it to ENTRYPOINT like this ENTRYPOINT["php", "artisan", "serve"]

Running docker container run container_name will execute php artisan serve.

Now, what if you want to pass params to this like --host=127.0.0.1.

Note we don’t want to write entire command like we did earlier in CMD: docker run container_name php artisan serve --host=127.0.0.1.

We only want to give php artisan serve additional param --host.

We can easily pass params like this: ENTRYPOINT["php", "artisan", "serve"] CMD["--host=0.0.0.0"]

Now you can run docker container run container_name --host=127.0.0.1. This says ALWAYS run php artisan serve but also have ability to pass params.

With CMD only we’d have to pass entire command like this: docker container run container_name php artisan serve --host=127.0.0.1.

When mixed, ENTRYPOINT sets the main command, and CMD takes params.. ENTRYPOINT["php artisan serve"]; CMD["--host=127.0.0.1"]. docker run container_name will run php artisan serve by default but we can also pass params docker run container_name --host=127.0.0.1 it will then run php artisan serve --host=127.0.0.1.

It’s just that the “ENTRYPOINT instruction sets the default executable for the container.”

Another ENTRYPOINT + CMD Example

Imagine we have image that starts python sever container, without param runs normal server, with param it runs local server.

docker container run -it python_server

Server started!

docker container run -it python_server python_server_local.py

Local server started!

Now lets look at how Dockerfile looks:

FROM ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive

RUN apt-get update -y && apt-get install sudo && apt-get install -y python3

COPY python_server.py ./

COPY python_server_local.py ./

CMD ["python_server.py"]

ENTRYPOINT ["python3"]

Leave a comment

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