So here’s my attempt in explaining the difference between the three!
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 Reply