Infrastructure: Amazon EKS

Kubernetes cluster layout, event-driven autoscaling with KEDA, and GitOps deployment with ArgoCD.


Table of Contents

  1. 10.1 EKS Cluster Layout
  2. 10.2 KEDA — Event-Driven Worker Autoscaling
    1. Why This Matters for Client Onboarding
  3. 10.3 GitOps Deployment (ArgoCD)
  4. 10.4 anchita-cli — Platform Operations CLI (Go)
  5. 10.5 Distributed Tracing & Observability

10.1 EKS Cluster Layout

EKS Cluster: platform-cluster

├── namespace: temporal
│   ├── temporal-frontend         (Deployment, 2 replicas)
│   ├── temporal-history          (Deployment, 3 replicas)
│   ├── temporal-matching         (Deployment, 2 replicas)
│   └── temporal-web-ui           (Deployment, 1 replica)

├── namespace: platform
│   ├── graphql-bff               (Deployment, 2 replicas, HPA 2–8)
│   ├── rest-api                  (Deployment, 2 replicas, HPA 2–6)
│   ├── case-service              (Deployment, 2 replicas)
│   ├── workflow-service          (Deployment, 2 replicas)
│   ├── document-service          (Deployment, 2 replicas)
│   ├── notification-service      (Deployment, 1 replica)
│   ├── audit-service             (Deployment, 2 replicas)
│   └── metrics-service           (Deployment, 1 replica)

├── namespace: workers
│   ├── onboarding-worker         (Deployment, KEDA-scaled 2–20)
│   ├── compliance-worker         (Deployment, KEDA-scaled 1–10)
│   ├── product-worker            (Deployment, KEDA-scaled 2–30)
│   └── integration-worker        (Deployment, KEDA-scaled 2–20)

├── namespace: agents
│   └── agent-service             (Deployment, GPU node pool, 1–4 replicas)

└── namespace: integration
    ├── core-banking-adapter      (Deployment, 2 replicas)
    ├── treasury-platform-adapter (Deployment, 2 replicas)
    ├── digital-banking-adapter   (Deployment, 2 replicas)
    └── [remaining adapters]

Namespace strategy: Each layer of the architecture has its own Kubernetes namespace, with NetworkPolicy restricting cross-namespace traffic to explicitly declared service dependencies. The temporal namespace is completely isolated from the integration namespace — Temporal workers communicate with integration adapters through the integration layer, not directly.


10.2 KEDA — Event-Driven Worker Autoscaling

Temporal Workers scale based on task queue depth using KEDA (Kubernetes Event-Driven Autoscaling). This is the key advantage of EKS over ECS for this system — workers scale based on actual work to be done, not CPU utilisation:

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: product-worker-scaler
  namespace: workers
spec:
  scaleTargetRef:
    name: product-provisioning-worker
  minReplicaCount: 2
  maxReplicaCount: 30
  triggers:
    - type: prometheus
      metadata:
        serverAddress: http://prometheus:9090
        metricName: temporal_task_queue_depth
        query: temporal_workflow_task_queue_size{task_queue="product-provisioning"}
        threshold: "5"   # scale up when > 5 tasks per worker

Why This Matters for Client Onboarding

During peak onboarding periods (when many Enterprise clients are activated in parallel), the product provisioning workers scale from 2 to 30 replicas automatically as the product workflow queue fills.

Long-running activation wait as a durable timer: Rather than blocking a worker thread, Anchita models the activation wait as a Temporal sleep() timer:

// WireDomesticWorkflow.java
Duration activationWindow = config.wireActivationWindow();  // configured per environment
Workflow.sleep(activationWindow);  // durable timer — no worker consumed
activateWireAccount(caseId);

No worker pod is consumed during the wait. The Temporal server persists the timer and re-schedules the activity when it fires. KEDA scales the worker pods down during quiet periods and back up when the timers fire.


10.3 GitOps Deployment (ArgoCD)

GitHub repo: platform/k8s-manifests
└── apps/
    ├── temporal/           (Helm chart values)
    ├── platform/           (Spring Boot Helm charts)
    ├── workers/            (Worker Helm charts + KEDA ScaledObjects)
    └── agents/             (agent service Helm chart)

ArgoCD watches this repo → auto-syncs to EKS on merge to main

Deployment pipeline:

Developer PR → GitHub Actions CI (build + test + Docker image push to ECR)
  → Merge to main → ArgoCD detects Helm chart change
    → ArgoCD syncs to EKS → rolling deployment (zero-downtime)
      → ArgoCD health checks → deployment marked healthy or rolled back

Service mesh: AWS App Mesh (Envoy) provides mTLS between all services within the cluster. No service-to-service traffic is unencrypted. Traffic management policies control retry budgets and circuit breakers at the mesh level (complementing the Resilience4j circuit breakers in the Spring Boot adapters).


10.4 anchita-cli — Platform Operations CLI (Go)

anchita-cli is a Go binary distributed to platform engineers, DevOps teams, and on-call operators. It communicates directly with the Anchita REST API — no direct database or Temporal access.

# Case management
anchita cases list --segment=ENTERPRISE --status=COMPLIANCE --limit=20
anchita cases show CASE-2026-042
anchita cases search --company="Acme Corp"

# Workflow operations
anchita workflow status CASE-2026-042
anchita workflow signal CASE-2026-042 --signal=submitErrorRecovery --action=RETRY
anchita workflow history CASE-2026-042

# Platform health
anchita workers status
anchita workers queues --task-queue=product-provisioning

# Admin
anchita admin product-catalog list
anchita admin product-catalog show WIRE_DOMESTIC

Distributed as a single static binary — brew install anchita-cli or download from the GitHub releases page. No JVM, no Python installation required. Platform teams on macOS, Linux, and Windows all use the same tool built from one Go codebase with GOOS cross-compilation.

This follows the same pattern as kubectl, helm, argocd, and the temporal CLI itself — all Go, all single binaries, all standard in the cloud-native ecosystem.


10.5 Distributed Tracing & Observability

A single money movement crosses the API gateway, the Temporal workflow, one or more activities, the ledger, and an external rail adapter — often with an asynchronous gap (a durable timer, an ACH return window) in the middle. Without a correlation thread, debugging a stuck transfer means grepping five services by timestamp. Anchita makes every hop traceable end to end using OpenTelemetry with W3C Trace Context.

[ Client UI / Mobile ]
        │  HTTP POST  (traceparent + X-Correlation-ID)
        ▼
[ Spring Boot API Gateway / GraphQL BFF ]      ← generates or accepts the W3C traceparent
        │  trace context injected
        ▼
[ Temporal Workflow ]                          ← context carried in workflow headers
        │  header propagation (survives replay and timers)
        ▼
[ Temporal Activity Workers ] ──► [ PostgreSQL Ledger / Outbox ]
        │  W3C trace header on every outbound call
        ▼
[ Partner-Bank Integration Adapters ]
  • Ingress — the gateway generates a traceparent (or adopts the caller’s) and attaches an X-Correlation-ID that stays human-readable in logs.
  • Across the async boundary — Temporal propagates the trace context in workflow and activity headers via its OpenTelemetry interceptor, so a span started at intake still joins the trace when a durable timer fires hours later. This is the hard part generic tracing guides skip: the workflow and the activity that resumes it are different executions, and the context must survive the gap.
  • Egress and sink — activities propagate the W3C header to the ledger and to partner-bank adapters; spans, metrics, and structured JSON logs export through an OpenTelemetry Collector to Prometheus / Grafana (and CloudWatch / X-Ray on AWS). The same temporal_task_queue_depth signal that drives KEDA autoscaling is one of these metrics.

The result: one trace ID ties the operator’s click, the workflow, every ledger posting, and the external dispatch into a single timeline — the observability bar expected of a high-scale financial platform.


↑ Back to top

Anchita Banking — Fictional Reference Architecture for Cloud-Native Institutional Banking