I've seen many Dockerfiles with various syntax. Some of them use CMD
without brackets some of them use brackets. According to my experiments those two are equivalents:
CMD ["/bin/ping", "localhost"]
CMD /bin/ping localhost
But this is not true for ENTRYPOINT
According to my experiments those are not the same and only the version with brackets is working.
ENTRYPOINT ["/docker-entrypoint.sh"]
ENTRYPOINT /docker-entrypoint.sh
I was experimentig with thosefiles:
Dockerfile:
FROM debian:wheezy
COPY docker-entrypoint.sh /
RUN chmod +x /docker-entrypoint.sh
# WORKS AS EXPECTED - FIRST PASS EXECUTION TO /docker-entrypoint.sh THEN TO CMD
ENTRYPOINT ["/docker-entrypoint.sh"]
# PRINTS "PASSED ARGUMENTS" AND EXITS (CMD IS NOT EXECUTED)
# ENTRYPOINT /docker-entrypoint.sh
# WORKS
CMD ["/bin/ping", "localhost"]
# WORKS
# CMD /bin/ping localhost
# ERROR
# CMD "/bin/ping localhost"
docker-entrypoint.sh
#!/bin/bash
echo "PASSED ARGUMENTS"
echo "$@"
exec "$@"
Configuration:
wakatana@ubuntu:~/df$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.3 LTS
Release: 18.04
Codename: bionic
wakatana@ubuntu:~/df$ docker info
Client:
Debug Mode: false
Server:
Containers: 44
Running: 8
Paused: 0
Stopped: 36
Images: 98
Server Version: 19.03.5
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: systemd
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: b34a5c8af56e510852c35414db4c1f4fa6172339
runc version: 3e425f80a8c931f88e6d94a8c831b9d5aa481657
init version: fec3683
Security Options:
apparmor
seccomp
Profile: default
Kernel Version: 4.15.0-99-generic
Operating System: Ubuntu 18.04.3 LTS
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 3.83GiB
Name: ubuntu
ID: GIQ3:BYEM:O3GZ:OWNP:VROK:V3IV:SVMI:MRZ7:CLHG:GDBR:PG3S:6NQU
Docker Root Dir: /var/lib/docker
Debug Mode: false
Username: xclbr
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
WARNING: No swap limit support
wakatana@ubuntu:~/df$ docker --version
Docker version 19.03.5, build 633a0ea838
I assume that the bracket version is preferred way, but I'm wondering why is non bracket version even allowed to build? Does it have some benefit? Why CMD
works with both versions when ENTRYPOINT
works only with bracket version?
Differences between CMD & ENTRYPOINT CMD commands are ignored by Daemon when there are parameters stated within the docker run command while ENTRYPOINT instructions are not ignored but instead are appended as command line parameters by treating those as arguments of the command.
RUN is an image build step, the state of the container after a RUN command will be committed to the container image. A Dockerfile can have many RUN steps that layer on top of one another to build the image. CMD is the command the container executes by default when you launch the built image.
But since Docker allows only a single ENTRYPOINT (to be precise, only the last ENTRYPOINT in the Dockerfile has an effect), you need to find a way to run multiple processes (the tunnel and the application) with a single command.
Both ENTRYPOINT and CMD are essential for building and running Dockerfiles—it simply depends on your use case. As a general rule of thumb: Opt for ENTRYPOINT instructions when building an executable Docker image using commands that always need to be executed.
There are two rules:
/bin/sh -c '...'
.ENTRYPOINT
and CMD
are combined into a single command.There is also one detail: if you call /bin/sh -c 'command'
, any remaining arguments become the positional parameters $0
, $1
, etc. for expanding the command
string; they do not get further passed as arguments to the command
.
So if your Dockerfile says
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/command.sh"]
then when Docker launches the container, they will get combined into a single command line
/entrypoint.sh /command.sh
but if you do it with string form
ENTRYPOINT /entrypoint.sh
CMD /command.sh
you will get
/bin/sh -c '/entrypoint.sh' /bin/sh -c '/command.sh'
which evaluates the string /entrypoint.sh
and executes it as is, with no arguments; the command gets lost.
Typically you want to allow the command part to be a standard shell command (docker run --rm -it some-image /bin/sh
is super useful for debugging). To support this, the ENTRYPOINT
must be the JSON-array form, and it needs to make sure to run the command passed in its arguments (in a shell script, end with exec "$@"
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With