There is a dedicated tool for this - s6-overlay.
To quote from their description:
A simple init process which allows the end-user to execute tasks like initialization (...) Multiple processes in a single container (...) Able to operate in "The Docker Way"
The repo provides lengthy explanation how it works, how to install etc. which I won't repeat here.
Imo their repo lacks a working, straightforward minimal example how to run a process + a script so I provide one. I modify the example they provide in their docs.
Say we want to run nginx
(or any process that runs until end of container lifetime) plus some shell script myscript.sh
.
Local directory structure:
./Dockerfile
./myscript.sh
./s6-overlay/s6-rc.d/myapp/type
./s6-overlay/s6-rc.d/myapp/up
./s6-overlay/s6-rc.d/user/contents.d/myapp
Dockerfile
:
FROM ubuntu
ARG S6_OVERLAY_VERSION=3.1.4.1
RUN apt-get update && apt-get install -y nginx xz-utils
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
# Minimal set of dependecies required for s6
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz
ADD https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-x86_64.tar.xz /tmp
RUN tar -C / -Jxpf /tmp/s6-overlay-x86_64.tar.xz
# Overhead of files to manage processes via s6
COPY s6-overlay /etc/s6-overlay
# Copy the script we intend to run
COPY myscript.sh /home
# CMD is the main process - nothing special here
CMD ["/usr/sbin/nginx"]
# ENTRYPOINT must be /init for s6 to work
ENTRYPOINT ["/init"]
myscript.sh
- make sure to make it executable:
#!/bin/bash
echo "foo" > /home/foo.txt
echo "bar" > /home/bar.txt
s6-overlay/s6-rc.d/myapp/type
:
oneshot
"an up file contains a single command line" so as soon our script has >1 line, we have to outsource our script to a separate file. Therefore this is our s6-overlay/s6-rc.d/myapp/up
:
/home/myscript.sh
s6-overlay/s6-rc.d/myapp/contents.d/myapp
is an empty file.
Now we simply need to docker build (...)
and docker run -p 80:80 (...)
. If you have done everything correctly, you should see a log message s6-rc: info: service myapp successfully started
at container startup.
You can then visit localhost:80
and run docker exec CONTAINER bash -c "cat /home/foo.txt"
to confirm it works as expected.
Note that utilizing s6-rc.d
is the recommended way to do it. There's also a legacy way to accomplish this with less overhead by putting myscript.sh
into folder /etc/cont-init.d/
.