Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ jobs:
- name: Verify Bionic linkage
run: |
set -euo pipefail
for f in dist/microinit-android-* dist/shutdown-android-*; do
for f in dist/libmicroinit.so dist/libshutdown.so dist/microinit-android-* dist/shutdown-android-*; do
[ -f "$f" ] || continue
file "$f"
if ! file "$f" | grep -qi 'android\|linker64\|linker'; then
Expand Down Expand Up @@ -288,7 +288,13 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }}

- name: Publish microinit-android-arm64
run: ./scripts/publish-oci-microinit-android.sh dist/microinit-android-arm64 dist/shutdown-android-arm64
run: |
set -euo pipefail
microinit=dist/libmicroinit.so
shutdown=dist/libshutdown.so
[[ -f "${microinit}" ]] || microinit=dist/microinit-android-arm64
[[ -f "${shutdown}" ]] || shutdown=dist/shutdown-android-arm64
./scripts/publish-oci-microinit-android.sh "${microinit}" "${shutdown}"

- name: Job summary
run: |
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<img src="docs/logo.png" alt="microinit" width="240">
</p>

Lightweight PID 1 init system and service supervisor designed for BigFred OS.
Lightweight PID 1 init system and service supervisor for embedded Linux and containers.
Works in embedded systems based on Linux as well as in containers.

Lightning fast and solid-rock reliable. Inspired by supervisord and Kubernetes, handles dependencies, able to self-heal.
Expand Down Expand Up @@ -131,6 +131,9 @@ MIT

See **[docs/README.md](docs/README.md)** for the full index.

- [Operator guide](docs/operator.md) — manage services, write config, dependencies, boot
- [Operator guide](docs/operator.md) — everyday CLI and boot
- [Configuration](docs/configuration.md) — JSON, drop-ins, hot reload
- [Service lifecycle](docs/service-lifecycle.md) — states and dependency behaviour at boot
- [Using as supervisord](docs/using-as-supervisord.md) — PHP-FPM + NGINX example
- [Control socket API](docs/api.md) — Unix socket protocol for integrations
- [Architecture](docs/architecture.md) — design overview (`init` / `supervise`, reload, OTel)
5 changes: 4 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ Guides and references for running and integrating **microinit**.

| Document | Audience | Contents |
|----------|----------|----------|
| [Operator guide](operator.md) | Linux admins / device operators | Managing services from the shell, writing JSON config, dependencies, boot sequence |
| [Operator guide](operator.md) | Linux admins / device operators | Everyday CLI, boot, quick config overview |
| [Configuration](configuration.md) | Administrators | JSON files, drop-ins in subfolders, hot reload, service fields |
| [Service lifecycle](service-lifecycle.md) | Administrators | States over time; dependency when a service restarts at boot |
| [Using as supervisord](using-as-supervisord.md) | Container / VM admins | `supervise` mode; PHP-FPM + NGINX with drop-ins and hot reload |
| [Control socket API](api.md) | Integrators / UI / scripts | Unix socket framing, request/response JSON |
| [Architecture](architecture.md) | Developers | Design overview: `init` vs `supervise`, reload, OTel, distribution |
| [Developer index](developer.md) | Contributors / embedders | Doc map + Go SDK pointer |
Expand Down
3 changes: 2 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ For `logs` with `follow: true`, keep reading frames in a loop (each frame has it

## Further reading

- [Operator guide](operator.md) — day-to-day CLI and config
- [Operator guide](operator.md) — day-to-day CLI
- [Configuration](configuration.md) — JSON files and hot reload
- [Architecture](architecture.md) — internals
- [Documentation index](README.md)
11 changes: 5 additions & 6 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ This document explains **why** microinit exists, **how** it is designed, and **w

**microinit** is a small program that on a device (or in a container) **starts and supervises services** — networking, databases, applications — according to a list stored in JSON files. It can also act as a classic system init (Linux process number 1).

It is not a full systemd. It aims to be **lightweight, predictable, and easy to embed** in a system image (for example BigFred OS) and in containers.
It is not a full systemd. It aims to be **lightweight, predictable, and easy to embed** in custom Linux system images and in containers.

---

Expand All @@ -18,7 +18,7 @@ The same supervisor logic runs under two thin wrappers:

| | `microinit init` | `microinit supervise` |
|---|---|---|
| Typical use | Embedded / hub system (PID 1) | Container, distroless |
| Typical use | Embedded / custom Linux (PID 1) | Container, distroless |
| Early-boot (mounts, etc.) | Yes | No |
| Console login (getty) | Yes, when PID 1 | No |
| Logs on TTYs (tty2 / tty3) | Yes | No (in-memory ring + IPC / optional files) |
Expand Down Expand Up @@ -175,11 +175,10 @@ With `panic = abort` in release, metrics code must avoid panics — a failure in

Two independent Linux artifacts, plus an Android binary bundle:

1. **ORAS (linux)** — static arm64 binaries (`microinit` + `shutdown`) plus early-boot and unmount scripts for the hub system image, e.g. `ghcr.io/dcc-bigfred/microinit-linux-arm64`.
1. **ORAS (linux)** — static arm64 binaries (`microinit` + `shutdown`) plus early-boot and unmount scripts for system images (see project README for registry URLs).
2. **ORAS (android)** — supervise-only Bionic binaries (`microinit` + `shutdown`, built
with `--no-default-features`), e.g. `ghcr.io/dcc-bigfred/microinit-android-arm64`.
GitHub Releases also ship `armv7` and `x86_64`.
3. **Distroless container image** (amd64 + arm64) — `ghcr.io/dcc-bigfred/microinit`, default `ENTRYPOINT /microinit` + `CMD supervise`.
with `--no-default-features`). GitHub Releases also ship `armv7` and `x86_64`.
3. **Distroless container image** (amd64 + arm64) — default `ENTRYPOINT /microinit` + `CMD supervise` (see README for the current image name).

Tag lifecycle: `main` / `sha-<7>` on push, `v*` / `latest-release` on release.

Expand Down
230 changes: 230 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
# Configuration

This page explains **where** microinit reads settings, **how** to describe a service in JSON, and **what happens when you save a file** (hot reload). No Rust required — only a text editor.

---

## Where files live

By default durable state lives under **`/data`**. Override with **`DATA_DIR`** (absolute path, e.g. `/data`).

| File or folder | Purpose |
|----------------|---------|
| `$DATA_DIR/etc/microinit.json` | Main file — service list and global options |
| `$DATA_DIR/etc/microinit.services.enabled-override.json` | Written by `microinit enable` / `disable` |
| `$DATA_DIR/etc/microinit.d/services/**/*.json` | **Drop-ins** — extra or overriding services |
| `$DATA_DIR/etc/microinit.json.example` | Example (created if missing) |

A system image may **seed** `/data/etc/microinit.json` from `/etc/microinit/microinit.json` during early-boot — only if `/data` does not already have its own copy.

With **`microinit supervise --config /path/microinit.json`**, drop-ins sit next to that file:

```text
/etc/microinit/microinit.json
/etc/microinit/microinit.d/services/
/etc/microinit/microinit.services.enabled-override.json
```

---

## Drop-ins (files in subfolders)

You do not have to put every service in one big `microinit.json`. Extra JSON under **`microinit.d/services/`** is loaded automatically.

**Rules:**

1. Any `**/*.json` in that tree (subfolders are fine).
2. Files sorted **alphabetically** (full path).
3. Same service **`name`** — the **later** file wins.
4. Add a new service or replace fields of an existing one.

**Example layout:**

```text
/data/etc/
microinit.json
microinit.d/
services/
base/network.json
web/
php-fpm.json
nginx.json
```

`web/nginx.json` can set `"dependsOn": ["php-fpm"]` while `php-fpm` lives in `web/php-fpm.json`. Folder order matters only when the **same** service name appears twice.

**Tip:** folder names like `10-base/`, `20-web/` control override order.

---

## Main file (skeleton)

```json
{
"version": 1,
"socket": "/run/microinit.sock",
"console": "/dev/tty1",
"logs": {
"tty": "/dev/tty2",
"initTty": "/dev/tty3",
"lines": 300,
"logToFiles": false,
"dir": "/data/logs"
},
"services": []
}
```

| Field | Meaning |
|-------|---------|
| `version` | Schema version (use `1`) |
| `socket` | Control socket for `microinit list`, UI, scripts |
| `console` | Boot console and getty (init mode) |
| `logs.tty` | Service logs (init mode) |
| `logs.initTty` | microinit’s own messages |
| `logs.logToFiles` | If `true`, also files under `$DATA_DIR/logs/` |
| `openTelemetry` | Optional metrics (see README) |

Most operators only edit **`services`**.

---

## One service entry

### Long-running service (daemon)

```json
{
"name": "myapp",
"enabled": true,
"daemon": true,
"restart": true,
"restartBackoff": 2,
"startWaitSecs": 1,
"shutdownWaitSecs": 5,
"dependsOn": ["network"],
"cmd": "/etc/init.d/myapp",
"cwd": "/"
}
```

With `cmd`, microinit runs `cmd start`, `cmd stop`, `cmd restart`.

Or explicit commands:

```json
"startCmd": "/usr/sbin/myapp --config /data/etc/myapp.conf",
"stopCmd": "killall myapp"
```

**Important:** start should **`exec`** the program in the **foreground** so microinit can track the process and restart on crash. A script that backgrounds a daemon and exits makes microinit think everything is fine with no PID tracked.

### One-shot job (at boot)

```json
{
"name": "network",
"daemon": false,
"restart": false,
"cmd": "/etc/init.d/network"
}
```

Success → `succeeded`. Failure → `failed`.

### Fields — short reference

| Field | Role |
|-------|------|
| `name` | Unique name (CLI, `dependsOn`) |
| `enabled` | `false` = do not start at boot |
| `daemon` | `true` = long-lived; `false` = one-shot |
| `restart` | Retry after crash (daemon only) |
| `restartBackoff` | Seconds before each retry |
| `startWaitSecs` | After start, wait; if process dies in window → `failed` |
| `shutdownWaitSecs` | After stop, wait then `SIGKILL` |
| `background` | Parallel start at boot |
| `dependsOn` | These must be `running` or `succeeded` first |
| `livenessProbe` | Optional health check; failure triggers restart |

### Liveness probe

Exactly **one** of `cmd`, `httpUrl`, or `tcpAddr`:

```json
"livenessProbe": {
"httpUrl": "http://127.0.0.1:8080/health",
"httpAcceptedCodes": [200],
"interval": 30,
"timeout": 5
}
```

Defaults: `interval` 60 s, `timeout` 5 s.

---

## Enable / disable without editing JSON

```bash
microinit disable grafana
microinit enable grafana
```

The override file wins over `"enabled"` in JSON.

---

## Hot reload (save file → apply)

microinit watches JSON via **inotify** (no periodic disk scanning). On save:

1. Short pause (~300 ms) — one save often emits several events.
2. Load and merge (main + drop-ins + override).
3. **Invalid JSON** → old config kept; warning in logs.
4. **Valid JSON** → diff services:
- new → start (with `dependsOn`)
- removed → stop
- definition changed → restart
- `enabled` toggled → start or stop

**Reboot is usually not needed.** After saving:

```bash
microinit list
```

### What does **not** hot-reload

Requires **microinit restart** (on PID 1 hosts: reboot):

- `socket` path
- `logs.*` (TTYs, `logToFiles`, buffer size)
- `console`

---

## Dependencies

```json
"dependsOn": ["network", "redis"]
```

A service starts when every listed name is **`running`** or **`succeeded`**. Until then: **`waiting_for_dependency`** — it starts **on its own** when ready.

`microinit stop` while waiting **cancels** the wait — fixing the dependency does **not** start the service without `microinit start`.

```bash
microinit start --force myapp # debugging only
```

Boot example with restarts: [Service lifecycle](service-lifecycle.md).

---

## Further reading

- [Operator guide](operator.md) — everyday commands
- [Using as supervisord](using-as-supervisord.md) — PHP-FPM + NGINX
- [Service lifecycle](service-lifecycle.md)
- `man/man5/microinit.json.5.mdoc` — full field list
Loading
Loading