Browse Source

Rewrite ENTRYPOINT documentation covering all the combinations with examples.

Docker-DCO-1.1-Signed-off-by: Sven Dowideit <SvenDowideit@docker.com> (github: SvenDowideit)
Sven Dowideit 10 years ago
parent
commit
0390d04d8a
1 changed files with 186 additions and 31 deletions
  1. 186 31
      docs/sources/reference/builder.md

+ 186 - 31
docs/sources/reference/builder.md

@@ -460,43 +460,140 @@ The copy obeys the following rules:
 ENTRYPOINT has two forms:
 ENTRYPOINT has two forms:
 
 
 - `ENTRYPOINT ["executable", "param1", "param2"]`
 - `ENTRYPOINT ["executable", "param1", "param2"]`
-  (*exec* form, the preferred form)
+  (the preferred *exec* form)
 - `ENTRYPOINT command param1 param2`
 - `ENTRYPOINT command param1 param2`
   (*shell* form)
   (*shell* form)
 
 
-There can only be one `ENTRYPOINT` in a `Dockerfile`. If you have more
-than one `ENTRYPOINT`, then only the last one in the `Dockerfile` will
-have an effect.
+An `ENTRYPOINT` allows you to configure a container that will run as an executable.
 
 
-An `ENTRYPOINT` helps you to configure a container that you can run as
-an executable. That is, when you specify an `ENTRYPOINT`, then the whole
-container runs as if it was just that executable.
+For example, the following will start nginx with its default content, listening
+on port 80:
 
 
-Unlike the behavior of the `CMD` instruction, The `ENTRYPOINT`
-instruction adds an entry command that will **not** be overwritten when
-arguments are passed to `docker run`. This allows arguments to be passed
-to the entry point, i.e.  `docker run <image> -d` will pass the `-d`
-argument to the entry point.
+    docker run -i -t --rm -p 80:80 nginx
 
 
-You can specify parameters either in the `ENTRYPOINT` JSON array (as in
-"like an exec" above), or by using a `CMD` instruction. Parameters in
-the `ENTRYPOINT` instruction will not be overridden by the `docker run`
-arguments, but parameters specified via a `CMD` instruction will be
-overridden by `docker run` arguments.
+Command line arguments to `docker run <image>` will be appended after all
+elements in an *exec* form `ENTRYPOINT`, and will override all elements specified
+using `CMD`.
+This allows arguments to be passed to the entry point, i.e., `docker run <image> -d`
+will pass the `-d` argument to the entry point. 
+You can override the `ENTRYPOINT` instruction using the `docker run --entrypoint`
+flag.
 
 
-Like a `CMD`, you can specify a plain string for the `ENTRYPOINT` and it
-will execute in `/bin/sh -c`:
+The *shell* form prevents any `CMD` or `run` command line arguments from being
+used, but has the disadvantage that your `ENTRYPOINT` will be started as a
+subcommand of `/bin/sh -c`, which does not pass signals.
+This means that the executable will not be the container's `PID 1` - and
+will _not_ receive Unix signals - so your executable will not receive a
+`SIGTERM` from `docker stop <container>`.
 
 
-    FROM ubuntu
-    ENTRYPOINT ls -l
+Only the last `ENTRYPOINT` instruction in the `Dockerfile` will have an effect.
+
+### Exec form ENTRYPOINT example
 
 
-For example, that `Dockerfile`'s image will *always* take a directory as
-an input and return a directory listing. If you wanted to make this
-optional but default, you could use a `CMD` instruction:
+You can use the *exec* form of `ENTRYPOINT` to set fairly stable default commands
+and arguments and then use either form of `CMD` to set additional defaults that
+are more likely to be changed.
 
 
     FROM ubuntu
     FROM ubuntu
-    CMD ["-l"]
-    ENTRYPOINT ["ls"]
+    ENTRYPOINT ["top", "-b"]
+    CMD ["-c"]
+
+When you run the container, you can see that `top` is the only process:
+
+    $ docker run -it --rm --name test  top -H
+    top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
+    Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
+    %Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
+    KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
+    KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem
+    
+      PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
+        1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top
+    
+To examine the result further, you can use `docker exec`:
+
+    $ docker exec -it test ps aux
+    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
+    root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
+    root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux
+
+And you can gracefully request `top` to shut down using `docker stop test`.
+
+If you need to write a starter script for a single executable, you can ensure that
+the final executable receives the Unix signals by using `exec` and `gosu`
+(see [the Dockerfile best practices](/articles/dockerfile_best-practices/#entrypoint)
+for more details):
+
+```bash
+#!/bin/bash
+set -e
+
+if [ "$1" = 'postgres' ]; then
+    chown -R postgres "$PGDATA"
+
+    if [ -z "$(ls -A "$PGDATA")" ]; then
+        gosu postgres initdb
+    fi
+
+    exec gosu postgres "$@"
+fi
+
+exec "$@"
+```
+
+Lastly, if you need to do some extra cleanup (or communicate with other containers)
+on shutdown, or are co-ordinating more than one executable, you may need to ensure
+that the `ENTRYPOINT` script receives the Unix signals, passes them on, and then
+does some more work:
+
+```
+#!/bin/sh
+# Note: I've written this using sh so it works in the busybox container too
+
+# USE the trap if you need to also do manual cleanup after the service is stopped,
+#     or need to start multiple services in the one container
+trap "echo TRAPed signal" HUP INT QUIT KILL TERM
+
+# start service in background here
+/usr/sbin/apachectl start
+
+echo "[hit enter key to exit] or run 'docker stop <container>'"
+read
+
+# stop service and clean up here
+echo "stopping apache"
+/usr/sbin/apachectl stop
+
+echo "exited $0"
+```
+
+If you run this image with `docker run -it --rm -p 80:80 --name test apache`,
+you can then examine the container's processes with `docker exec`, or `docker top`,
+and then ask the script to stop Apache:
+
+```bash
+$ docker exec -it test ps aux
+USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
+root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
+root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
+www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
+www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
+root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
+$ docker top test
+PID                 USER                COMMAND
+10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
+10054               root                /usr/sbin/apache2 -k start
+10055               33                  /usr/sbin/apache2 -k start
+10056               33                  /usr/sbin/apache2 -k start
+$ /usr/bin/time docker stop test
+test
+real	0m 0.27s
+user	0m 0.03s
+sys	0m 0.03s
+```
+
+> **Note:** you can over ride the `ENTRYPOINT` setting using `--entrypoint`,
+> but this can only set the binary to *exec* (no `sh -c` will be used).
 
 
 > **Note**:
 > **Note**:
 > The *exec* form is parsed as a JSON array, which means that
 > The *exec* form is parsed as a JSON array, which means that
@@ -505,13 +602,71 @@ optional but default, you could use a `CMD` instruction:
 > **Note**:
 > **Note**:
 > Unlike the *shell* form, the *exec* form does not invoke a command shell.
 > Unlike the *shell* form, the *exec* form does not invoke a command shell.
 > This means that normal shell processing does not happen. For example,
 > This means that normal shell processing does not happen. For example,
-> `CMD [ "echo", "$HOME" ]` will not do variable substitution on `$HOME`.
+> `ENTRYPOINT [ "echo", "$HOME" ]` will not do variable substitution on `$HOME`.
 > If you want shell processing then either use the *shell* form or execute 
 > If you want shell processing then either use the *shell* form or execute 
-> a shell directly, for example: `CMD [ "sh", "-c", "echo", "$HOME" ]`.
+> a shell directly, for example: `ENTRYPOINT [ "sh", "-c", "echo", "$HOME" ]`.
+> Variables that are defined in the `Dockerfile`using `ENV`, will be substituted by
+> the `Dockerfile` parser.
 
 
-> **Note**:
-> It is preferable to use the JSON array format for specifying
-> `ENTRYPOINT` instructions.
+### Shell form ENTRYPOINT example
+
+You can specify a plain string for the `ENTRYPOINT` and it will execute in `/bin/sh -c`.
+This form will use shell processing to substitute shell environment variables,
+and will ignore any `CMD` or `docker run` command line arguments.
+To ensure that `docker stop` will signal any long running `ENTRYPOINT` executable
+correctly, you need to remember to start it with `exec`:
+
+    FROM ubuntu
+    ENTRYPOINT exec top -b
+
+When you run this image, you'll see the single `PID 1` process:
+
+    $ docker run -it --rm --name test top
+    Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
+    CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
+    Load average: 0.08 0.03 0.05 2/98 6
+      PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
+        1     0 root     R     3164   0%   0% top -b
+
+Which will exit cleanly on `docker stop`:
+
+    $ /usr/bin/time docker stop test
+    test
+    real	0m 0.20s
+    user	0m 0.02s
+    sys	0m 0.04s
+
+If you forget to add `exec` to the beginning of your `ENTRYPOINT`:
+
+    FROM ubuntu
+    ENTRYPOINT top -b
+    CMD --ignored-param1
+
+You can then run it (giving it a name for the next step):
+
+    $ docker run -it --name test top --ignored-param2
+    Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
+    CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
+    Load average: 0.01 0.02 0.05 2/101 7
+      PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
+        1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
+        7     1 root     R     3164   0%   0% top -b
+
+You can see from the output of `top` that the specified `ENTRYPOINT` is not `PID 1`.
+
+If you then run `docker stop test`, the container will not exit cleanly - the
+`stop` command will be forced to send a `SIGKILL` after the timeout:
+
+    $ docker exec -it test ps aux
+    PID   USER     COMMAND
+        1 root     /bin/sh -c top -b cmd cmd2
+        7 root     top -b
+        8 root     ps aux
+    $ /usr/bin/time docker stop test
+    test
+    real	0m 10.19s
+    user	0m 0.04s
+    sys	0m 0.03s
 
 
 ## VOLUME
 ## VOLUME