GloriousFlywheel

Container Builds

This project uses three methods for building OCI container images, selected based on the requirements of each component.

Build Methods

nix2container (Preferred)

nix2container builds OCI images directly from Nix derivations without requiring a Docker daemon. It is the preferred method for all Nix-based components because it produces byte-for-byte reproducible images and generates optimized layers based on the Nix store graph.

Key properties:

Usage in this project:

# Simplified example from flake.nix
packages.attic-server-image = nix2container.buildImage {
  name = "attic-server";
  config = {
    entrypoint = [ "${atticd}/bin/atticd" ];
    cmd = [ "--mode" "monolithic" ];
  };
  layers = [
    (nix2container.buildLayer { deps = [ atticd ]; })
  ];
};

Dockerfile (Fallback)

Standard multi-stage Dockerfiles are used when the component is not built with Nix or when the build requires a Node.js toolchain that is simpler to express as Docker stages.

The runner dashboard uses this approach:

The Dockerfile lives at app/Dockerfile and can be built with any standard Docker-compatible tool (Docker, Podman, Buildah).

rules_img (Bazel-Native)

For components managed entirely within Bazel, the image_layer and image_manifest rules from the Bazel ruleset produce OCI images without shelling out to Docker or Nix. This is used for the SvelteKit application image target.

Key targets:

The Bazel approach is useful when the image contents are already Bazel outputs (JavaScript bundles, static assets) and adding a Nix or Docker step would introduce unnecessary complexity.

Container Registries

Registry Visibility Usage
ghcr.io/{your-org} Public Upstream images published for general consumption
registry.gitlab.com/{your-group} Private Overlay images, deployment-specific builds

Images are tagged with both a content-based digest and a mutable latest tag. CI pipelines push to the appropriate registry based on the build context (upstream vs. overlay).

Attic Server Container

The Attic cache server runs as a container with the following characteristics:

graph TD
    A[nix2container] -->|builds| B[attic-server image]
    B -->|contains| C["/bin/atticd"]
    C -->|"--mode monolithic"| D[Auto-migrations + Server]
    D -->|reads| E[Config file + env vars]
    D -->|connects| F[PostgreSQL]
    D -->|serves| G[Binary cache API]

Choosing a Build Method

graph TD
    Q["Is the component<br/>built with Nix?"]
    Q -->|Yes| N[nix2container]
    Q -->|No| Q2["Are all inputs<br/>Bazel targets?"]
    Q2 -->|Yes| R[rules_img]
    Q2 -->|No| D[Dockerfile]