Tini is the simplest init
you could think of.
All Tini does is spawn a single child (Tini is meant to be run in a container), and wait for it to exit all the while reaping zombies and performing signal forwarding.
NOTE: There are pre-built Docker images available for Tini. If you're currently using an Ubuntu or CentOS image as your base, you can use one of those as a drop-in replacement.
Add Tini to your container, and make it executable. Then, just invoke Tini and pass your program and its arguments as arguments to Tini.
In Docker, you will want to use an entrypoint so you don't have to remember to manually invoke Tini:
# Add Tini
ENV TINI_VERSION v0.6.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
ENTRYPOINT ["/tini", "--"]
# Run your program under Tini
CMD ["/your/program", "-and", "-its", "arguments"]
# or docker run your-image /your/program ...
Note that you can skip the --
under certain conditions, but you might
as well always include it to be safe. If you see an error message that
looks like tini: invalid option -- 'c'
, then you need to add the --
.
Arguments for Tini itself should be passed like -v
in the following example:
/tini -v -- /your/program
.
NOTE: The binary linked above is a 64-bit dynamically-linked binary.
The -v
argument can be used for extra verbose output (you can pass it up to
3 times, e.g. -vvv
).
By default, Tini needs to run as PID 1 so that it can reap zombies (by running as PID 1, zombies get re-parented to Tini).
If for some reason, you cannot run Tini as PID 1, you should register Tini as a process subreaper instead (only in Linux >= 3.4), by either:
- Passing the
-s
argument to Tini (tini -s -- ...
) - Setting the environment variable
TINI_SUBREAPER
(e.g.export TINI_SUBREAPER=
).
This will ensure that zombies get re-parented to Tini despite Tini not running as PID 1.
NOTE: Tini will issue a warning if it detects that it isn't running as PID 1 and isn't registered as a subreaper. If you don't see a warning, you're fine.
Tini can also be used with an existing entrypoint in your container!
Assuming your entrypoint was /docker-entrypoint.sh
, then you would use:
ENTRYPOINT ["/tini", "--", "/docker-entrypoint.sh"]
Tini has very few dependencies (it only depends on libc), but if your container fails to start, you might want to consider using the statically-built version instead:
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-static /tini
Tini is a very small file (in the 10KB range), so it doesn't add much weight to your container.
The statically-linked version is bigger, but still < 1M.
If you'd rather not download the binary, you can build Tini by running
cmake . && make
.
Before building, you probably also want to run:
export CFLAGS="-DPR_SET_CHILD_SUBREAPER=36 -DPR_GET_CHILD_SUBREAPER=37"
This ensure that even if you're building on a system that has old Linux Kernel headers (< 3.4), Tini will be built with child subreaper support. This is usually what you want if you're going to use Tini with Docker (if your host Kernel supports Docker, it should also support child subreapers).
After spawning your process, Tini will wait for signals and forward those to the child process, and periodically reap zombie processes that may be created within your container.
When the "first" child process exits (/your/program
in the examples above),
Tini exits as well, with the exit code of the child process (so you can
check your container's exit code to know whether the child exited
successfully).
If something isn't working just like you expect, consider increasing the verbosity level (up to 3):
tini -v -- bash -c 'exit 1'
tini -vv -- true
tini -vvv -- pwd