Docker Entrypoint Vs CMD and Kubernetes

igreendataadmin

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”]