Blog

Technical articles on engineering, research, and leadership.

A passive Suricata IDS feeding an XDP blocklist on small Fedora gateways, where the firewall sits in the path of the only way back into the box. The failure direction had to be decided before the datapath was written, and the hard part was every reporting layer that claimed a state it had not checked: an auto-blocker a spoofed packet can aim at your own resolver, a health check exempt from the mechanism it monitors, and an emergency control that took an exit status as proof of effect.

eBPFXDPSuricataLinuxsystemdNetworkingSecurity

Moving CI from three hand-built self-hosted runners to ephemeral Actions Runner Controller pods on a small k3s cluster. The architecture is a Helm chart and an afternoon. The traps are a 50-byte MTU difference that resets every container a job starts, a chart that hardcodes the one flag you need, a runner image with no libatomic, and rootless BuildKit refusing to mount /proc.

Kubernetesk3sGitHub ActionsARCBuildKitCI/CDNetworkingDevOps

Moving one small Next.js site from a CI job that SSHed into a box to a single-node k3s cluster reconciled by Flux. The interesting part is not the architecture; it is the traps: a StorageClass that disappears with a flag, a DHCP-supplied search domain that resolves Let's Encrypt to localhost, a Helm value that flattens to nothing, and an image-automation marker that fails silently when you add a word of prose to it.

Kubernetesk3sFluxCDGitOpsTraefikCI/CDDevOps

Every cover on this blog is a cyberpunk neon infographic made with OpenAI's gpt-image-1. This is what happened when I tried to reproduce that exact style locally on a MacBook Pro M5 Max, with no API: which open models match the aesthetic, why none of them can render small legible text, and the composite workflow that closes the gap.

Image GenerationFLUXQwen-ImageApple SiliconMLXmfluxLocal AI

A reproducible, end-to-end pipeline that turns Qwen2.5-Coder-14B into a focused Kubernetes troubleshooting assistant, trained with MLX on a single MacBook Pro M5 Max and deployed through llama.cpp. The twist: every training example is authored by Claude Opus, making this a worked example of distilling a strong closed model into a specialized open-weight one.

LLMFine-TuningLoRAMLXApple SiliconKubernetesllama.cpp

Part two of fine-tuning Qwen2.5-Coder-14B into a Kubernetes troubleshooting assistant. The first run proved the pipeline on 47 examples and overfit instantly; the obvious fix was more data. This is what happened when I scaled the synthetic dataset from 65 to 2,053 examples, generated it with Claude Code subagents instead of a paid API, and watched the validation loss actually fall.

LLMFine-TuningLoRASynthetic DataClaude CodeSubagentsKubernetes