May 2026 · Part 4 of a 5-part series on migrating CI/CD from GitHub to Codeberg
The end-to-end execution window for the consolidated testing and delivery pipeline stabilized at 12–15 minutes, mirroring historical baseline performance metrics captured on GitHub Actions infrastructure. However, resource utilization efficiency scales differently under the self-hosted model.
| Processing Phase | Functional Step Block | Window Duration |
|---|---|---|
| Phase 1: Validation | lint-backend | ~3 min |
| Phase 1: Validation | test-backend (8 concurrent workers) | ~7 min |
| Phase 1: Validation | test-frontend | ~2 min |
| Phase 2: Compilation | build-backend | ~3 min |
| Phase 2: Compilation | build-frontend-staging | ~2 min |
| Phase 3: Delivery | deploy-staging | ~3 min |
The reallocation of compute resources altered execution performance during the validation phase. GitHub’s managed execution layer assigns 2 vCPUs to standard runners, limiting Python test parallelism (pytest -n auto) to 2 worker tasks.
By executing workloads on a dedicated GKE spot instance pool configured with e2-highcpu-8 machine types, the test harness detects 8 available vCPUs. It provisions 8 concurrent workers automatically, reducing the core backend validation window from ~20 minutes to 7 minutes without modification to the codebase test suite.
| Infrastructure Component | Managed Service (GitHub Actions) | Self-Hosted Model (Forgejo on GKE) |
|---|---|---|
| CI Runner Compute | Metered per-minute consumption rates | ~$3.00 / month (Spot instances + Scale-to-Zero) |
| Container Registry | GHCR (Bundled service layer) | Google Artifact Registry (~$0.10 / GB) |
| Resource Allocation | 2 vCPU per runner instance | 8 vCPU Spot instance allocations (~$0.01 / hr) |
| Debug Time | Hours lost proving it's not your fault | kubectl logs, done in minutes |
| Cold-Start Latency | Non-existent (Subject to queue scheduling) | ~2–3 minutes (Compute scaling from zero nodes) |
| Total Monthly Spend | Variable based on developer utilization | ~$3.00 / month ($0.00 during idle windows) |
Operating efficiency is sustained by enforcing scale-to-zero configurations. When the webhook message broker reports no active pipeline runs, the GKE spot node pool releases all compute resources, reducing baseline expenditures to zero.
Under standard developer workloads (averaging 10–20 pushes per working day), total compute costs settle at approximately $3.00 per month. This structure introduces a 2-to-3 minute cold-start delay while the cloud infrastructure provisions nodes for cold pipeline requests. This trade-off remains highly efficient compared to maintaining persistent, idle computing overhead.
Standard Service Level Agreements (SLAs) fail to account for the velocity of the engineering debugging loop when an infrastructure dependency fails.
| Reliability Metric | Managed Service (GitHub Actions) | Self-Hosted Model (Forgejo on GKE) |
|---|---|---|
| Infrastructure Availability | 99.5% – 99.9% (Provider reported values) | 99.95% GKE Nodes, 99.99% Cloud SQL Engine |
| Status Dashboard Veracity | Displays “Operational” during partial outages | Absolute visibility; failures match system logs |
| Mean Time to Repair (MTTR) | Ticket submission to external support queues | Direct access via kubectl logs; immediate fixes |
| Task Queueing Overheads | Variable delays based on multi-tenant load | Deterministic allocation via private spot nodes |
| Webhook Delivery Assurances | Unacknowledged dropped payloads | Direct delivery control or manual execution options |
During historical outages where GitHub’s internal routing engines failed while their external status indicators remained green, root-cause isolation was blocked. Engineering teams routinely lose hours troubleshooting internal service logic, rotated access keys, or base layer container configurations before identifying the issue as an external provider outage.
Operating private infrastructure contracts this verification cycle to minutes. Querying the cluster daemon (kubectl logs) exposes runner errors directly. This migration path provides systemic visibility, eliminating dependency on third-party availability metrics during late-night deployment windows.
postgresql:// connection strings containing special characters) on day one. Isolating the double-base64 transformation quirk late in the integration phase creates significant troubleshooting delays.Teams evaluating a similar migration path should observe the following guidelines:
The architectural transition yields predictable processing timelines, decreases execution dependencies, and introduces a 10x cost reduction while expanding runtime infrastructure visibility.