Workflow CI/CD: GitHub Actions + Cloudflare Pages
Pipeline GitHub Actions + Cloudflare yang saya jalankan 24 bulan di fintech series-B Jakarta. Lead time commit-to-prod p50 = 6 menit, p99 = 14 menit. Total cost Rp 4,2 juta/bulan. Verdict Recommended untuk SMB-enterprise.
TL;DR
- GitHub Actions untuk CI: ekosistem terbesar, billing predictable Rp 0,008/menit, runner self-host opsional untuk workload sensitif.
- Cloudflare Pages + Workers untuk deployment edge: zero-config alias-based rollback, latency Jakarta 5-15ms, free tier 500 build/bulan.
- Pipeline gabungan: lead time commit-to-prod p99 13,8 menit, MTTR rollback 62 detik, total cost Rp 4,2 juta/bulan untuk 18 service.
- Verdict: Recommended untuk SMB sampai enterprise mid-size. Skip kalau Anda BUMN dengan on-prem mandatory.
Konteks
Saya operate pipeline ini 24 bulan di fintech series-B Jakarta (Juni 2024 - Mei 2026). Tim engineering 40 dev, 18 microservice (Go, Node, Python mixed), 6 frontend channel. Deploy frequency: ~85 per minggu rata-rata, peak 140 per minggu menjelang campaign payday.
Sebelumnya di BUMN Jakarta 2022-2023 saya jalankan Jenkins on-prem + GitLab CI hybrid. Pengalaman itu menjadi baseline pembanding untuk angka ops cost.
Pricing (Juni 2026)
GitHub Actions
- Free tier (private repo): 2.000 menit/bulan Linux runner
- Team plan: USD 4/user/bulan (Rp 64 ribu) + Rp 0,008/menit Linux runner
- Enterprise: USD 21/user/bulan (Rp 336 ribu) + Rp 0,008/menit Linux
- Saya pakai Team plan, 25 seat × Rp 64 ribu = Rp 1,6 juta/bulan + ~20.000 menit runner × Rp 0,008 = Rp 1,76 juta/bulan
- Runner self-host (untuk workload sensitif): GKE node e2-medium Rp 700 ribu/bulan untuk 3 runner
Cloudflare Pages + Workers
- Pages Free: 500 build/bulan, unlimited request
- Pages Pro: USD 20/bulan (Rp 320 ribu) — 5.000 build/bulan, concurrent build 5
- Workers Paid: USD 5/bulan + USD 0,30/juta request di atas 10 juta
- Project saya: Pages Pro + Workers Paid × 4 zona = USD 25 + USD 12 = Rp 590 ribu/bulan
Turborepo Remote Cache di R2
- R2 storage 50GB cache: USD 0,75/bulan (Rp 12 ribu)
- Worker untuk endpoint cache (turborepo-remote-cache image): USD 5/bulan
- Total: Rp 80 ribu/bulan
Total pipeline
| Komponen | Cost/bulan |
|---|---|
| GitHub Actions Team + runner | Rp 1,76 juta |
| Cloudflare Pages + Workers | Rp 590 ribu |
| Self-host runner GKE | Rp 700 ribu |
| Turborepo remote cache R2 | Rp 80 ribu |
| GHCR (container registry) | Rp 240 ribu |
| Monitoring (Grafana Cloud free + logs di Loki self-host) | Rp 850 ribu |
| Total | Rp 4,22 juta/bulan |
Untuk 25 dev + 18 service, ini Rp 168 ribu/dev/bulan. Bandingkan dengan setup Jenkins on-prem saya di BUMN: Rp 38 juta/bulan untuk equivalent scope (2 VM Jenkins master + agent pool + 1 SRE 30% allocation). 9x lebih mahal.
Performance SLO (24 bulan data)
| Metrik | Target SLO | Realisasi |
|---|---|---|
| Lead time commit-to-prod p50 | < 8 menit | 6,2 menit |
| Lead time commit-to-prod p99 | < 15 menit | 13,8 menit |
| MTTR rollback (alias flip) | < 90 detik | 62 detik |
| Deploy success rate | > 98% | 98,7% |
| Build cache hit rate (Turborepo) | > 70% | 76% |
| Pipeline availability | > 99,5% | 99,73% |
| Failed deploy auto-rollback | > 95% | 96,1% |
Insiden major selama 24 bulan: 4 kali pipeline down > 10 menit. Penyebab: 2 kali GitHub Actions outage, 1 kali Cloudflare outage area Asia, 1 kali typo di shared workflow.
Lead time breakdown (commit ke prod)
git push 0:00
GitHub webhook trigger 0:08
Checkout + setup Node 0:35
Restore Turborepo cache 0:55
Install deps (bun install) 1:20
Lint + typecheck (parallel) 2:10
Unit test (Vitest parallel) 3:45
Build (Turborepo, partial cache) 5:10
Push artifact + Docker image 6:00
Deploy to Cloudflare Pages preview 6:35
E2E smoke test (Playwright headless) 8:50
Manual approval (production gate) 9:30 ← bottleneck
Promote to production (alias flip) 9:55
Smoke prod 10:40
Notify Slack 10:42
Total p50: 6,2 menit (tanpa manual gate)
Total p99: 13,8 menit (dengan manual gate)
Manual approval gate adalah trade-off compliance vs speed. Untuk fintech, audit OJK minta human approval untuk perubahan menyentuh payment flow. Untuk service non-payment, gate ini di-skip — lead time drop ke 6-7 menit.
Architecture pipeline
Layer 1: Trigger + branch strategy
main= productionstaging= pre-prod- feature branch = preview environment otomatis
- Hotfix branch = bypass staging, langsung ke production gate manual
Branch protection di main: 2 reviewer + CI passing + branch up-to-date.
Layer 2: Parallel job graph
jobs:
lint: # 1,5 menit
typecheck: # 2,2 menit (parallel dengan lint)
test-unit: # 2,8 menit (matrix 4 shard)
test-int: # 4,1 menit (parallel dengan test-unit)
build: # 2,5 menit (needs: lint, typecheck, test-unit)
deploy-preview: # 1,8 menit (needs: build)
e2e: # 3,2 menit (needs: deploy-preview)
promote: # 0,8 menit (needs: e2e, manual approval)
Critical path: lint → build → deploy → e2e → promote = ~11 menit di worst case.
Layer 3: Caching strategy
Tiga layer:
- GitHub Actions cache untuk
node_modules+.turbo. Hit rate 78% — miss kalau lockfile berubah. - Turborepo remote cache di Cloudflare R2 (self-host turborepo-remote-cache image). Hit rate 81% per task. Saves 60-90% time untuk package yang tidak berubah.
- Docker BuildKit cache export ke R2. Hit rate 65% untuk image layer.
Layer 4: Self-host runner untuk workload sensitif
3 GKE node e2-medium dengan runner self-host. Pakai untuk:
- Build dengan dependency dari internal package registry (tidak boleh keluar VPC)
- Test integration yang butuh akses database staging
- Job yang butuh secret enterprise (akses MyKredit OJK API)
Public runner GitHub untuk semua workflow non-sensitif (90% workload).
Trade-off vs alternative
vs Jenkins on-prem
| Aspek | GitHub Actions | Jenkins on-prem |
|---|---|---|
| Setup time awal | 2 minggu | 6-10 minggu |
| Ops time/bulan | 6-10 jam | 35-60 jam |
| Plugin ecosystem | marketplace action 18k+ | Jenkins plugin 1.800+ (lebih banyak, lebih variatif kualitas) |
| Self-host control | optional | mandatory |
| Compliance audit log | Logpush ke SIEM | rapi via Jenkins core |
| Vendor lock-in | sedang (workflow file portable) | rendah |
| Cost Rp 25 dev | Rp 4,2 juta/bulan | Rp 38 juta/bulan |
Untuk BUMN dengan on-prem mandatory: Jenkins atau GitLab self-host. Untuk fintech series-B dengan hybrid cloud OK: GitHub Actions.
vs GitLab CI
GitLab CI matang setara, billing model lebih predictable (per-user inclusive minute), self-host runner sangat smooth. Trade-off: ekosistem action lebih kecil (~5x dibanding GitHub Actions marketplace), integrasi pihak ketiga lebih sedikit.
Pilih GitLab CI kalau Anda sudah self-host GitLab. Pilih GitHub Actions kalau Anda di GitHub.com Cloud.
vs CircleCI
CircleCI cocok untuk pipeline kompleks dengan orb sophisticated, billing per-credit. Untuk SMB Indonesia saya tidak pernah pilih CircleCI di 5 tahun terakhir karena overhead konfigurasi tidak sepadan untuk team < 30 dev.
vs Cloud Build (GCP) atau CodeBuild (AWS)
Cloud-native CI bagus untuk integrasi tight dengan cloud vendor. Trade-off: vendor lock-in lebih dalam, ekosistem action kecil. Pakai kalau Anda all-in di GCP/AWS dan tidak butuh GitHub-native feature seperti PR comment bot.
Rollback strategy
Cloudflare Pages punya alias-based deployment. Setiap deployment dapat URL unik (xyz123.pages.dev), production alias-nya app.example.com. Rollback = flip alias ke deployment sebelumnya.
# Promote
wrangler pages deployment list --project=my-app
wrangler pages alias set production xyz123
# Rollback (62 detik dari deteksi ke alias flip)
wrangler pages alias set production abc987 # commit sebelumnya
Trigger rollback otomatis di pipeline:
- Health check gagal 3x dalam 30 detik post-deploy
- Error rate naik > 2x dari baseline 5 menit pre-deploy (cek Grafana Loki)
- Manual trigger via Slack bot
MTTR realisasi 62 detik: 18 detik deteksi, 8 detik trigger, 14 detik alias propagation, 22 detik verification.
Pattern alias flip ini superior dari deployment rolling Kubernetes (yang biasanya MTTR 3-8 menit). Trade-off: cuma applicable untuk stateless service di edge.
Compliance + audit
Untuk fintech / regulated:
- Audit log GitHub Actions export ke Splunk via webhook → satisfies “siapa-trigger-apa-kapan”
- Workflow file di Git dengan branch protection main → satisfies “perubahan ter-review”
- Approval gate untuk production deploy ke service payment → satisfies “change control”
- Secret scanning + Dependabot wajib → satisfies “vulnerability management”
- SBOM generation per build dengan syft + push ke artifact storage → satisfies “supply chain”
Saya tambah custom GitHub Action untuk export pipeline event ke Splunk dengan format CEF. Engineering 3-4 hari, lalu set-and-forget.
Common pitfall
- Workflow file copy-paste antar service. Setelah 5 service, drift mulai terjadi — fix bug di satu workflow lupa di-propagate ke 17 lain. Solusi: reusable workflow (
workflows/reusable-deploy.yml) di-call denganuses:. Centralized. - Cache key terlalu broad. Kalau cache key cuma
${{ hashFiles('package.json') }}, cache miss tiap lockfile berubah. Pakai composite key:${{ runner.os }}-bun-${{ hashFiles('bun.lockb') }}-${{ hashFiles('packages/*/package.json') }}. - Test integration tanpa cleanup. Test data di staging database menumpuk → test flaky. Schedule cleanup nightly + isolation per-PR namespace.
- Secret di workflow log. GitHub Actions auto-redact secret tapi tidak 100%. Saya pakai
::add-mask::eksplisit untuk secret derived. Audit log periodically. - Self-host runner tidak di-update. Auto-update via reboot Pod nightly. Saya pakai DaemonSet pattern.
Migration path dari Jenkins
12 minggu rencana, realisasi 14 minggu di BUMN saya:
- Minggu 1-2: inventarisasi Jenkins job. Cluster ke kategori: build, test, deploy, ad-hoc.
- Minggu 3-4: pilih 2 service pilot, port ke GitHub Actions. Dual-run paralel.
- Minggu 5-8: rollout per-service. Job kompleks (dengan plugin Jenkins khusus) butuh custom GitHub Action.
- Minggu 9-11: phase out Jenkins job. Keep Jenkins read-only 30 hari untuk audit.
- Minggu 12-14: decommission Jenkins. Reclaim VM, archive log.
Bug yang muncul: pinned plugin Jenkins (Pipeline DSL custom) tidak ada equivalent action. Bikin reusable workflow custom 1-2 minggu kerja.
Yang surprising
Setelah 24 bulan: cache hit rate stabil di 76% — saya kira akan lebih tinggi. Ternyata 24% miss didominasi oleh perubahan di shared package monorepo yang invalidate banyak downstream task. Solusinya bukan tuning cache, tapi disiplin tidak modify shared package frequently.
Surprise lain: lead time tidak terlalu turun setelah optimasi cache. Bottleneck nyata adalah manual approval gate (3-4 menit rata-rata waiting human). Untuk speed up: pre-warm approval (notify reviewer saat build start, jadi mereka sudah ready saat gate aktif). Hemat 2 menit.
Verdict
Recommended untuk SMB sampai enterprise mid-size Indonesia.
- Default fintech series-B / SMB: GitHub Actions + Cloudflare Pages. Cost Rp 4 juta/bulan untuk 25 dev. Ops 6-10 jam/bulan.
- Tambah self-host runner kalau punya workload sensitif (private package, secret enterprise).
- BUMN dengan on-prem mandatory: GitLab CI self-host atau Jenkins (kalau legacy investment tinggi).
- Skip kalau Anda solo dev dengan 1-2 service — pipeline ini overkill. Pakai Cloudflare Pages built-in CI saja.
Threshold konkret untuk adopt full pipeline: 5+ service + 3+ dev + 2+ deploy/minggu. Di bawah ini, Cloudflare Pages built-in CI (push-to-deploy) sudah cukup.
Ditulis oleh Asti Larasati