## Summary
- Move Dagger module from `.dagger/` to repo root (`src/blumeops/`), rename `blumeops-ci` → `blumeops`
- Replace opaque `docker_build()` with native Dagger pipelines that surface full build errors per step
- Migrate navidrome as the first container (`containers/navidrome/container.py`)
- Upgrade navidrome from v0.60.3 to v0.61.1 (major artwork overhaul, SQLite FTS5 search, server-managed transcoding)
- Add `dagger call container-version` for CI version extraction without Dockerfile parsing
- All mise tasks (`container-list`, `container-version-check`, `container-build-and-release`) updated for hybrid mode
- Legacy `docker_build()` fallback preserved for all other containers
## Motivation
When navidrome v0.61.0 added a new Go build tag (`sqlite_fts5`), `docker_build()` showed only "exit code: 1". We had to run `docker build --progress=plain` manually to find `undefined: buildtags.SQLITE_FTS5`. Native Dagger pipelines show the full error inline.
## Container build dispatch needed
After merge, dispatch container build for navidrome:
```
mise run container-build-and-release navidrome --ref 470b4bd
```
## Deploy steps
1. Wait for container build to complete
2. Back up navidrome-data PVC (non-reversible DB migrations)
3. `argocd app set navidrome --revision main && argocd app sync navidrome`
4. Verify at https://dj.ops.eblu.me
## Future
Remaining containers migrate incrementally in follow-up PRs using the same pattern.
Reviewed-on: #330
96 lines
3.7 KiB
Markdown
96 lines
3.7 KiB
Markdown
---
|
|
title: Add Dagger Nix Build Function
|
|
modified: 2026-04-11
|
|
tags:
|
|
- how-to
|
|
- containers
|
|
- ci
|
|
- dagger
|
|
- zot
|
|
---
|
|
|
|
# Add Dagger Nix Build Function
|
|
|
|
Add Dagger functions for building nix container images and extracting version info from nix derivations. This enables local nix container evaluation and provides the version extraction mechanism needed by [[add-container-version-sync-check]].
|
|
|
|
## Context
|
|
|
|
Discovered during analysis of [[adopt-commit-based-container-tags]]: nix containers (authentik, ntfy) derive their bundled app version from the nixpkgs pin, not from an explicit declaration. To validate that a VERSION file matches the actual nix-built version, we need a way to query the version from nix.
|
|
|
|
Currently, nix containers can only be built on ringtail (the `nix-container-builder` runner). There is no local build path for developers — the only option is to push and wait for CI. Adding a Dagger-based nix build gives both local evaluation and version extraction.
|
|
|
|
## What to Do
|
|
|
|
### 1. Add `build_nix` Dagger function
|
|
|
|
A new function in `src/blumeops/main.py` (formerly `.dagger/src/blumeops_ci/main.py`) that builds a nix container inside a `nixos/nix` container:
|
|
|
|
```python
|
|
@function
|
|
async def build_nix(
|
|
self, src: dagger.Directory, container_name: str
|
|
) -> dagger.File:
|
|
"""Build a nix container from containers/<name>/default.nix. Returns the image tarball."""
|
|
# Uses NIX_IMAGE (nixos/nix:2.33.3) — already defined in the module
|
|
# Runs nix-build inside the container
|
|
# Returns the docker-archive tarball
|
|
```
|
|
|
|
This mirrors the existing `build` function (Dockerfile) but for nix. The result is a docker-archive tarball that can be loaded with `docker load` or pushed with `skopeo`.
|
|
|
|
### 2. Add `nix_version` Dagger function
|
|
|
|
A function that extracts the version of a specific nix package from the nixpkgs pin:
|
|
|
|
```python
|
|
@function
|
|
async def nix_version(
|
|
self, src: dagger.Directory, package: str
|
|
) -> str:
|
|
"""Extract the version of a nixpkgs package. Returns version string."""
|
|
# nix eval --raw nixpkgs#<package>.version
|
|
```
|
|
|
|
This lets the version sync check run `dagger call nix-version --src=. --package=authentik` to get the actual version that would be built.
|
|
|
|
### 3. Add `publish_nix` Dagger function (optional)
|
|
|
|
If useful, a combined build-and-push that mirrors `publish` but for nix images:
|
|
|
|
```python
|
|
@function
|
|
async def publish_nix(
|
|
self, src: dagger.Directory, container_name: str, version: str,
|
|
registry: str = "registry.ops.eblu.me",
|
|
) -> str:
|
|
"""Build nix container and push to registry via skopeo."""
|
|
```
|
|
|
|
This would give a `dagger call publish-nix` path parallel to the existing `dagger call publish`.
|
|
|
|
## Nix in Dagger
|
|
|
|
The `flake_lock` function already demonstrates running nix inside Dagger using `nixos/nix:2.33.3`. The nix build function follows the same pattern but needs:
|
|
|
|
- `NIX_PATH` set to resolved nixpkgs (same as the CI workflow does)
|
|
- `--extra-experimental-features "nix-command flakes"` for `nix eval`
|
|
- The full repo source mounted (nix files may reference other files like `test-connectivity.sh`)
|
|
|
|
## Key Files
|
|
|
|
| File | Change |
|
|
|------|--------|
|
|
| `src/blumeops/main.py` | Add `build_nix`, `nix_version`, optionally `publish_nix` |
|
|
|
|
## Verification
|
|
|
|
- [ ] `dagger call build-nix --src=. --container-name=ntfy` produces a valid docker-archive tarball
|
|
- [ ] `dagger call nix-version --src=. --package=ntfy-sh` returns the correct version string
|
|
- [ ] `dagger call nix-version --src=. --package=authentik` returns the Authentik version
|
|
- [ ] Tarball from `build-nix` can be loaded with `docker load` and run locally
|
|
|
|
## Related
|
|
|
|
- [[add-container-version-sync-check]] — Parent: needs nix version extraction for sync check
|
|
- [[adopt-commit-based-container-tags]] — Grandparent goal
|
|
- [[dagger]] — Dagger reference
|