kadet-hub logokadet-hub

Navidrome on Kubernetes without Docker Compose, with Kapitan

Navidrome 0.64.2, a music server with a web UI and the Subsonic API, with its SQLite database and its music on claims, rendered by the kadet-hub kubernetes generator 1.14.0 from its Docker Compose file.

What it deploys

Required parameters

No parameter has to be set.

Include

A target includes the recipe and its options as classes and can override anything the recipe sets:

classes:
  - recipes.navidrome
parameters:
  namespace: navidrome
  kapitan:
    vars:
      target: navidrome

Fetching it

The quickstart goes through these steps on a kind cluster with the uptime-kuma recipe, from installing Kapitan to the running app.

A separate fetch inventory pins the recipe by version and digest. This is fetch/targets/recipes.yml for version 1.0.0:

parameters:
  kapitan:
    dependencies:
      - type: oci
        source: ghcr.io/kadet-hub/recipes/navidrome:1.0.0@sha256:9a7c239b59e53509e695ba12ee3e194922e3c7bb86b1881a53ac9f23fbff53a1
        output_path: inventory/classes/recipes/navidrome

The first command fetches the recipe into inventory/classes/recipes/navidrome, the second the generators and compiles:

kapitan compile --inventory-path fetch --fetch --output-path .
kapitan compile --fetch

The first command exits with status 1 because the fetch target compiles nothing. Kapitan's --fetch checks neither the digest nor the attestation. This verifies the attestation of the recipe:

gh attestation verify \
  oci://ghcr.io/kadet-hub/recipes/navidrome@sha256:9a7c239b59e53509e695ba12ee3e194922e3c7bb86b1881a53ac9f23fbff53a1 \
  --owner kadet-hub \
  --cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main

The attested index must also list each digest under its recipe with the pinned version, and not as yanked. Verifying by hand shows how to read it.

Settings

Setting Inventory
Navidrome version components.navidrome.image, tag and digest
Navidrome’s settings, such as ND_SCANSCHEDULE or ND_BASEURL components.navidrome.env.<variable>
size of the claim data, 1Gi components.navidrome.volume_claims.data.spec.resources.requests.storage
size of the claim music, 1Gi components.navidrome.volume_claims.music.spec.resources.requests.storage
exposure a route or Ingress of the target to the Service navidrome on port 4533
resources components.navidrome.resources

The claim data holds the SQLite database, the cache of transcoded files and artwork, and Navidrome’s settings. SQLite allows one replica.

The root filesystem is read-only, as the compose file asks. /tmp is an emptyDir, because SQLite needs a temporary file for a database migration of the first start (DEC-215 in the spec). With the compose file alone, Navidrome 0.64.2 exits at its first start for that reason.

Mapping

The service navidrome becomes the component navidrome. Its name stays, so no reference is rewritten.

Compose Recipe
service navidrome StatefulSet navidrome, Service navidrome
deluan/navidrome:latest docker.io/deluan/navidrome:0.64.2@sha256:38dc2727bfcfd5ede290f8ada114fc90368146f265ae4701ddddbcbe2a44ee52, which latest was at migration
port 4533:4533 Service port http on 4533, ClusterIP
volume navidrome_data at /data claim template data, ReadWriteOnce, 1Gi
read_only: true readOnlyRootFilesystem: true and an emptyDir at /tmp (DEC-215)
version, container_name, restart: unless-stopped not rendered
the comment #- "/mnt/music:/music:ro" claim template music, ReadWriteOnce, 1Gi, read-only at /music (DEC-216)
the comment # user: 1000:1000 UID, GID and fsGroup 1000 under restricted (DEC-217)

Proof

check navidrome --level deploys with tests/target.yml, on kind for each Kubernetes minor CI tests. A compose file has no Kubernetes objects to compare with, so the recipe is proven by deploying it (RCP-38).

tests/smoke checks that the pod passes Pod Security restricted. It starts a pod of Navidrome’s image, which carries curl and ffmpeg, as UID 1000 with the claim music-navidrome-0 mounted, and writes a FLAC file of three seconds of silence with a title, an artist and an album. From there, through the Service navidrome on port 4533, it

Versions

The recipe's files are in kadet-hub/recipes. All recipes