<p align="center">
<img src="assets/logo.svg" alt="tino - tiny init process for containers" width="320">
</p>
<p align="center">
tiny init process (PID 1) for Docker, Kubernetes, and other containers
</p>
<p align="center">
<a href="https://crates.io/crates/tino"><img src="https://img.shields.io/crates/v/tino?style=flat&logo=rust&logoColor=ffffff&label=crate&labelColor=64748b&color=0f766e" alt="Crate Version"></a>
<a href="https://github.com/lvillis/tino/actions"><img src="https://img.shields.io/github/actions/workflow/status/lvillis/tino/ci.yaml?branch=main&style=flat&logo=githubactions&logoColor=ffffff&label=ci&labelColor=64748b&color=0f766e" alt="CI Status"></a>
<a href="https://hub.docker.com/r/lvillis/tino"><img src="https://img.shields.io/docker/pulls/lvillis/tino?style=flat&logo=docker&logoColor=ffffff&label=pulls&labelColor=64748b&color=0f766e" alt="Docker Pulls"></a>
<a href="https://hub.docker.com/r/lvillis/tino"><img src="https://img.shields.io/docker/image-size/lvillis/tino/latest?style=flat&logo=docker&logoColor=ffffff&label=image&labelColor=64748b&color=0f766e" alt="Docker Image Size"></a>
</p>
`tino` is a tiny init process (PID 1) for Docker, Kubernetes, and other container workloads. It is a practical `tini` alternative with signal forwarding, subreaper support, command argument expansion without `/bin/sh`, and optional Linux Landlock restrictions.
## Why Use tino as PID 1
- Runs as PID 1 and forwards signals to the managed process.
- Reaps orphaned children with `-s/--subreaper`.
- Supports parent-death signals, grace timeouts, and exit-code remapping.
- Expands `${VAR}` and `${VAR:-default}` in child arguments without requiring `/bin/sh`.
- On Linux, can restrict writes, TCP ports, IPC scope, executable paths, and device `ioctl` with Landlock.
## Install tino
Install with Cargo:
```bash
cargo install tino
```
Build a release binary:
```bash
cargo build --release --target x86_64-unknown-linux-musl
```
Copy `tino` into your own image:
```dockerfile
COPY --from=lvillis/tino:latest /sbin/tino /sbin/tino
ENTRYPOINT ["/sbin/tino", "-g", "-s", "--"]
CMD ["/opt/app/service"]
```
## Use tino in Docker and Kubernetes
Run a command locally:
```bash
tino -- /usr/bin/sleep 10
```
Use argument expansion without a shell:
```dockerfile
ENTRYPOINT ["/sbin/tino", "--expand-env", "--"]
CMD ["/opt/app/service", "--port=${SERVICE_PORT:-8900}"]
```
Inspect the final command and effective restrictions without executing the child:
```bash
/sbin/tino --expand-env --write-preset runtime --write-allow /data/logs --explain -- \
/opt/app/service --port=${SERVICE_PORT:-8900}
```
`--expand-env` is not a shell. Supported forms are `${VAR}`, `${VAR:-default}`, and `$$` for a literal dollar sign. Unbraced `$VAR` is left unchanged.
## Restrict container access with Landlock
Landlock-based restrictions require Linux 5.13+ with Landlock enabled.
- `--write-restrict`, `--write-allow`, `--write-preset`, `--write-no-dev`, `--write-warn-only`
- `--bind-tcp-allow`, `--connect-tcp-allow` require Landlock ABI v4+
- `--device-ioctl-allow` requires Landlock ABI v5+
- `--scope-signals`, `--scope-abstract-unix` require Landlock ABI v6+
- `--exec-allow` restricts which executables the child may launch after startup
Example:
```bash
/sbin/tino \
--write-preset runtime \
--write-allow /data/logs \
--bind-tcp-allow 8900 \
--exec-allow /opt/app/service \
-- \
/opt/app/service --port=8900
```
If Docker blocks `landlock_*` syscalls, use the bundled seccomp profile:
```bash
docker run --rm -it \
--security-opt seccomp=./seccomp-landlock.json \
<image> \
/sbin/tino --write-restrict --write-allow /data -- /opt/app/service
```
To make that the Docker default:
```json
{
"seccomp-profile": "/etc/docker/seccomp-landlock.json"
}
```
Refresh the profile with:
```bash
python scripts/update-seccomp-landlock.py
```
## Download binary releases
GitHub Releases publish versioned archives with a single top-level directory:
```text
tino-<version>-<os>-<arch>-<abi>/
tino
LICENSE
README.md
```
Supported assets:
| `linux/amd64` | `x86_64-unknown-linux-gnu` | `tino-<version>-linux-x86_64-gnu.tar.gz` |
| `linux/amd64` | `x86_64-unknown-linux-musl` | `tino-<version>-linux-x86_64-musl.tar.gz` |
| `linux/arm64` | `aarch64-unknown-linux-musl` | `tino-<version>-linux-aarch64-musl.tar.gz` |
| `linux/arm/v6` | `arm-unknown-linux-gnueabihf` | `tino-<version>-linux-arm-gnueabihf.tar.gz` |
| `linux/arm/v7` | `armv7-unknown-linux-gnueabihf` | `tino-<version>-linux-armv7-gnueabihf.tar.gz` |
Each release also includes:
- `SHA256SUMS`
- per-asset `*.spdx.json` SBOM files
- GitHub artifact attestations for archives and SBOMs
## Environment defaults
These environment variables act as defaults. Explicit CLI flags still win.
- `TINI_SUBREAPER`
- `TINI_KILL_PROCESS_GROUP`
- `TINI_VERBOSITY`
## Testing
```bash
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all --verbose
cargo bench --bench logic_paths
```
On Unix targets, `tests/unix_behaviour.rs` covers the CLI license output, missing-command errors, exit-code remapping, environment expansion, and Landlock behavior.