Carl Andersson

SUMMARY
DevOps/Site Reliability engineer with 10+ years of experience across infrastructure, networking, and platform engineering. I prefer declarative configuration, battle-tested software, and solving problems properly rather than quickly. Strong background in network architecture, Kubernetes, and Nix-based infrastructure. I've worked across the stack from physical datacenters to cloud platforms, and I build tools when existing ones don't fit.
COMPETENCIES
EXPERIENCE
Dynamist - Systems specialist
Jul 2026 - now()
Building on my previous freelance projects: • nixkube(nix-csi) • pynixd • easykubenix to expand Dynamist's market position for delivering software scalably and reliably. These projects, plus new ones, now live together under nixidae, an umbrella project for Nix, Python and Kubernetes tooling.
SOLID Kubernetes
The complete Kubernetes experience in a bottle. Rewrote Dynamist's Kustomize and Argo CD ApplicationSet platform as about 85 typed components on the NixOS module system, through easykubenix. Helm charts are pinned by hash, rendered into Nix and merged and type-checked with everything else. The output is Kubernetes manifests and OpenTofu configuration. Manifests go to a per-environment branch that Argo CD deploys (the rendered manifests pattern), so every deploy is a commit you can diff and revert. Bootstrap applies from a workstation. Proven on a live IPv6-only Talos lab cluster.
Built the observability stack: vmagent to VictoriaMetrics for metrics, OpenTelemetry Collector to VictoriaLogs for logs, with log lines parsed into structured fields. Dashboards and alert rules ship as code, and are checked against the upstream mixins so thresholds do not come from one cluster's numbers.
Key achievements:
- tofu-operator: Joins easykubenix and terranix, so Kubernetes and OpenTofu configuration share one NixOS module system and can read each other's values. Runs in the cluster (kopf, kr8s), keeps OpenTofu state in Kubernetes, and configures both the cluster and the applications on it, such as the Keycloak clients that make OIDC work. An approval names the digest of the saved plan, so a stale approval cannot apply a different plan. Providers come from Nix derivations generated for every version of every OpenTofu registry provider on every platform, so it can configure anything the provider ecosystem covers.
- Argo CD at scale: One Application with 623 resources pushed the controller to 2.4 GB and caused etcd timeouts. Split delivery into per-component units: 928 objects across 32 Applications.
- Keycloak as code: Realms, OIDC clients, groups and users as OpenTofu written in Nix, reconciled continuously with state kept in the cluster. Proven end to end with kube-apiserver OIDC login and group claims.
- Cluster provisioning: Five IPv6-only Talos nodes as KubeVirt VMs from a Nix-generated
OpenTofu unit. The migration from the old tree gave byte-identical configuration and an empty
tofu planagainst live state. - Monitoring you can trust: 36 scrape jobs, 223 alert rules, 0 evaluation errors. A verification tool runs every alert expression and dashboard query against the live backend (35 dashboards), and build-time checks validate dashboard JSON.
- Apply cost: 209 CRDs were 42.6 of about 45 MB of rendered output and added 922 MiB to apiserver memory. A resourceVersion gate cut a steady-state apply of 1,250 objects from 72 s to 28 s.
- Components: Cilium (LB-IPAM, BGP), Traefik with Gateway API, CloudNativePG with barman backups to Ceph RGW, Rook-Ceph (block, file, object), Harbor, External Secrets, oauth2-proxy, Kyverno, Vertical Pod Autoscaler. Modules for AWS, Azure and OpenStack storage and cloud integration.
Evolvit - Infrastructure Consultant
Oct 2025 - Mar 2026
Building a production Kubernetes environment on VMware for Evolvit. Full platform including ClusterAPI-managed control plane, Cilium networking, OIDC authentication and all bells & whistles. Training staff on Kubernetes, Nix, and Linux administration.
Helicon - Infrastructure Consultant
Sep 2023 - Feb 2025
Stockholm Exergi
Managed HashiCorp-based infrastructure in AWS. Led Terraform refactoring to improve state management and infrastructure reliability. Recommended Kubernetes migration path which client later adopted. Developed tooling using Nix for cross-team developer environments.
Kraftringen
Maintained production AKS cluster with full observability stack. Built extensive CNPG monitoring for TimescaleDB workloads in Grafana. Managed Kustomize-based deployments and version upgrades.
Viaplay - Site Reliability Engineer
Sep 2022 - Aug 2023
SRE in the Media Asset Management division managing hybrid cloud infrastructure. Responsible for 10+ PB storage infrastructure, transcoding compute clusters, and on-premise networking. Architected AWS-to-on-premise connectivity for MAM workload distribution. Part of team managing the physical infrastructure layer underlying Kubernetes clusters.
SDNit - Infrastructure Consultant
Nov 2021 - Sep 2022
Consulting for Viaplay. Initiated and deployed Kubernetes for Media Asset Management. Managed both on-premise RKE2 and EKS clusters with supporting services including Keycloak and observability tooling. Application releases deployed from the developers' CI pipelines with Helm, applied automatically and rolled back on failure.
Key achievements:
Kubernetes deployment
Deployed Kubernetes on-premise using RKE2 on Ubuntu with Ansible to consolidate with previously deployed AWS infrastructure. Kubernetes replaced a custom SaltStack based "scheduler" that installed systemd units. Collaborated with application developers to enable control-plane software that uses Kubernetes jobs for heavy media processing workloads
See more at SDNits websiteDialect - Infrastructure Engineer / SRE
Mar 2019 - Nov 2021
Technical responsibility for a 6-rack datacenter, reporting directly to CTO for infrastructure decisions and purchases. Managed 400-500 VMs. (Including MikroTik Cloud Hosted Router instances for customer network isolation)
Key achievements:
- VMware deployment: Deployed vSphere + vCloud + NSX-T + vSAN stack to replace an unreliable Hyper-V S2D cluster. Customers got self-service via vCloud portal
- Datacenter consolidation: Migrated Dialect conglomerate hosting from InterXion to Skövde datacenter. Live-migrated VMs over stretched L2, then physically relocated and remounted servers to reuse hardware
- Network modernization: Continued L2 removal for remaining edge cases, deployed EVPN on Cumulus Linux (Mellanox + Broadcom hardware) for appropriate L2 stretching, initiated IPv6 rollout
- Backup infrastructure: Deployed Cohesity for VMware and legacy Hyper-V workloads
IT Support & Sysadmin
2014 - 2019
IT support and Windows Server administration serving 50+ SME customers (5-50 users each). Built high-quality support from scratch together with one colleague; by 2025 the team had grown to 15+ members. Specialized in MikroTik networking including site-to-datacenter tunnel infrastructure. PowerShell automation for cross-customer environment provisioning. This role established the networking foundation that led to my later datacenter and infrastructure work.
Key achievements:
- Network architecture redesign: Eliminated chronic STP looping issues by migrating customer connectivity from L2 tunneling to L3 routing, requiring subnet migrations across the customer base
- O365 crisis response: When parent company went bankrupt, wrote PowerShell + Puppeteer automation to create admin users and accept new CSP partnerships across 1000+ Microsoft 365 tenants
- Internal tooling: Built PBX queue monitoring with notifications, custom TeamViewer auto-registration installer (before native support existed), HTTP API for physical phone PBX group login/logout
- MikroTik and networking instructor for all Dialect branch offices
PROJECTS
nixidae
One checkout pinning my Nix + Python (+ Kubernetes) projects, so cross-project changes build and test together.
Umbrella project for Nix + Python, and Nix + Python + Kubernetes, tooling "and friends". One checkout holds several projects as submodules, pinned to a known-good set of commits, so a change that crosses project boundaries can be made, built and tested together instead of drifting apart.
Technical details
Projects in the collection:
- nanopynix - Drive Nix from Python, batteries included
- pynixd - The Nix daemon protocol in Python
- easykubenix - Kubernetes manifests generated via the NixOS module system, plus OpenTofu management: cluster provisioning and day2 (infra on top of what's deployed), with Nix derivations for all OpenTofu registry providers
- nixkube (nix-csi) - CSI driver that mounts the Nix store into pods
- flake-compatish - Reads a flake this project does not own
- user-mode-nixos - NixOS integration tests on User-Mode Linux and QEMU, driven by one Python runner. Both runners behave the same inside and outside the build sandbox (guests get internet only outside it); the UML path needs no KVM.
Each project keeps its own repository and history. The umbrella tool pins them to a known-good set of commits, so cross-project changes build and test together.
pyterm
pymux, a tmux reimplementation in Python, and the terminal stack beneath it, tested against six real terminals.
Umbrella project for pymux—a souped-up tmux reimplementation in Python—and its stack: ptterm, pyte, txterm, ptyhost, and patches to prompt-toolkit, developed together. Supports a range of keyboard and graphics protocols.
Technical details
Projects in the collection:
- pymux - Terminal multiplexer, arranges several terminals
- ptterm - Draws one terminal with prompt-toolkit
- txterm - Draws one terminal with Textual
- ptyhost - Runs a program and carries its bytes
- pyte - Terminal screen parsing and state
- prompt-toolkit - The toolkit underneath it all, patched for render performance
Test suite: Differential and conformance-driven rather than hand-written expectations. The emulator is judged against six independent implementations (kitty, WezTerm, Alacritty, Ghostty, libvterm, xterm.js) and against borrowed suites—xterm's esctest, vttest, libvterm and Alacritty reference tests—each run both directly and through a pymux pane, so the diff is exactly what the multiplexer adds. Pixel-level checks screenshot a real terminal on its own Wayland display with and without pymux and subtract the images; Hypothesis property tests hold the resize/reflow invariants; every check is a hermetic Nix derivation that keeps the artifacts of a failing run.
nix-csi
A CSI driver that mounts the Nix store into pods, replacing container images with store paths.
Kubernetes CSI driver that mounts the Nix store into pods, enabling container image replacement with Nix packages. Uses hardlink views with shared inodes for memory-efficient page cache sharing across pods. Works on managed Kubernetes without node modifications.
Technical details
Problem: Container images have inefficient layer sharing, fragile build caching, and no intrinsic SBOM. Nix solves these at the package level but needed Kubernetes integration.
How it works:
- DaemonSet deployment—no node modifications required. Works on managed clusters (EKS, GKE, AKS).
- Creates a node-local Nix store at
/var/lib/nix-csi. - For each CSI volume, creates a hardlink view of requested store paths.
- Mount modes: read-only (direct bind mount, shared inodes) or read-write (overlayfs layer).
Key benefit: Hardlinked files share page cache across pods. When one pod loads a shared library, other pods get cached pages. Container layers can't do this—each container gets separate inodes even with the same base image.
Comparison: Similar concept to nix-snapshotter, but doesn't require containerd modifications. Inspired Flox's "imageless Kubernetes" approach.
Written in Python. In production use in hetzkube.
easykubenix
Kubernetes manifests and OpenTofu management — clusters and day2 — from the NixOS module system.
Kubernetes manifest generation using the NixOS module system. Composes cleanly, scales well, and lets you override with mkForce instead of JSON patches. Renders Helm charts into the module system for compatibility.
Technical details
Why: Helm templates are stringly-typed and hard to debug. Kustomize patches are limited—strategic merge works until it doesn't, JSON patches are verbose. The NixOS module system already solves configuration composition well.
Features:
- Deep merging from multiple sources
- Type checking with clear errors
- Override at any level with
mkForce/mkOverride - Conditional configuration with dependency tracking
Helm compatibility: Renders Helm charts and imports results into the module system. Override rendered resources like any other. Covers most use cases, though some hooks/lifecycle features don't translate.
nix-csi integration: Reference Nix packages directly in manifests—nix-csi automatically identifies and pulls required store paths.
In production use managing all hetzkube deployments: cert-manager, Cilium, kube-prometheus-stack, Keycloak, and applications.
hetzkube
Production-grade Kubernetes on Hetzner, on a budget: ClusterAPI, NixOS nodes, no external load balancer.
LARPing production-grade Kubernetes on Hetzner on a strict budget. Full platform: ClusterAPI control plane, NixOS nodes, Cilium with Gateway API, custom IPAM for IPv4/IPv6 LoadBalancer address reuse, enforced dual-stack via Kyverno, kube-prometheus-stack, and OIDC authentication via Keycloak across all services.
Technical details
Stack:
- Control plane: ClusterAPI managed CX22 node(s).
- Workers: NixOS nodes rebuilt from scratch on every initialization.
- Networking: Cilium for CNI, ingress, Gateway API and network policies. Full dual-stack (IPv4+IPv6) enforced via Kyverno.
- Custom IPAM: Reuses node IP addresses as LoadBalancer addresses to avoid Hetzner floating IP/LB costs. Each node's /64 IPv6 block is carved up for services. Kyverno enforces IP sharing annotations to maximize IPv4 utilization.
- Storage: hetzner-csi for traveling volumes, local-path-provisioner for node-bound volumes.
- Observability: kube-prometheus-stack (Prometheus, Grafana, Alertmanager).
- Auth: Keycloak OIDC for all! (Kube, Grafana, Headlamp, pgAdmin, ...)
Deployed components:
All manifests generated via easykubenix. Application delivery via nix-csi.
</details>
fswiki
A wiki that is a filesystem: a FUSE mount, with an ACL enforced by Postgres on every read.
A wiki that is a filesystem: a FUSE mount whose files are the documents, so vim, rg and every tool you already own work with nothing to integrate. Permissions are enforced by the database on every read—an NTFS-style ACL over an ltree path, evaluated by Postgres row-level security, with no application tier that could forget to check.
Technical details
Architecture: PostgREST in front of Postgres and nothing else serving data; a shared core (client, path naming, three-way merge, render pipeline); the mount runs on trio via pyfuse3; the CLI covers status, diff, push, revert, merge, search, render and preview.
- Saving is not publishing: writes through the mount become private drafts until pushed; push three-way merges against the revision you actually read, so two people editing one page get a conflict instead of a silent lost update (SVN-style commit mode).
- Forbidden is indistinguishable from missing: a page the ACL denies renders, lists and collides exactly like a page that does not exist—the difference between the two is itself a disclosure, and the ACL never makes it.
- Check an ACL by being someone else: read-only impersonation mounts—read-only
transaction,
roin the mount options,0444files—logged server-side before a byte is served; borrow a membership to preview what a new engineer would see. - Reads are audited by the request that serves them: document and audit row commit in one transaction, so there is no window where one happens without the other; cache-served opens queue locally and ship later.
Testing: 1,039 tests against real Postgres and PostgREST (nothing mocked), 91% line coverage; the sandbox-safe half runs as a Nix check.
pyedit
A Python editing tool for AI agents: staged edits, git-merged scopes, apply and undo patches, no line numbers.
A Python editing tool for AI agents: an edit script runs against contextual VFSs—in-memory overlays where every edit is written against the file as first read—so agents can discard line number considerations entirely. Git's own three-way merge reconciles the scopes, and every change comes out as git-canonical apply and undo patches, written and replayed by in-memory libgit2.
Technical details
Model: staged state lives in memory; one function writes to disk. A dry-run
is not a second code path—it is a run that never called apply. The staged state prints as a
unified diff for review; --apply is the only thing that touches disk, and an
applied run prints an undo id that reverses the whole thing.
- Scopes, no drift:
with pyedit.VFS()opens an independent overlay over disk truth; on exit git merges it (disk is ancestor, parent is ours, scope is theirs). Line numbers never enter it: a conflict is aCollision, never a guess, and rename detection follows an edit to the file's new name. - git does the paperwork: dry-run and undo patches are git-canonical, written and applied by libgit2 on a mempack—no Python parses a diff on the replay path, so line numbers are exact by construction.
- Syntax gate: staged text is parsed before it is shown—
compile()for Python, tree-sitter for seventeen languages (Go, Rust, C, C++, Nix, Bash, ...); applying known-broken syntax refuses without--force. tree-sitter also serves position queries and file outlines; rope does Python renames, a real language server the rest. - Speaks foreign patches: OpenAI apply_patch envelopes, libgit2-exact git
diffs, and unified diffs anchored by search—because an agent's
@@numbers are a suggestion, not a promise. One hunk that will not anchor fails the whole input.
Rails: fail closed, loud errors, a watchdog that kills hung runs and dumps every thread's stack, and stored diffs at 0600. Round-trip tested byte for byte: text, create, delete, binary, symlink, no-EOL.
pyjj
Python bindings, CLI, and TUI for jj — an exercise in pyo3 and agent-driven development.
Python bindings, a CLI, and a Textual TUI for Jujutsu (jj). Mostly an exercise in pyo3 and agent-driven development, with self-verification as the point: each project verifies itself in its own Nix build, and the binding-surface documentation is re-checked against every jj_lib release it pins.
Technical details
- pyjj-bindings - Rust/PyO3 crate around jj_lib, arriving as a normal crates.io dependency—no jj monorepo source in the repo at all
- pyjj - pure Python, wraps the bindings in a pythonic API for consumers
- pyjj-cli - CLI on top of pyjj
- pyjjui - Textual TUI on top of pyjj
Split out of the jj monorepo so each project's Nix build is genuinely self-contained—its
own directory is its src, full stop.
grpclib-transports
gRPC over stdio, SSH, Unix sockets, and multiprocessing pipes. Published library, with docs.
gRPC over arbitrary-ish transports: grpclib client and server sessions over custom asyncio transports—stdio subprocess pipes, SSH sessions, Unix-domain sockets, and multiprocessing pipe pairs. Published library, documented at lillecarl.github.io/grpclib-transports.
Crossfaction Battlegrounds
First public crossfaction PvP for WoW private servers (~2012); Blizzard later shipped the idea officially.
First public implementation of crossfaction PvP queuing for World of Warcraft private servers (~2012). Balanced queue times between factions by allowing mixed-faction teams. Implemented multiple queue modes including item-level balancing and FIFO. Still used by private servers today, and the concept was later adopted by Blizzard as an official feature.
Technical details
Problem: WoW factions (Alliance/Horde) had imbalanced PvP populations. On private servers, 80/20 splits meant 30+ minute queues for one faction, instant for the other.
Implementation (C++):
- Reused arena faction field to temporarily assign players to opposite faction during battlegrounds
- Invalidated Player info cache to all BG players
- Faked faction responses in player info cache packets
- Modified scoreboard packets so client UI displayed teams correctly
- Queue modes: simple (first-come-first-served) and item-level balanced (with gear-swap prevention)
Impact: Published publicly—first implementation any server could use. Spread rapidly across the private server community during the 3.3.5a era when faction imbalance was severe. Still in use today.
Blizzard later added crossfaction instances to retail WoW (dungeons/raids first, then battlegrounds). The concept was proven on private servers years earlier.
One of my first real programming projects—modifying a large C++ codebase to solve a problem affecting thousands of players.
Other
- dinix - Render dinit service configurations using Nix
- ghanix - Write GitHub Actions workflows
as NixOS modules; takes
liband nothing else. Early days—not even half-finished. - RC-Butiken - C# sync daemon for 20,000+ SKUs from supplier to Shopify. SQLite state tracking
with
daily diffing to handle API rate limits. Built inventory/price change reports for strategic ordering and crawled
Traxxas.com for spare parts categorization.
Technical details
Problem: Swedish RC hobby shop needed automated product catalog management. 20,000+ products, Shopify API rate limits, daily supplier updates.
Architecture:
- SQLite state tracking: store last-synced state, diff against daily supplier data, push only changes. Reduced daily API calls from 20,000+ to a few hundred.
- Selective sync: inventory/prices updated daily, images/descriptions imported once then shop-maintained.
- Daily reports: inventory changes, price changes, new products—enabled strategic ordering decisions.
Traxxas crawler: Scraped Traxxas.com parts catalog to extract car model → category → part relationships. Generated tags/categories for Shopify products. Bootstrapped better spare parts browsing UX.
Ran reliably for years with minimal maintenance.
This document is compacted for print. For more details, please visit lillecarl.com/cv