Building this site: a serverless portfolio on GCP
2026-09-29 · Harshit Singh
This site is my Cloud Resume Challenge build, and it's also the demo. The visitor counter at the bottom of the page is a live transaction against a real backend — here is how the whole thing works, and the decisions that shaped it.
The request path
The static site is served by Firebase Hosting (Google's edge CDN with managed TLS). The counter is a Rust (axum) API in a 9 MB distroless container on Cloud Run, which runs a Datastore transaction — begin, read, commit with retry on conflict — against Firestore in Datastore mode. No lost increments, even under parallel load; there's a 50-way concurrency test in the repo proving it.
Why no load balancer
The classic challenge architecture puts a GCS bucket behind a global
HTTPS load balancer with Cloud CDN. I built that first, then priced
it: the forwarding rule alone is about $18/month. Firebase Hosting
gives the same properties — global edge caching, managed certs,
custom domain — at $0 within the free tier. Same story, better
economics. Every significant choice like this is written down as an
ADR in the repo's notes/decisions.md.
Keyless CI/CD
No service-account JSON keys exist anywhere. GitHub Actions mints a
5-minute OIDC token per run, Google's Secure Token Service exchanges
it (repo-scoped trust condition), and the pipeline impersonates a
least-privilege CI service account. The runtime service account is
separate and holds exactly one role: datastore.user.
Failing unit tests block deploys; images deploy by digest, never by
mutable tag.
What I'd tell someone starting
- Write decisions down as you go — the ADR log is the best interview prep I have.
- Verify in a real browser, not just curl. Headless Chromium screenshots caught real issues.
- Put a billing budget on day one. "Should be free" is not a control.
- Google's front end reserves
/healthz. Yes, really.
Source: github.com/hxrsh159/cloud-resume-challenge. More posts as new projects land.