Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMD and ENTRYPOINT bracket vs non bracket version

Tags:

docker

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?

like image 481
Wakan Tanka Avatar asked Jun 05 '20 00:06

Wakan Tanka


People also ask

Can you tell the difference between CMD and entrypoint?

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.

What is the difference between CMD and run in Dockerfile?

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.

Can we have 2 entrypoint in Dockerfile?

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.

Is CMD mandatory in Dockerfile?

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.


1 Answers

There are two rules:

  1. If you use the JSON-array ("bracket") version, it is an explicit list of "words" that make up the command; if you use a bare string, it is wrapped in /bin/sh -c '...'.
  2. After applying the first rule, the 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 "$@").

like image 159
David Maze Avatar answered Oct 20 '22 20:10

David Maze