In Dockerfiles, it is recommended to use the exec form for CMD and ENTRYPOINT instructions. The exec form, which is
represented as a JSON array, ensures that the process runs directly without being wrapped in a shell. This allows OS signals like SIGTERM and SIGINT
to be received by the process. This practice enhances the reliability and control of your Docker containers.
Using the shell form instead of the exec form for CMD and ENTRYPOINT instructions in Dockerfiles can lead to several issues. When you use the shell form, the executable runs as a child process to a shell, which does not pass OS signals. This can cause problems when trying to gracefully stop containers because the main process will not receive the signal intended to terminate it. Moreover, the exec form provides more control and predictability over the execution of the command. It does not invoke a command shell, which means it does not have the potential side effects of shell processing.
The exec form does not allow shell features such as variable expansion, piping (|) and command chaining (&&,
||, ;). In case you need to use these features, there are a few alternatives:
SHELL instruction before CMD or ENTRYPOINT This rule will not raise an issue if the SHELL instruction is used before the CMD or ENTRYPOINT instruction,
as we consider this a conscious decision.
FROM scratch ENTRYPOINT echo "Welcome!"
FROM scratch ENTRYPOINT echo "Long script with chaining commands" \ && echo "Welcome!" \ && echo "Goodbye"
FROM scratch ENTRYPOINT ["echo", "Welcome!"]
FROM scratch SHELL ["/bin/bash", "-c"] ENTRYPOINT echo "Long script with chaining commands" \ && echo "Welcome!" \ && echo "Goodbye"
FROM scratch ENTRYPOINT ["/entrypoint.sh"]