|
@@ -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
|
|
|
|
|