Raxx · internal docs

internal · gated

RCA — Woodpecker CI server replace (pip-cache activation) ran ~22min vs 3-5min accepted downtime

Incident ID: 2026-08-07-woodpecker-server-replace-pip-cache-activation Date: 2026-08-07 Severity: SEV-2 (deploy pipeline blocked — CI fully down for part of the window) Duration: ~23m total (destroy of old instance ~06:20 UTC → first pipeline resumed executing 06:42:46 UTC) Blast radius: Woodpecker CI (ci.moosequest.net) — no pipelines could run or complete during the window. No customer-facing production impact (CI/build system only). Author: sre-agent

Summary

Issue #4416 authorized a standalone terraform apply to replace the Woodpecker CI server instance and activate the PyPI cache wiring (docs/ops/runbooks/ci-build-cache.md), accepting an estimated ~3-5 minute downtime and the known risk that the out-of-band wp-config-svc container would be re-provisioned from the Terraform template. The replace itself (terraform apply -target=aws_instance.woodpecker_server) completed cleanly in under 2 minutes, but three post-replace validation checks each surfaced a gap that the plan/apply step could not have shown, extending real downtime to ~23 minutes: (1) the boot template lacked an ECR login step needed to pull the private wp-config-svc image, so the server itself crash-looped; (2) the -target-scoped apply correctly avoided ~23 unrelated pending resources but also skipped the ALB target-group re-attachment, leaving the public URL unreachable after the server itself came up; (3) it also skipped the CI agent launch template, leaving the running agent instance permanently pointed at the destroyed instance's dead private IP, so queued pipelines sat pending indefinitely. All three were fixed forward during validation. Final state: server healthy, wp-config-svc healthy and functionally equivalent to its pre-replace out-of-band config, agent fleet reconnected, and the pip cache is confirmed active — live devpi-server access logs show real pip install traffic from a pipeline run hitting the cache (/root/pypi/+simple/... and /root/pypi/+f/... sub-second responses).

Timeline (all times UTC)

Impact

What went well

What didn't go well

Root cause analysis

Detection

Resolution

Action items

# Action Owner Due Issue
1 Add aws ecr get-login-password \| docker login to user_data_server.sh.tpl before the docker compose up step, so the boot script is self-sufficient and doesn't depend on undocumented out-of-band ECR auth sre-agent 2026-08-14 #4426
2 Document the standalone-replace procedure's full dependent-resource set in docs/ops/runbooks/ci-build-cache.md and/or ci-woodpecker.md — enumerate aws_lb_target_group_attachment.woodpecker_server and aws_launch_template.woodpecker_agent as required companion -targets (or switch to a non--target apply once the unrelated #4140 backlog is resolved) — runbook text already updated this pass, ticket tracks keeping it accurate sre-agent 2026-08-14 #4427
3 Add an explicit terraform apply -target=aws_launch_template.woodpecker_agent + aws autoscaling start-instance-refresh step to the standalone-replace runbook procedure, noting that ASG instance_refresh does not auto-trigger from a bare launch-template content update when version = "$Latest" — done this pass (see runbook §Standalone-replace path step 5) sre-agent 2026-08-14 #4427
4 Evaluate migrating agent server-discovery to the existing SSM-based mode (server_use_asg=true pattern already has this — /ci/woodpecker/server-host) even while server_use_asg=false, so future server replaces don't require an agent LT + instance-refresh dance at all operator 2026-08-21 #4428
5 Prefer a narrow, single-workflow pipeline trigger (or a direct pip install smoke test on an agent) for future cache/infra verification instead of a full manual trigger on develop, to avoid incidentally re-running the entire monorepo's deploy workflows sre-agent 2026-08-14 (documented here, no separate ticket — process note)

References