Blog
- everything
- #kubernetes
- #ceph
- #docker
- #ansible
- #observability
- #security
- #llm
- #architecture
- all topics
-
I Reverse-Engineered My Smart Ring BLE Protocol Clean-Room
COLMi R02, Realtek RTL8762E, BLE from Linux and a Pixel 10a. 16-byte framing, an unenforced checksum, and a clean-room method with evidence levels.
-
Tracking Meals and Automating Shopping With an MCP Server
An MCP server for meal tracking and grocery shopping automation: planned meals minus live stock, and why the v2 rebuild derives stock from an event journal.
-
Building a Headless Storefront Against the OpenTaberna API
A headless storefront for OpenTaberna: a 37-line API client, TypeScript types generated from OpenAPI, and a compiler that catches field typos.
-
Automating Web Shop Order Processing Before the Catalogue
Web shop order processing automated first: Stripe webhook payment confirmation, stock reservations, outbox-driven DHL labels, two manual steps.
-
OpenTaberna: Headless, Open-Source E-Commerce You Self-Host
OpenTaberna is headless, open-source e-commerce: an Apache-2.0 shop API on FastAPI and PostgreSQL that you self-host with Docker Compose.
-
Traefik's 60-Second readTimeout Covers the Whole Request Body
"Expected filesize of 104857600 bytes but read 29491200": Traefik's readTimeout defaults to 60s and bounds the whole request body, so slow uploads get cut.
-
Multicast Service Discovery on a Host With a WireGuard Interface
"Required key not available" (ENOKEY) on multicast sendto: kernel WireGuard has no peer for 239.0.0.0/8. Filter interfaces on IFF_MULTICAST and IFF_POINTOPOINT.
-
Running a Self-Hosted Tailscale Control Server Behind a Reverse Proxy
Headscale behind Traefik: tls.options=no-h2@file with alpnProtocols http/1.1, because the Tailscale noise handshake breaks when ALPN negotiates h2.
-
nginx: The Map Variable That Fixes the URI in proxy_pass
nginx: [emerg] invalid URI prefix in proxy_pass: a regex location needs a bare upstream, and a map on $uri keeps a path-specific Cache-Control header.
-
A Daily Digest of What Actually Got Merged, Built from MQTT and a Local LLM
paho-mqtt subscriber to SQLite plus a local LLM: a daily digest that summarises merged pull requests per repository from diff stats, no cloud API.
-
The NTP Clock Jump That Made the Scheduler Skip a Week of Measurements
time.time() vs time.monotonic() in a Python scheduler: a backwards NTP step delayed runs by nine days. Monotonic durations and a jump-injecting test.
-
fsGroupChangePolicy: OnRootMismatch and the setgid Invariant That Makes It Sound
Pod stuck in ContainerCreating from fsGroup recursive chown: fsGroupChangePolicy: OnRootMismatch, and why the setgid bit on the volume root makes it safe.
-
kube-proxy in iptables Mode and Native nftables Rules in the Forward Chain
kube-proxy iptables-nft sync silently aborts on native nftables rules a mesh agent adds to the FORWARD chain. Fix: nft delete rule by handle, ip and ip6.
-
The Whole Estate in One Article: How Every Layer Fits Together
Self-hosted platform build order: why mesh, cluster, Ceph storage, identity and observability must precede model serving, shown with Compose depends_on.
-
Documentation as a Repository: Publishing a Wiki.js Site from Reviewed Markdown
Wiki.js Git storage for docs as code: publish reviewed Markdown and fail a pull request when src/ changes without docs/, checked with git diff.
-
Testing Infrastructure Code by Executing Its Real Expressions
Ansible Templar in pytest: render the shipped combine(recursive=True) expression from defaults/main.yml instead of a shallow Python paraphrase.
-
Keeping Documentation Honest with an OpenAPI Snapshot Diff
FastAPI app.openapi() snapshot test in pytest: fail CI when the live OpenAPI schema drifts from the committed openapi.snapshot.json.
-
When Microservice Decomposition Is the Wrong Default
import-linter forbidden contract as a module boundary: a FastAPI modular monolith instead of early microservices, and when a network split pays off.
-
One Local Endpoint for Every Agent Session
OPENAI_BASE_URL=http://localhost:8080/v1 for every AI tool: one local FastAPI proxy that logs each request and refuses internal-only projects.
-
Treating Issue Bodies as Untrusted Input
Prompt injection via GitHub issue bodies: fence untrusted text and accept model output only as a fixed JSON action schema, tested without a model.
-
From a Large Allowlist to Three Denials: Permissions for a Coding Agent
bwrap --unshare-net --cap-drop ALL instead of a command allowlist: sandboxing a coding agent's shell so rm -rf and curl cannot leave the workspace.
-
Self-Hosted LLM Inference: Serving, Benchmarking and Agent Guardrails
Ollama OpenAI-compatible /v1/chat/completions: a repeatable benchmark on your own tasks and a dry-run plus --approve guardrail for infrastructure agents.
-
Verifying an Agent's Work Against Reality, Not Its Own Report
git diff --quiet HEAD and a re-run test command in a separate CI job: verifying a coding agent's work from repository state instead of its own report.
-
Testing an Agent Harness Without Ever Calling the Model
Unit testing a coding agent's tool-call permission layer with pytest and recorded fixtures: allow, deny or ask decisions with no model or API key.
-
The Label as Contract: Consent and Priority as the Whole Queue
agent-ready label as the only consent gate for a coding agent: FIFO order by label time and a re-read-then-swap claim so two runs never share an issue.
-
A Deterministic Daemon That Turns a Labelled Issue Into a Pull Request
git apply --check before git commit: an issue-to-PR daemon where the model only returns a patch and plain Python commits, pushes and opens the PR.
-
Testing That a Canvas Diagram Actually Painted Pixels
getImageData in Playwright to assert a canvas actually drew pixels, since jsdom has no canvas renderer and DOM assertions pass on a blank canvas.
-
Turning Alertmanager Webhooks Into Retained MQTT State
Alertmanager webhook to MQTT retained messages: clear stale state on resolve with an empty retained payload, keeping current alerts in Redis by fingerprint.
-
A Dead-Man's Switch for the Monitoring System Itself
Alertmanager dead man's switch with expr: vector(1) == 1: an always-firing Heartbeat alert and an external receiver that alerts when pings stop.
-
Probing the Names You Publish, Not the Services You Run
blackbox_exporter __param_target relabel_configs: probe the published hostname to catch DNS, TLS expiry and proxy errors that /healthz cannot see.
-
Prometheus HTTP Service Discovery Backed by a Live Inventory
Prometheus http_sd_configs: the targets and labels JSON an inventory endpoint must return, refresh_interval, and why targets persist when it is down.
-
Host Probes via the Textfile Collector Pattern
node_exporter --collector.textfile.directory: torn .prom writes fixed by write-temp-then-rename, and stale files caught with a last-run timestamp alert.
-
Self-Hosted Identity with Keycloak: Central Offboarding and Forward Auth
Keycloak "invalid_grant" "Account disabled": one admin API call disables a user for every OIDC client, plus oauth2-proxy forward auth for apps without login.
-
A Rules File for Health Evaluation, Validated at Load Time
Go rules file with gopkg.in/yaml.v3: yaml.Unmarshal accepts operator: greter. Validate operators and metric names at load time so startup fails.
-
Merging Concurrent Polls Without Ever Serving a Half-Built Graph
atomic.Pointer swap of a fully merged snapshot so concurrent polls never serve a torn read, a bug go test -race cannot see. errgroup with timeouts.
-
An Entity Graph as the Data Model for a Heterogeneous Estate
Go entity graph data model: one Entity struct with Kind and Attrs, typed contains, dependsOn and runsOn edges, health rollup and cycle detection.
-
Forward Auth: Putting Real Authentication in Front of Software That Has None
Traefik forwardAuth with X-Auth-Request-User: strip the header first or clients can spoof it. oauth2-proxy and Keycloak in front of apps with no login.
-
Enforcing Client Identity Alongside Realm Roles
Keycloak azp claim: a realm role does not show which client the token was issued to. Enforcing azp next to role checks in a FastAPI dependency.
-
OIDC Client Shapes: A Token-Validating API Is Not a Login Client
Keycloak directAccessGrantsEnabled on a token-validating API lets it mint tokens. bearerOnly client, oidc-audience-mapper and a PyJWT aud check.
-
Realm-as-Code: Reconciling Clients and Roles But Never Users or Signing Keys
kc.sh import with --override=true recreates the realm, dropping users and signing keys. Reconciling only clients and roles via the Keycloak Admin REST API.
-
DNS Wildcards and Empty Non-Terminals: The Answer That Is Not an Error
A stale _acme-challenge TXT record makes a DNS wildcard return NODATA or NXDOMAIN: RFC 4592 closest encloser, empty non-terminals and a zone check.
-
WireGuard Route Selection: Per-Host /32 Versus Subnet Routes With NAT
WireGuard AllowedIPs overlap: a /24 on a gateway peer and a /32 on a direct peer break the return path. Longest-prefix-match and a /32 on both ends.
-
Group-Based Default-Deny Instead of Hand-Maintained Peer Lists
NetBird Default policy replaced by group-based default-deny: auto_groups on setup keys, role:/tier: group names, and a script diffing live policies.
-
Separating 'Cannot Ever' From 'Currently Broken' in Sweep Automation
Sweep automation: a 404 cannot tell "never supported" from "currently broken". An explicit cannot-ever allowlist with required reasons, and its tests.
-
External Secrets with Offline JWT Validation When Vault Cannot Reach the Cluster
Vault kubernetes auth "failed to validate token" tokenreviews i/o timeout: jwt auth with jwt_validation_pubkeys from sa.pub for External Secrets.
-
Overlay Mesh Networking with NetBird: Peer Addressing and the Public DNS Fallthrough
NetBird mesh hostnames resolve to the public host via a zone wildcard when the mesh resolver is down. Fix: a *.mesh blackhole record and accept-new.
-
cert-manager for Mesh-Only Names That No ACME Challenge Can Reach
Waiting for HTTP-01 challenge propagation, no such host: ACME cannot issue for private names. A cert-manager CA ClusterIssuer and trust distribution.
-
How a VPN Client Silently Shrinks Your Pod Network MTU
Frag needed and DF set (mtu = 1420): a VPN hop below the CNI's auto-detected 1500 MTU stalls large pod transfers. Reproducing it and pinning the MTU.
-
ndots and the Accidental Search-Domain Leak in Pod DNS
dnsConfig.searches with ndots:5 lets an internal wildcard answer external names. Why ndots:1 only half fixes it and a trailing dot fully does.
-
A DNS Canary CronJob as a Regression Test for Split-Horizon Resolution
CoreDNS Corefile rewrite regressions caught by a busybox nslookup CronJob that checks internal, external and NXDOMAIN names and fails the Job.
-
fsGroup Recursive chown Hangs on Large Volumes
fsGroupChangePolicy: OnRootMismatch stops kubelet re-chowning every file on each mount. Why fsGroup pods restart slowly, and when fsGroupPolicy None applies.
-
Object Storage as the Durability Boundary for a Container Registry
MANIFEST_UNKNOWN after losing a registry PVC: REGISTRY_STORAGE s3 on MinIO keeps blobs through helm uninstall. What it does not fix: garbage-collect.
-
Importing Pre-Existing Storage as a Static PersistentVolume
persistentVolumeReclaimPolicy: Retain with volumeName and claimRef binds a PVC to existing data. What Released means and how to rebind safely.
-
Ceph CSI StorageClasses: RBD for Block, CephFS for Shared Volumes
Multi-Attach error for volume: Ceph RBD is ReadWriteOnce by design. When to use rook-ceph-block and when rook-cephfs for ReadWriteMany.
-
Breaking the Circular Dependency in GitOps Secret Delivery
External Secrets SecretStore tokenSecretRef needs a Vault token before GitOps can deliver one. Breaking the loop with one out-of-band secret.
-
Pinning Image Tags to Git SHAs Because GitOps Diffs Manifests, Not Registries
image :latest never triggers an Argo CD rollout because GitOps diffs manifest text. Tagging with git rev-parse --short HEAD and committing it back.
-
Sync Waves and the CRD-Before-Consumer Ordering Problem
no matches for kind "Widget" in version: CRD and CR in one Argo CD sync. sync-wave "-1" fixes ordering; Prune=false stops a CRD prune wiping CRs.
-
ApplicationSets: Onboarding a Workload With a Directory and a Pull Request
ApplicationSet git directory generator on services/*: one Argo CD Application per directory, requeueAfterSeconds, and where sync errors show up.
-
Alerting on Symptoms Instead of Metrics: Designing Alerts People Do Not Ignore
probe_success == 0 via blackbox_exporter instead of CPU alerts, plus a dnspython check that treats NOERROR with an empty answer as down.
-
Argo CD App-of-Apps: Bootstrapping a Bare Cluster from One Root Application
Argo CD app-of-apps: a root Application with directory recurse over apps/ bootstraps a bare cluster from one kubectl apply, with pruning.
-
The Transactional Outbox: Never Losing a Job You Already Committed
Transactional outbox in Postgres: commit-then-enqueue loses jobs on a crash. A SKIP LOCKED relay to Redis Streams and an idempotent consumer.
-
Running Alembic Migrations Once, Before the Workers Fork
alembic upgrade head in app code runs once per gunicorn worker and races. Running it in the entrypoint under pg_advisory_lock, before exec.
-
A Multi-Service docker-compose That a New Contributor Can Actually Start
depends_on condition: service_healthy: why a plain depends_on list races, with Postgres, Redis and Keycloak healthchecks, --import-realm and a smoke test.
-
Runtime Configuration for an Angular Container Without Rebuilding
Angular environment.ts is baked in at ng build. Load config.json via APP_INITIALIZER, generated by envsubst in /docker-entrypoint.d at container start.
-
Layering an Angular Application: core, shared, features and the Rule That Holds
eslint-plugin-boundaries element-types: enforcing one dependency direction between Angular core, shared and features folders, with a failing lint example.
-
Designing a Docker Image Build API: Job Model and Streamed Logs
Docker SDK ImageBuild returns a nil error when RUN fails: read the error field in the JSON build stream. A Go job model with POST /builds and live logs.
-
Embedding a Built Frontend Into a Go Binary with go:embed
//go:embed dist with http.FileServer returns 404 on SPA client routes after a refresh: an index.html fallback, serving the API from the same Go binary.
-
Rootless BuildKit: What fuse-overlayfs Costs on a Cold Cache
Rootless BuildKit with --oci-worker-snapshotter=fuse-overlayfs needs no --privileged, but cold-cache builds pay a FUSE round-trip per file. Measuring it.
-
Running BuildKit as a Remote Builder Without a Docker Daemon
open /var/run/docker.sock: no such file or directory from docker buildx on a containerd CI worker: run buildkitd with mTLS and use the remote driver.
-
Trusting an Internal and a Public Certificate Authority in One Process
curl: (60) SSL certificate problem after SSL_CERT_FILE points at an internal CA: it replaces the trust store. Append with update-ca-certificates instead.
-
A 500 That Was a Misconfigured Client, Not an Auth Failure
resp.json()["active"] raises KeyError when token introspection returns 401 invalid_client. Check the status code first and report a client config error.
-
A Confidential OIDC Client That Exists Only to Introspect Tokens
invalid_client "Parameter client_secret is missing" on Keycloak token introspection for a public SPA client: add a confidential introspection-only client.
-
Building the Dry-Run Path First, and Testing That It Sends Nothing
if dry_run: return guards drift as side effects are added. Split the tool into a pure plan() and apply(), and test that dry run never calls the client.
-
Running Ceph on Commodity Hardware: Failure Domains and the Four Things That Bite
ceph osd df --format json: alert on the fullest OSD, not the mean, because one full OSD stops writes. Plus CRUSH failure domains and monitor quorum.
-
Scoring Tool Calls by Parsed Structure Instead of String Equality
Scoring LLM tool calls: parse the arguments JSON first so key order and 5 vs 5.0 pass, wrong tools fail, and extra fields follow per-case rules.
-
Why a Leaderboard Score Does Not Predict Your Workload
LLM leaderboard scores do not predict a narrow workload. A 20 to 50 case task eval with a deterministic JSON schema scorer instead of an LLM judge.
-
Making a Benchmark Deterministic Against a Server Tuned for Interactive Use
LLM output still varies at temperature 0 with a fixed seed because batching changes float order. Repeat each prompt and compare mean and stdev.
-
An OpenAI-Compatible Proxy in Front of a Local Model Server
/v1/chat/completions behind a FastAPI proxy: bearer API-key auth, unbuffered SSE streaming, and a /healthz that cannot trigger a model load.
-
Serving Several Local Models on One GPU with On-Demand Loading
llama-swap config.yaml with cmd, ttl and healthCheckTimeout: loading llama-server models on demand and unloading idle ones on a single GPU.
-
Sizing One GPU for Local LLM Inference: VRAM, Quantisation and KV Cache
llama-bench -ctk q8_0 -ctv q8_0 vs f16: estimating VRAM for GGUF weights plus a KV cache that grows with context, and catching slow KV cache types.
-
One Dashboard on Five Unrelated Backends: Normalising at the Boundary
asyncio.gather with return_exceptions=True in a FastAPI BFF: map two upstream APIs onto one schema and return partial data with health when one is down.
-
Preventing Overselling with a Database CHECK Constraint
violates check constraint "stock_not_negative": why check-then-decrement oversells under READ COMMITTED, and a single conditional UPDATE that cannot.
-
Idempotent Payment Webhooks with a Deduplication Table
Payment webhook processed twice on retry: dedupe on the provider event ID with a primary key, committed in the same transaction as the side effect.
-
Modelling an Order Lifecycle as an Explicit State Machine
Python order status as a state machine: a transition table and one transition_to method that raises InvalidTransition on moves like shipping a cancelled order.
-
MQTT Persistent Sessions and Retained Messages for Offline Subscribers
MQTT clean_session=False only persists with a stable client ID, QoS 1 and Mosquitto persistence true. Retained messages give new subscribers the last value.
-
A Shared Multi-Stage Base Image for a C++ Service Fleet
vcpkg install pistache rebuilt in every service Dockerfile: a shared, versioned multi-stage base image that compiles C++ dependencies once for the fleet.
-
Migrating Redis Consumers from Python to C++ on Constrained Hardware
redis-plus-plus xreadgroup times out before its block timeout: set socket_timeout to 0. Replacing idle Python Redis stream consumers with C++.
-
UUID Case Normalization as a Recurring Cross-Service Bug
Uppercase vs lowercase UUID keys cause silent cache and database lookup misses between services. Normalise once at the boundary with str(uuid.UUID(value)).
-
Docker Compose or Kubernetes: What the Control Loop Actually Buys You
Docker Compose restart: always vs a Kubernetes Deployment: what happens when the host dies, and what the control loop costs in debugging.
-
Sizing Redis maxmemory Against a Stream Trim Threshold
OOM command not allowed when used memory exceeds maxmemory on XADD MAXLEN: why the stream never trims itself, and why a standalone XTRIM still works.
-
A Single-Writer Rule for Configuration Held in Redis
SET NX PX lease plus a Lua script that checks the fencing token, bumps a version and publishes, so exactly one process writes a Redis config key.
-
Chaining Single-Purpose Redis Consumers into a Processing Pipeline
XREADGROUP, XACK and XAUTOCLAIM: splitting one Python consumer into single-purpose Redis Streams stages with at-least-once delivery and crash recovery.
-
Tracking Moving Objects with Redis Sorted Sets and an Atomic Lua Tick
ZINCRBY updates one member only: a Lua script via redis-cli --eval advances every sorted set score atomically and returns members past a threshold.
-
Auto-Unsealing Vault Without Cloud KMS or a TPM, Using Tang and Clevis
clevis encrypt sss with Tang pins to auto-unseal Vault without cloud KMS or a TPM: binding Shamir key shares, a systemd unit, and the t threshold.
-
Runtime Secret Injection with a Vault Agent Sidecar and a Wrapped AppRole
secret_id_response_wrapping_path in Vault Agent approle auto_auth: a sidecar that bootstraps from a single-use wrapped secret_id and renders secrets to a file.
-
Vault KV-v2: Why put Silently Wipes Every Sibling Field
vault kv put wipes sibling fields and -cas fails with "check-and-set parameter did not match the current version": why, and how patch avoids it.
-
Replacing Distributed SSH Keys with a Vault Certificate Authority
TrustedUserCAKeys with the Vault ssh secrets engine: short-lived SSH user certificates limited by allowed_users and ttl instead of authorized_keys.
-
Tuning Ceph Recovery: The Trade Between Degraded Time and Client Latency
osd_max_backfills does nothing under mClock unless osd_mclock_override_recovery_settings is set. Choosing and measuring osd_mclock_profile for recovery.
-
Capacity Planning Against the Fullest OSD, Not the Average
Ceph full_ratio applies per OSD: one OSD at 95% stops writes while ceph df shows 70%. Alerting on the fullest OSD in ceph osd df, plus the upmap balancer.
-
CRUSH Hybrid Rules: Pinning the Read Primary to SSD Without Rebalancing
step take default class ssd, chooseleaf firstn 1, then class hdd firstn 0: a CRUSH rule with an SSD primary and HDD replicas, tested with crushtool.
-
SMR Drives in a Replicated Cluster: Finding the Disk That Ruins the Pool
lsblk ZONED=none does not rule out drive-managed SMR. A 30-minute fio randwrite probe and p99 latency ratio catch the cliff before it hits a Ceph OSD.
-
A Layered Storage Benchmark: Isolating Device, Network and Protocol Bottlenecks
fio, iperf3, rados bench, then fio on RBD: benchmarking device, network, Ceph protocol and full stack separately to find which layer caps throughput.
-
Infrastructure as Code with Ansible: Making a Host Reproducible from the Repository
ansible-playbook --check --diff and a changed=0 second run as proof a host matches its repository, with a container demo that corrects a hand edit.
-
Multi-Stage Docker Builds: Shipping a Runtime Without the Toolchain
COPY --from=build with CGO_ENABLED=0 and distroless/static: a multi-stage Dockerfile taking a Go image from 812MB to 24MB, and the no-shell trade-off.
-
A Minimal Go HTTP Service with chi, Timeouts and Graceful Shutdown
Go http.Server ReadHeaderTimeout and srv.Shutdown with signal.NotifyContext: draining in-flight requests on SIGTERM in a chi service, with a test.
-
Managing a Shared DNS Zone Through a Replace-Everything API
PUT /zone replaces the whole DNS zone: a read-merge-write client with owner TXT records that keeps unmanaged records and removes stale managed ones.
-
Powering and Discovering Peripherals over PoE with Multicast Announcements
IP_ADD_MEMBERSHIP multicast discovery for PoE sensors in Python: announcer, collector with expiry, and why IGMP snooping without a querier breaks it.
-
Provisioning a Single-Board Computer as an Industrial Edge Node
/proc/device-tree/model read by Ansible to load board-revision vars via include_vars with_first_found, with a generic fallback and a container test.
-
A Python CLI That Scaffolds a Project Structure You Actually Want
Python scaffolding CLI with only argparse and string.Template: generates src layout, pyproject.toml, Dockerfile and .gitignore, tested with tomllib.
-
Replacing pip, venv, flake8, black and isort with uv and Ruff
uv sync --locked and ruff check replacing pip install -r requirements.txt, venv, flake8, black and isort: uv.lock plus one pyproject.toml config.
-
Configuration Precedence: Docker Secrets, Kubernetes Secrets, Environment, .env, Default
Docker secrets in /run/secrets, Kubernetes secret mounts, env vars and .env: a Python resolver with fixed precedence that reports which source won.
-
Closed-Vocabulary Pydantic Validation for a Public Ingest Endpoint
Pydantic extra="forbid" and Literal types return 422 for typo'd fields and unknown values that the default extra="ignore" silently drops.
-
An Exception Hierarchy and One Handler for FastAPI Error Responses
FastAPI add_exception_handler on a base AppError instead of raising HTTPException in services: one status-code mapping and a consistent error body.
-
Designing a Consistent FastAPI Response Envelope
FastAPI response envelope with Pydantic Generic[T] and a custom APIRoute get_route_handler that wraps every response in success, data and error.
-
A Feature-Module Layout for a FastAPI Application That Keeps Growing
FastAPI APIRouter per feature directory with its own router.py, schemas.py and service.py, replacing a shared routers.py, schemas.py and crud.py.
-
chmod -R and the setgid Bit: Why a Four-Digit Mode Is Not Enough
chmod -R 775 clears the setgid bit of 2775 directories, so new files lose the shared group. Separate find -type d and -type f, and assert with stat -c %a.
-
Docker Registry Credentials for Two Local Users on One Host
"may require 'docker login'" for a deploy user after root logged in: credentials live in each user's ~/.docker/config.json. Per-user login with Ansible.
-
Reasserting Kernel Sysctls That Docker Silently Reverts
net.ipv4.ip_forward = 1 although sysctl.d says 0: dockerd rewrites it at start. A oneshot unit After=docker.service reruns sysctl --system.
-
Deploying Docker Compose from Ansible Without Shelling Out
community.docker.docker_compose_v2 instead of a command task running docker compose up -d: real changed status and --check --diff support.
-
Ansible Role Idempotence: Why a changed=0 Run Is the Only Proof You Have
Molecule "Idempotence test failed because of the following tasks": why command, shell and timestamped templates report changed, and how to fix it.
-
Migrating the SSH Port Mid-Playbook Without Locking Ansible Out
Ansible meta: reset_connection after changing the sshd Port: validate with sshd -t, flush_handlers, and ping before closing the old port.
The full text of everything here is in one file at /llms-full.txt.