- Nix 98.2%
- Just 1.8%
| _crds | ||
| env/dev | ||
| manifests/dev | ||
| .gitignore | ||
| .sops.yaml | ||
| AGENTS.md | ||
| common.nix | ||
| DEPLOYMENT_GUIDE.md | ||
| flake.lock | ||
| flake.nix | ||
| justfile | ||
| README.md | ||
| renovate.json | ||
| templates.nix | ||
| treefmt.nix | ||
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) defines all Kubernetes resources in a type-safe way - Nixidy generates plain YAML manifests and commits them to
manifests/dev/ - ArgoCD watches the manifest directory 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
├── env/dev/ # Application definitions (auto-discovered by import-tree)
│ ├── *.nix # Application configs (argocd, traefik, etc.)
│ ├── *.sops.yaml # Encrypted secrets
│ └── _modules/ # Generated CRD type modules (do not edit)
├── _crds/ # Generated CRD Nix files (regenerate with just regen-crds)
└── manifests/dev/ # Generated YAML manifests (committed, do not edit)
├── apps/ # ArgoCD Application definitions
├── argocd/ # ArgoCD manifests
├── sops-secrets-operator/ # SOPS operator manifests
└── */ # Other application manifests
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 incommon.nix) - Domain:
*.k8s.martials.no(configured incommon.nix) - Entry Points:
web: HTTP (port 80)websecure: HTTPS (port 443)
Routing Methods
Traefik IngressRoute (recommended):
yamls = [
(''
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: myapp-route
namespace: myapp
spec:
entryPoints:
- web
routes:
- match: Host(`myapp.k8s.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 addressnetworking.domain.root: Base domainnetworking.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
# Generate manifests to manifests/dev/
just switch
# 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 # Preview generated manifests
just switch # Generate and write manifests
just diff # 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
- Edit configuration in
env/dev/*.nix - Build and validate:
just build - Generate manifests:
just switch - Review:
git diff manifests/ - Commit and push
- ArgoCD auto-syncs within minutes
Adding a New Application
- Create
env/dev/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; };
};
};
};
}
- Build, switch, and commit as usual
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
Important: Never edit .sops.yaml files directly with text editors. Always use sops command.
Documentation
- DEPLOYMENT_GUIDE.md: Comprehensive guide for deploying applications with CI/CD
- 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.lockpins 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
- Nixidy Documentation - Official docs and options reference
- ArgoCD Documentation - GitOps deployment
- k3s Documentation - Lightweight Kubernetes
- SOPS - Secrets management
License
Personal cluster configuration. Use as reference for your own setup.