Expanding variables and shell expressions in parameters to Docker entrypoint
############################################################################

:date: 2016-06-13
:summary: Expanding variables and shell expressions in parameters to Docker entrypoint

A known best practice when creating Docker images is when you need to run
commands in runtime before starting the actual application/ daemon is to create
an entrypoint script and pass the command as parameters in the :code:`CMD`
instruction. Another best practice is to exec the final command so it would be
PID 1 and receive the signals passed to it. Let's create a small example. Here's
the :code:`Dockerfile`:

.. code::

    FROM alpine
    COPY entrypoint.sh /entrypoint.sh
    RUN chmod +x entrypoint.sh
    ENTRYPOINT ["/entrypoint.sh"]
    ENV var value
    CMD ["echo", "$var"]

And the :code:`entrypoint.sh` script:

.. code:: shell

    #!/bin/sh
    set -eu
    # Perform any needed tasks here.
    exec $@

Now let's build and run this container:

.. code:: shell

    $ docker build --tag entrypoint .
    Sending build context to Docker daemon 28.67 kB
    Step 0 : FROM alpine
     ---> 5f05d2ba9e65
    Step 1 : COPY entrypoint.sh /entrypoint.sh
     ---> f59f4d7f3546
    Removing intermediate container 27ca546c6b6c
    Step 2 : ENTRYPOINT /entrypoint.sh
     ---> Running in 98c65b63948a
     ---> 1de45b33021b
    Removing intermediate container 98c65b63948a
    Step 3 : ENV var value
     ---> Running in 133a8781f0ac
     ---> bba451334fb2
    Removing intermediate container 133a8781f0ac
    Step 4 : CMD echo $var
     ---> Running in e8436c6c3202
     ---> a49d9b335b74
    Removing intermediate container e8436c6c3202
    Successfully built a49d9b335b74
    $ docker run entrypoint
    $var

As we can see the variable :code:`var` wasn't expanded to it's content. After a
bit of head scratching, The following simple change was made to the entrypoint
script.

.. code:: shell

    #!/bin/sh
    set -eu
    # Perform any needed tasks here.
    eval "exec $@"

The change is to first evaluate the expression (expanding any variable and
expression found), then :code:`exec` it. The outcome is what you'd expect.

.. code::

    $ docker build --tag entrypoint .
    Sending build context to Docker daemon 28.67 kB
    Step 0 : FROM alpine
     ---> 5f05d2ba9e65
    Step 1 : COPY entrypoint.sh /entrypoint.sh
     ---> b874d862999d
    Removing intermediate container fb6483ff00e3
    Step 2 : ENTRYPOINT /entrypoint.sh
     ---> Running in 82adf0b2c4c7
     ---> 6674f336c5e1
    Removing intermediate container 82adf0b2c4c7
    Step 3 : ENV var value
     ---> Running in 599f3f98c11d
     ---> 980f1e1e1ad5
    Removing intermediate container 599f3f98c11d
    Step 4 : CMD echo $var
     ---> Running in e29f1948480a
     ---> e27fd79143f8
    Removing intermediate container e29f1948480a
    Successfully built e27fd79143f8
    $ docker run entrypoint
    value