Dockerfile - detailed explanation of entrypoint instruction

Posted by knnakai on Tue, 02 Nov 2021 09:39:11 +0100

ENTRYPOINT

Two ways of writing

# exec format
ENTRYPOINT ["executable", "param1", "param2"]

# shell format
ENTRYPOINT command param1 param2

a key

  • ENTRYPOINT specifies the default entry command of the image. The entry command will be executed as the root command when starting the container, and all other incoming values will be used as the parameters of the command
  • The value of ENTRYPOINT can be overridden by

docker run --entrypoint

  • Only the last entry point instruction in Dockerfile will work

ENTRYPOINT and CMD are used together

  • When ENTRYPOINT is specified, the meaning of CMD is changed. Instead of directly running its command, the content of CMD is passed to the ENTRYPOINT instruction as a parameter
  • In other words, when actually executed, it becomes
<ENTRYPOINT> "<CMD>"

Soul torture

So why should there be entry point after CMD? What are the benefits of this < entry point > "< CMD >"?

Difference between CMD and ENTRYPOINT

CMD                   # Specify the command to run when the container is started. Commands cannot be appended
ENTRYPOINT            # Specify the command to run when the container starts, and you can append the command

What do you mean by that? This is actually one of the application scenarios of ENTRYPOINT. Let's look at it below

Test CMD

Write dockerfile file

FROM centos
CMD ["ls","-a"]    

Build mirror

docker build -f CMD.dockerfile -t test .

Run container

> docker run test
.
..
.dockerenv
bin
dev
etc
home
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

Run the container and append the command

> docker run test -l
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "-l": executable file not found in $PATH: unknown.
  • See the error message that the executable file cannot be found, executable file not found
  • Following the image name is command, which will replace the default value of CMD at runtime. Therefore, - l here replaces the original CMD rather than appended to the original ls -a
  • And -l is not a command at all, so naturally it can't be found

If you want to add the - i parameter, you must override the ls command

> docker run test ls -a -l
total 56
drwxr-xr-x   1 root root 4096 Oct 28 09:36 .
drwxr-xr-x   1 root root 4096 Oct 28 09:36 ..
-rwxr-xr-x   1 root root    0 Oct 28 09:36 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 Oct 28 09:36 dev
drwxr-xr-x   1 root root 4096 Oct 28 09:36 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15 14:17 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 221 root root    0 Oct 28 09:36 proc
dr-xr-x---   2 root root 4096 Sep 15 14:17 root
drwxr-xr-x  11 root root 4096 Sep 15 14:17 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Oct 28 09:36 sys
drwxrwxrwt   7 root root 4096 Sep 15 14:17 tmp
drwxr-xr-x  12 root root 4096 Sep 15 14:17 usr
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var

Yes, but this is obviously not the best choice. ENTRYPOINT can solve this problem

Test ENTRYPOINT

Write dockerfile file

FROM centos
ENTRYPOINT ["ls","-a"]    

Build mirror

docker build -f ENTRYPOINT.dockerfile -t test . 

Run the container and append the command

> docker run test -l
total 56
drwxr-xr-x   1 root root 4096 Oct 28 09:38 .
drwxr-xr-x   1 root root 4096 Oct 28 09:38 ..
-rwxr-xr-x   1 root root    0 Oct 28 09:38 .dockerenv
lrwxrwxrwx   1 root root    7 Nov  3  2020 bin -> usr/bin
drwxr-xr-x   5 root root  340 Oct 28 09:38 dev
drwxr-xr-x   1 root root 4096 Oct 28 09:38 etc
drwxr-xr-x   2 root root 4096 Nov  3  2020 home
lrwxrwxrwx   1 root root    7 Nov  3  2020 lib -> usr/lib
lrwxrwxrwx   1 root root    9 Nov  3  2020 lib64 -> usr/lib64
drwx------   2 root root 4096 Sep 15 14:17 lost+found
drwxr-xr-x   2 root root 4096 Nov  3  2020 media
drwxr-xr-x   2 root root 4096 Nov  3  2020 mnt
drwxr-xr-x   2 root root 4096 Nov  3  2020 opt
dr-xr-xr-x 207 root root    0 Oct 28 09:38 proc
dr-xr-x---   2 root root 4096 Sep 15 14:17 root
drwxr-xr-x  11 root root 4096 Sep 15 14:17 run
lrwxrwxrwx   1 root root    8 Nov  3  2020 sbin -> usr/sbin
drwxr-xr-x   2 root root 4096 Nov  3  2020 srv
dr-xr-xr-x  13 root root    0 Oct 28 09:38 sys
drwxrwxrwt   7 root root 4096 Sep 15 14:17 tmp
drwxr-xr-x  12 root root 4096 Sep 15 14:17 usr
drwxr-xr-x  20 root root 4096 Sep 15 14:17 var

The second application scenario of ENTRYPOINT

  • Starting the container is to start the main process, but some preparations may be required before starting the main process. For example, mysql may require some database configuration and initialization, which should be solved before the final mysql server runs
  • You may also want to avoid using the root user to start the service, so as to improve security. Before starting the service, you need to perform some necessary preparations as root, and finally switch to the service user to start the service
  • These preparations have nothing to do with the container CMD. No matter what the CMD is, a preprocessing work needs to be carried out in advance. In this case, a script can be written and put into ENTRYPOINT for execution, and the script will take the received parameters (i.e. < CMD >) as commands and execute them at the end of the script

Official image redis

FROM alpine:3.4
...
RUN addgroup -S redis && adduser -S -G redis redis
...
ENTRYPOINT ["docker-entrypoint.sh"]

EXPOSE 6379
CMD [ "redis-server" ]

docker-entrypoint.sh

#!/bin/sh
...
# allow the container to be started with `--user`
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
    find . \! -user redis -exec chown redis '{}' +
    exec gosu redis "$0" "$@"
fi

exec "$@"

The content of the script is judged according to the content of CMD. If it is a redis server, switch to the redis user identity to start the server. Otherwise, it is still executed as root

[root@poloyy ~]#  docker run -it redis id
uid=0(root) gid=0(root) groups=0(root)

# Directly into the container
[root@poloyy ~]#  docker run -it redis
root@565f89976d63:/#