install — for idiots (install a real service, step by step)
Class:
idiot. Every step, nothing assumed. Goal: watch Skidbladnir install a service two different ways (systemd and OpenRC) from the SAME description, and prove it — without touching a real machine. If you already know Rust, readinstall-guide.md.
What you need first
- A terminal. In it, type this and press Enter:
cd /run/media/rickard/T9/git/Skidbladnir
- Rust (
cargo). Check it — type and press Enter:
cargo --version
Step 1 — the big idea, in one sentence
You write one description of your service (what to run, as which user, which ports). Skidbladnir turns it into the right files and commands for whatever init system the target uses — systemd on Ubuntu, OpenRC on Alpine — and it does this as data you can inspect before anything runs.
Step 2 — run the install tests and watch them pass
The install lifecycle has tests that install a service into a temporary folder (so no root, no real machine) and check every file and command. Run them — type and press Enter:
cargo test --release install_product
Look for the green test result: ok. Two tests just ran:
install_product_on_systemd_system— installed the service the systemd way.install_product_on_openrc— installed the same service the OpenRC way.
Step 3 — see the "one spec, two backends" proof
Type and press Enter:
cargo test --release one_spec_renders_to_systemd_and_openrc
That single test takes ONE ServiceSpec and renders it to BOTH systemd and OpenRC, each in its own native shape. That is the whole point of the install tree: describe once, install anywhere. The SAME description now also renders to SysV (/etc/init.d/<name> LSB script), runit (a /etc/sv/<name>/ service directory), dinit (a /etc/dinit.d/<name> textual service description), s6-rc (a /etc/s6-rc/source/<name>/ compiled-source definition dir), OCI (a podman run container invocation), Quadlet (a systemd .container unit podman-systemd turns into a <name>.service) and Windows SCM (a WiX .wxs service fragment driven by sc.exe) — all eleven backends from one spec, full coverage. Watch the runit, dinit, s6-rc, OCI, Quadlet and Windows ones:
cargo test --release runit_renders_a_service_dir_with_run_finish_conf_and_log
cargo test --release dinit_renders_a_service_description_and_env_file
cargo test --release s6rc_renders_a_source_definition_dir_with_run_finish_deps_and_env
cargo test --release oci_renders_a_podman_run_invocation_and_env_file
cargo test --release quadlet_renders_a_container_unit_and_verbs
cargo test --release windows_service_renders_a_wix_fragment_and_sc_verbs
Step 4 — understand the three verbs
Skidbladnir treats these as three different jobs (run each test to watch it):
- install = make the service + unpack the product + create its data and log folders.
cargo test --release install_product_on_systemd_system
- update = swap in a new version but keep the data and logs.
cargo test --release update_product_preserves_data_and_log_and_swaps_version
- uninstall = remove the service; keep the data unless you say "purge".
cargo test --release uninstall_product_purge_flag_controls_data_retention
Each green line is Skidbladnir proving that job works, into a throwaway folder.
Step 5 — why "verbs as data" means you can trust it
Notice none of those tests needed root or a real service manager. That is because Skidbladnir does not do the install directly — it produces the list of files to write and the list of commands to run (enable, start, …) as plain data. The test reads that data and checks it. Only the real apply step actually runs the commands. So you can always see exactly what would happen first.
Step 6 — where secrets go (and where they must NOT)
A service's password or token is a secret. The systemd unit file lives at /etc/systemd/system/<name>.service, which anyone on the machine can read (mode 0644). So a secret must never be written into it. Skidbladnir gives you two knobs: with_env(key, value) for ordinary settings (these end up in the unit, in the clear) and with_secret_env(key, value) for secrets (these go only into a locked-down env file that is chmod 600 — readable by nobody but the owner). If you set a secret but forget to say where the env file lives, Skidbladnir refuses to install rather than leak it. Watch the guard prove it:
cargo test --release secret_env_never_leaks_into_world_readable_unit
cargo test --release write_private_file_is_0600_even_over_a_loose_preexisting_file
The first line checks the token is nowhere in the unit but is in the private file; the second checks the private file is chmod 600 the instant it is created — never briefly world-readable.
Step 6 — see the identity a real install would mint
Type and press Enter:
cargo test --release fresh_dirs_mint_different_install_ids
This proves that installing onto the same machine twice keeps the same machine fingerprint but gets a fresh install id each time — that is how Skidbladnir tells "same machine, reinstalled" apart from "a different machine".
Where to go next
- To drive a real install (with root, on a real target), read
install-guide.md. - To understand why it is a tree of init backends and not just systemd, read
install-reasoning.md.