Quick Overview
Tini is a tiny but valid init
for containers. It is designed to be a simple init system that runs as PID 1 and forwards signals to the user's main process. Tini is particularly useful for running processes in containers, as it ensures the correct handling of signals and reaping of zombie processes.
Pros
- Lightweight: Tini is a small, single-binary executable that adds minimal overhead to container images.
- Signal Handling: Tini correctly forwards signals to the main process, ensuring proper termination and cleanup.
- Zombie Process Reaping: Tini reaps zombie processes, preventing them from accumulating and causing issues.
- Compatibility: Tini is designed to work with a wide range of container runtimes and orchestration platforms.
Cons
- Limited Functionality: Tini is a minimal init system and may not provide the advanced features of larger init systems like systemd.
- Dependency on Container Runtime: Tini's functionality is dependent on the container runtime and may require specific configuration or integration.
- Potential Complexity: While Tini is relatively simple, integrating it into a container setup may add some complexity to the build process.
- Lack of Customization: Tini has a limited set of options and may not provide the level of customization that some users may require.
Code Examples
Tini is a command-line tool, and its usage is primarily through the command line. Here are a few examples of how to use Tini:
- Running a command with Tini:
tini -- my_command arg1 arg2
This will run the command my_command arg1 arg2
with Tini as the init system.
- Passing arguments to Tini:
tini --version
This will display the version of Tini.
- Configuring Tini with environment variables:
TINI_SUBREAPER=1 tini -- my_command arg1 arg2
This will set the TINI_SUBREAPER
environment variable to 1
, which enables the subreaper functionality of Tini.
Getting Started
To use Tini, follow these steps:
- Download the Tini binary from the GitHub releases page.
- Add the Tini binary to your container image, for example, by copying it into the
/usr/local/bin/
directory. - In your container's entrypoint or CMD, use Tini to run your main process:
ENTRYPOINT ["/usr/local/bin/tini", "--", "my_command", "arg1", "arg2"]
This will ensure that Tini is the init system for your container and that signals are properly handled.
- (Optional) Configure Tini's behavior using environment variables, such as
TINI_SUBREAPER
orTINI_SIGPROP
.
That's it! Tini should now be integrated into your container setup, providing a lightweight and reliable init system.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Tini - A tiny but valid init
for containers
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.
Why Tini?
Using Tini has several benefits:
- It protects you from software that accidentally creates zombie processes, which can (over time!) starve your entire system for PIDs (and make it unusable).
- It ensures that the default signal handlers work for the software you run
in your Docker image. For example, with Tini,
SIGTERM
properly terminates your process even if you didn't explicitly install a signal handler for it. - It does so completely transparently! Docker images that work without Tini will work with Tini without any changes.
If you'd like more detail on why this is useful, review this issue discussion: What is advantage of Tini?.
Using Tini
NOTE: If you are using Docker 1.13 or greater, Tini is included in Docker
itself. This includes all versions of Docker CE. To enable Tini, just pass the
--init
flag to docker run
.
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.
NOTE: There are Tini packages for Alpine Linux and NixOS. See below for installation instructions.
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.19.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.
Signed binaries
The tini
and tini-static
binaries are signed using the key 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7
.
You can verify their signatures using gpg
(which you may install using
your package manager):
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini.asc /tini.asc
RUN gpg --batch --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 595E85A6B1B4779EA4DAAEC70B588DFF0527A9B7 \
&& gpg --batch --verify /tini.asc /tini
RUN chmod +x /tini
Verifying binaries via checksum
The tini
and tini-static
binaries have generated checksums (SHA1
and SHA256
).
You can verify their checksums using sha1sum
and sha256sum
(which you may install using
your package manager):
ENV TINI_VERSION v0.19.0
RUN wget --no-check-certificate --no-cookies --quiet https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64 \
&& wget --no-check-certificate --no-cookies --quiet https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-amd64.sha256sum \
&& echo "$(cat tini-amd64.sha256sum)" | sha256sum -c
Alpine Linux Package
On Alpine Linux, you can use the following command to install Tini:
RUN apk add --no-cache tini
# Tini is now available at /sbin/tini
ENTRYPOINT ["/sbin/tini", "--"]
NixOS
Using Nix, you can use the following command to install Tini:
nix-env --install tini
Debian
On Debian (Buster or newer), you can use the following command to install Tini:
apt-get install tini
Note that this installs /usr/bin/tini
(and /usr/bin/tini-static
), not /tini
.
Arch Linux
On Arch Linux, there is a package available on the AUR. Install using the official instructions or use an AUR helper:
pacaur -S tini
Other Platforms
ARM and 32-bit binaries are available! You can find the complete list of available binaries under the releases tab.
Options
Verbosity
The -v
argument can be used for extra verbose output (you can pass it up to
3 times, e.g. -vvv
).
Subreaping
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.
Remapping exit codes
Tini will reuse the child's exit code when exiting, but occasionally, this may not be exactly what you want (e.g. if your child exits with 143 after receiving SIGTERM). Notably, this can be an issue with Java apps.
In this case, you can use the -e
flag to remap an arbitrary exit code to 0.
You can pass the flag multiple times if needed.
For example:
tini -e 143 -- ...
Process group killing
By default, Tini only kills its immediate child process. This can be inconvenient if sending a signal to that process does not have the desired effect. For example, if you do
docker run krallin/ubuntu-tini sh -c 'sleep 10'
and ctrl-C it, nothing happens: SIGINT is sent to the 'sh' process, but that shell won't react to it while it is waiting for the 'sleep' to finish.
With the -g
option, Tini kills the child process group , so that
every process in the group gets the signal. This corresponds more
closely to what happens when you do ctrl-C etc. in a terminal: The
signal is sent to the foreground process group.
Parent Death Signal
Tini can set its parent death signal, which is the signal Tini should receive
when its parent exits. To set the parent death signal, use the -p
flag with
the name of the signal Tini should receive when its parent exits:
tini -p SIGTERM -- ...
NOTE: See this PR discussion to learn more about the parent death signal and use cases.
More
Existing Entrypoint
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"]
Statically-Linked Version
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
Size Considerations
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.
Building Tini
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).
Understanding Tini
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).
Debugging
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
Authors
Maintainer:
Contributors:
Special thanks to:
- Danilo Bürger for packaging Tini for Alpine
- Asko Soukka for packaging Tini for Nix
- nfnty for packaging Tini for Arch Linux
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot