Docker Entrypoint Vs CMD and Kubernetes
Docker gives two ways of running the main process ENTRYPOINT and CMD. I’ve seen lot of confusion about these options. Both can be used to tell docker what should be executed to run main process – so what should you be using. Is one better than other ? Can you use both ?
Kubernetes uses different names for these options adding to the confusion. So lets dive in and clear it up.
ENTRYPOINT Vs CMD
If you want to run nginx in foreground as your main process – you can use either of the below code in Dockerfile and either will work fine.
CMD [“nginx”, “-g”, “daemon off;”] |
OR
ENTRYPOINT [“nginx”, “-g”, “daemon off;”] |
However what if you need to do some pre-processing before starting your main process (in this case nginx). In such cases you can see the real use for ENTRYPOINT Vs CMD
# Run the startup script as ENTRYPOINT, for preprocessing. ENTRYPOINT [“/app/scripts/docker-entrypoint.sh”] # start nginx now CMD [“nginx”, “-g”, “daemon off;”] |
How Docker interprets ENTRYPRONT and CMD
Docker concatenates ENTRYPOINT and CMD (in that order) into one array of arguments to be passed to the container. In above example array passed to docker container will be as follows.
[“/app/scripts/docker-entrypoint.sh”, “nginx”, “-g”, “daemon off;” ] |
Docker Entrypoint script (why you need exec “$@”)
Based on above example it is easy to see why docker-entrypoint.sh script should use exec “$@” at the end. This way docker-entrypoint.sh is able to access arguments entered as CMD and execute them as main process after completing the per-processing.
#Docker Entry point script # Find host and IP of the container HOSTNAME=$(hostname) HOST_IP=$(ip addr show eth0 | grep -w inet| awk ‘{print $2}’) echo “Serving request from Host : ${HOSTNAME} / IP : ${HOST_IP}” >> /www/html /index.html # Execute CMD in Dockerfile exec “$@” |
You can also checkout this PostgreSQL initialisation example on Docker Website https://success.docker.com/article/use-a-script-to-initialize-stateful container-data
Overriding ENTRYPOINT and CMD in local Docker environment
You can override either ENTRYPOINT Or CMD Or Both when running docker container locally
# Override Entrypoint. This will use original CMD – but skip the pre-proessing done by docker-entrypoint.sh docker run –entrypoint “” mynginx:latest # Overide CMD. Note that this will not skip the pre-proessing done by docker entrypoint.sh docker run mynginx:latest — “cat /www/hmtl/index.hml” #Override Entrypoint and CMD both docker run –entrypoint “” mynginx:latest — “cat /www/hmtl/index.hml” |
This makes overriding concept extremely useful for troubleshooting container startup issues. Overriding ENTRYPOINT Or CMD with using /bin/bash allows you start the container by skipping the main process and instead getting Shell into that container. Then you can go on looking at application directories / logs / running test scripts etc.
docker run mynginx:latest — “/bin/bash” #OR docker run –entrypoint /bin/bash mynginx:latest |
Overriding ENTRYPOINT and CMD in Kubernetes
You can also override either ENTRYPOINT Or CMD Or Both when running container in Kubernetes. However Kubernetes manifest files use different spec names as compared to Dockerfile.
This is useful table from Kubernetes Documentation.
Docker field name | Kubernetes field name | |
The command run by the container | Entrypoint | command |
The arguments passed to the command | Cmd | args |
Following yaml file will override CMD
apiVersion: v1 kind: Pod metadata: name: mynginx spec: containers: – name: mynginx image: myrepo/mynginx:1.2 args: – sh – “-c” – “printenv;sleep 10000” |
This Yaml will override ENTRYPOINT
apiVersion: v1 kind: Pod metadata: name: mynginx spec: containers: – name: mynginx image: myrepo/mynginx:1.2 command: [“sh”, “-c”, “printenv;sleep 10000”] |