Skip to main content

DEPLOYMENT_TOPOLOGY — pricing-service

Sibling: OBSERVABILITY · SECURITY_MODEL · FAILURE_MODES

Strategic anchors: 02 §12 Deployment · ADR-0001 Core stack

The pricing-service is a stateless Node.js (NestJS, TypeScript) workload deployed on GCP. It runs as a containerised service on Cloud Run for the public/admin HTTP surface and as a separate deployment on GKE Autopilot for long-running consumers (Pub/Sub pull subscribers, outbox relay, cron). Both surfaces share the same image with different entrypoints. We never run on a non-GCP cloud and we never run pricing data in serverless edge runtimes (state proximity matters too much).


1. Environments

EnvRegionProjectPurpose
devme-central2melmastoon-devshared developer environment
stagingme-central2melmastoon-stagingrelease-candidate, full data shape
prodme-central2 (primary) + europe-west4 (DR read replica)melmastoon-prodlive
localn/an/adocker-compose; see LOCAL_DEV_SETUP

Each environment has its own Cloud SQL instance, Memorystore, Pub/Sub topics, and KMS keyring. No cross-env access.


2. Topology

┌─────────────────────────┐
│ Cloud Armor + GCLB │
└────────────┬────────────┘
│ TLS 1.3
┌────────────▼────────────┐
│ API Gateway (Apigee) │ → JWT validation, rate-limit, X-Tenant-Id
└────┬─────────────┬──────┘
┌──────────────▼─────┐ ┌────▼────────────────────┐
│ pricing-public │ │ pricing-admin │ Cloud Run services
│ (Cloud Run, scale │ │ (Cloud Run, scale 1-20) │
│ 2-200, vCPU 2, │ │ vCPU 1, mem 1 Gi) │
│ mem 2 Gi) │ │ │
└────────┬───────────┘ └────────┬────────────────┘
│ │
│ mTLS (workload identity)
│ │
▼ ▼
┌────────────────────────────────────────┐
│ Cloud SQL Postgres 16 HA (regional) │
│ schemas: pricing, pricing_quote │
└────────────────────────────────────────┘
▲ ▲
│ │
┌────────┴───────────────────────┴────────┐
│ Memorystore Redis 7 (HA) │
└────────────────────────────────────────┘


┌────────┴────────────────────────────────┐
│ GKE Autopilot — pricing-workers ns: │
│ • outbox-relay (Pub/Sub publisher) │
│ • inbox-consumer (4 subscriptions) │
│ • quote-expiry-cron (every 5 m) │
│ • fx-refresh-cron (hourly) │
│ • dynamic-suggestion-batch (nightly) │
└─────────────────────────────────────────┘


┌────────┴────────────┐
│ Pub/Sub topics: │
│ melmastoon.pricing.*│
└─────────────────────┘

Internal service-mesh: GKE Anthos Service Mesh (Istio); Cloud Run services participate via Cloud Run + ASM integration. mTLS is STRICT mesh-wide.


3. Container image

  • Base: gcr.io/distroless/nodejs20-debian12
  • Built via Cloud Build, signed with Binary Authorization (Sigstore cosign).
  • SBOM (CycloneDX) generated and attached on every build.
  • Multi-arch: linux/amd64 only (Cloud Run + GKE Autopilot are amd64).
  • Image size target: < 180 MB compressed.

Two entrypoints in the image:

ENTRYPOINT ["node", "dist/main.js"]
# CMD selectable via env: SERVICE_ROLE = http | worker

4. Cloud Run services

pricing-public (handles /v1/pricing/* and /internal/v1/quotes:*)

SettingValue
Min instances2
Max instances200
Concurrency per instance80
CPU2 vCPU (always allocated)
Memory2 Gi
Timeout10 s
Ingressinternal+lb (gateway only)
VPC connectoryes (to reach Cloud SQL via Private IP, Memorystore, AI orchestrator)
Service accountpricing-public@melmastoon-prod.iam.gserviceaccount.com
Startup CPU boostenabled
Health probesstartup /v1/livez, liveness /v1/livez, readiness /v1/readyz

pricing-admin (handles /v1/admin/*)

SettingValue
Min instances1
Max instances20
Concurrency40
CPU1 vCPU
Memory1 Gi

5. GKE Autopilot — pricing-workers namespace

WorkloadReplicasCPU reqMem reqNotes
outbox-relay3250 m512 Mileader-elects via Postgres advisory lock; only one active publisher per shard
inbox-consumer4500 m1 Gieach replica subscribes to all 4 inbox subscriptions; Pub/Sub handles fan-out
quote-expiry-cron1250 m512 MiCronJob */5 * * * *
fx-refresh-cron1250 m512 MiCronJob 5 * * * * (hourly, offset 5 m)
dynamic-suggestion-batch1500 m1 GiCronJob 0 2 * * * (02:00 me-central2)

All workloads use Workload Identity bound to the pricing-workers@… Google service account.


6. Data plane

ComponentSpec
Cloud SQL Postgres 16db-custom-8-32768 (8 vCPU, 32 Gi) primary; HA enabled; 2 read replicas in me-central2; cross-region read replica in europe-west4 for DR
Memorystore Redis 7Standard tier, 5 Gi, HA, AUTH enabled
Pub/Subper-aggregate topics (see EVENT_SCHEMAS); CMEK enabled; per-topic DLQ subscription
GCSbucket gs://melmastoon-prod-pricing-events/ for BigQuery sink staging; lifecycle rule: delete after 90 d
BigQuerydataset melmastoon_prod.pricing for event mirror + analytics
Cloud KMSkeyring melmastoon-prod-pricing with keys db, redis, pubsub, gcs; auto-rotation 365 d

7. Networking

  • VPC melmastoon-prod-vpc, subnet me-central2-pricing-subnet (10.40.16.0/20).
  • Cloud SQL via Private IP only; no public IP.
  • Memorystore reachable only inside VPC.
  • Egress to AI orchestrator over private service connect.
  • Egress to FX provider through a NAT with a static IP, allow-listed by the provider.
  • Cloud Armor policy pricing-edge with WAF rules: SQLi, XSS, generic header validation, geo-allow AF, TJ, IR, AE, QA, SA, OM, KW, EU, US (admin only).

8. CI/CD

  • GitHub Actions in melmastoon/platform-monorepo, workflow services/pricing-service/.github/workflows/ci.yml.
  • Path filter: any change under services/pricing-service/** or packages/pricing-engine/**.
  • Stages: lint → typecheck → unit → property → integration → contracts → openapi-conformance → image-build → trivy-scan → push → terraform-plan → cloud-deploy.
  • Promotion: dev (auto on merge to main), staging (auto with smoke tests), prod (manual approval after 24h staging soak).
  • Rollback: Cloud Run revision rollback in < 30 s; GKE workers rollback via kubectl rollout undo.

9. Disaster recovery

AssetRPORTOStrategy
Cloud SQL primary5 m15 mCross-region read replica + automated promotion runbook
Pub/Sub0 (in-region replicated)n/aMulti-zone by default
Application image05 mMulti-region Artifact Registry mirror
Configuration05 mTerraform state in GCS bucket with versioning
KMS keys0n/aMulti-region keyrings

Quarterly DR drill executes the failover runbook against staging.