Kubernetes cluster using Nixidy and ArgoCD
  • Nix 98%
  • Just 2%
Find a file
Martin Berg Alstad 3089d531bc
All checks were successful
ci/woodpecker/cron/flake-check Pipeline was successful
ci: Add flake-checker cronjob
2026-05-26 16:49:58 +00:00
.woodpecker ci: Add flake-checker cronjob 2026-05-26 16:49:58 +00:00
_crds feat: Add import-tree and refactor crd generation 2026-04-11 19:19:37 +02:00
env chore: update toolbox-dev to 0.0.8-dev 2026-05-26 15:32:07 +00:00
lib fix: Fix mkApplication to work with other apps 2026-05-19 18:02:45 +00:00
manifests chore: update manifests/ [CI SKIP] 2026-05-26 15:34:18 +00:00
.gitignore feat: Add pre-commit hook 2026-05-15 19:34:50 +00:00
.sops.yaml Sops for storing ArgoCD secrets 2026-03-31 22:55:11 +00:00
AGENTS.md docs: Add TODO.md and update AGENTS.md 2026-05-25 11:34:54 +00:00
common.nix Remove unused option 2026-05-15 17:34:54 +02:00
flake.lock chore(deps): Update flake inputs 2026-05-25 09:26:03 +00:00
flake.nix fix: Fix mkApplication to work with other apps 2026-05-19 18:02:45 +00:00
justfile chore(deps): Update flake inputs 2026-05-25 09:26:03 +00:00
README.md Init Woodpecker with verify build step (#4) 2026-04-25 10:03:06 +00:00
renovate.json feat(CI): Add switch job (#5) 2026-04-25 12:42:39 +00:00
templates.nix Add statix checker to treefmt 2026-05-15 19:34:45 +00:00
TODO.md Update TODO.md 2026-05-25 19:38:32 +00:00
treefmt.nix Add statix checker to treefmt 2026-05-15 19:34:45 +00:00

Kubernetes Cluster - Nixidy + ArgoCD

GitOps-managed Kubernetes cluster using Nixidy for type-safe manifest generation and ArgoCD for continuous deployment.

Overview

This repository implements the "Rendered Manifests Pattern":

  • Nix configuration (env/dev/*.nix, env/prod/*.nix) defines all Kubernetes resources in a type-safe way
  • Nixidy generates plain YAML manifests and commits them to manifests/dev/ and manifests/prod/
  • ArgoCD watches the manifest directories and automatically syncs changes to the cluster
  • App-of-apps pattern: ArgoCD manages itself and all other applications

Key Benefits: Type safety, reproducible builds, Git-based audit trail, declarative infrastructure.

Repository Structure

cluster/
├── flake.nix                   # Nix flake with dependencies and env configuration
├── flake.lock                  # Locked dependency versions
├── justfile                    # Common operations (run `just` to see all)
├── common.nix                  # Shared configuration (networking, domains, etc.)
├── templates.nix               # Reusable application templates
├── treefmt.nix                 # Formatter configuration
├── _crds/                      # Generated CRD Nix files (regenerate with just regen-crds)
├── env/
│   ├── dev/                    # Dev application definitions (auto-discovered by import-tree)
│   │   ├── *.nix               # Application configs (argocd, traefik, etc.)
│   │   └── *.sops.yaml         # Encrypted secrets
│   └── prod/                   # Prod application definitions
│       └── *.nix
└── manifests/
    ├── dev/                    # Generated YAML manifests for dev (committed, do not edit)
    │   ├── apps/               # ArgoCD Application definitions
    │   ├── argocd/             # ArgoCD manifests
    │   └── */                  # Other application manifests
    └── prod/                   # Generated YAML manifests for prod (committed, do not edit)

Prerequisites

  • Nix with flakes enabled
  • Kubernetes cluster (k3s recommended)
  • SOPS with age keys for secrets management (optional)

Ingress & Routing

The cluster uses Traefik as the ingress controller, deployed via Helm chart.

Configuration

  • LoadBalancer IP: 192.168.10.228 (configured in common.nix)
  • Domain (dev): *.dev.martials.no / Domain (prod): *.martials.no (configured in common.nix)
  • Entry Points:
    • web: HTTP (port 80)
    • websecure: HTTPS (port 443)

Routing Methods

Traefik IngressRoute (type-safe Nix resources preferred; YAML also supported):

resources.ingressRoutes.myapp-route.spec = {
  entryPoints = [ "web" ];
  routes = [
    {
      match = "Host(`myapp.dev.martials.no`)";
      kind = "Rule";
      services = [ { name = "myapp-svc"; port = 80; } ];
    }
  ];
};

See toolbox.nix for a complete example.

Customizing Networking

Edit common.nix to configure:

  • networking.localIp: LoadBalancer IP address
  • networking.domain.root: Base domain
  • networking.domain.k8s: Kubernetes subdomain

Quick Start

# Enter development shell (provides nixidy, kubectl, sops)
nix develop

# View available commands
just

# Build manifests (preview, doesn't modify files)
just build dev

# Generate manifests to manifests/dev/
just switch dev

# Review changes and commit
git diff manifests/
git add env/ manifests/
git commit -m "Update configuration"
git push

Note: ArgoCD automatically deploys changes pushed to the repository.

Common Operations

Run just or just --list to see all available commands. Most common:

just build dev          # Preview generated manifests
just switch dev         # Generate and write manifests
just diff dev           # Compare current vs generated
just argocd-status      # Check ArgoCD application status
just pods               # View all pods
just sops-edit          # Edit encrypted secrets
just regen-crds         # Regenerate CRD type modules from generators

See the justfile for the complete list of operations.

Development Workflow

Making Changes

  1. Edit configuration in env/dev/*.nix (or env/prod/*.nix)
  2. Build and validate: just build dev
  3. Generate manifests: echo y | just switch dev
  4. Review: git diff manifests/
  5. Commit and push
  6. ArgoCD auto-syncs within minutes

Adding a New Application

  1. Create env/dev/myapp.nix (or env/prod/myapp.nix) — it is automatically discovered by import-tree, no registration needed:
{ lib, ... }:

{
  applications.myapp = {
    namespace = "myapp";
    createNamespace = true;
    
    resources = let
      labels = { "app.kubernetes.io/name" = "myapp"; };
    in {
      deployments.myapp.spec = {
        replicas = 2;
        selector.matchLabels = labels;
        template = {
          metadata.labels = labels;
          spec.containers.myapp = {
            image = "registry.example.com/myapp:v1.0.0";
            ports.http.containerPort = 8080;
          };
        };
      };
      
      services.myapp.spec = {
        selector = labels;
        ports.http = { port = 80; targetPort = 8080; };
      };
    };
  };
}
  1. Build, switch, and commit: just build devecho y | just switch dev → commit env/ + manifests/

See DEPLOYMENT_GUIDE.md for detailed examples including ingress, secrets, databases, and CI/CD setup.

Using Helm Charts

helm.releases.myapp = {
  chart = lib.helm.downloadHelmChart {
    repo = "https://charts.example.com";
    chart = "app";
    version = "1.0.0";
    chartHash = "";  # Leave empty; build error provides correct hash
  };
  
  values = {
    replicaCount = 2;
    # ... other values
  };
};

Managing Secrets with SOPS

# Edit encrypted secrets (requires age key configured)
just sops-edit

# Secrets are automatically decrypted by SOPS operator in cluster

Documentation

  • AGENTS.md: Guidelines for AI agents and contributors
  • justfile: All available commands with descriptions

Architecture

  • Type Safety: Nixidy validates resources against Kubernetes schemas
  • Reproducibility: flake.lock pins all dependencies
  • GitOps: Single source of truth in Git, ArgoCD handles deployment
  • Declarative: Entire cluster state defined in Nix configuration
  • Secrets: SOPS encrypts secrets at rest in Git, decrypted in-cluster

Resources

License

Personal cluster configuration. Use as reference for your own setup.