> For the complete documentation index, see [llms.txt](https://host2host.onibonje.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://host2host.onibonje.com/docs/19-cloud-agnostic-deployment.md).

# Cloud-Agnostic & Deployment-Agnostic Architecture

## 1. Overview

The H2H platform is designed for **deployment agnosticism**: the **same composable JAR modules** run on **modern cloud-native infrastructure** and on **legacy bank data-centre platforms** — without forking application code.

| Profile                          | Target                                                                      | Typical bank context                         |
| -------------------------------- | --------------------------------------------------------------------------- | -------------------------------------------- |
| **A — Kubernetes** (recommended) | OCI containers on EKS, AKS, GKE, OpenShift, Rancher                         | Greenfield, cloud-first, multi-region        |
| **B — Standalone JVM**           | Spring Boot executable JAR on Linux/Windows VM (`systemd`, Windows Service) | On-prem DC without container platform        |
| **C — Legacy app server**        | WAR on WebLogic, WebSphere, JBoss EAP                                       | Existing enterprise Java operations model    |
| **D — Hybrid**                   | Profile B/C runtime near Finacle + Profile A admin in cloud                 | Core banking on-prem, control plane in cloud |

**Principle:** Abstract infrastructure behind **standard JDBC**, **S3-compatible APIs**, **Kafka protocol**, **Vault API**, and **OpenTelemetry** — never embed cloud-vendor SDKs in business logic. **Containers are optional**, not mandatory.

```mermaid
flowchart TB
  subgraph app [Application Layer - Same JARs All Profiles]
    Runtime[h2h-runtime]
    Admin[h2h-admin-api]
    UI[Admin UI]
  end

  subgraph modern [Profile A - Kubernetes]
    K8s[K8s / OpenShift]
    Helm[Helm Charts]
    Docker[OCI Images]
  end

  subgraph legacy [Profiles B and C - Legacy DC]
    VM[VM + systemd / Windows Service]
    WAS[WebLogic / WebSphere / JBoss]
    FatJar[Spring Boot executable JAR]
  end

  subgraph abstractions [Infrastructure Abstractions]
    JDBC[JDBC Database]
    KafkaAPI[Kafka Protocol]
    S3API[S3-Compatible Storage]
    VaultAPI[Vault API]
    OTelAPI[OTLP Telemetry]
  end

  app --> modern
  app --> legacy
  modern --> abstractions
  legacy --> abstractions
```

***

## 2. Deployment Principles

| Principle                                  | Implementation                                                                |
| ------------------------------------------ | ----------------------------------------------------------------------------- |
| **Same JARs, multiple packaging profiles** | Executable JAR, WAR, or OCI image from one codebase                           |
| 12-factor config                           | All config via env vars, JNDI, or external property files — no secrets in JAR |
| Infrastructure as Code                     | Terraform + Helm (Profile A); Ansible/scripts (Profiles B/C)                  |
| No cloud SDK in app code                   | S3 API, JDBC, Kafka protocol abstractions                                     |
| Portable observability                     | OpenTelemetry OTLP exporters — any backend                                    |
| Legacy coexistence                         | WAR deployment for banks without Kubernetes                                   |
| Hybrid support                             | On-prem CBS + cloud gateway; or on-prem full stack                            |
| Finacle proximity                          | Profile B/C co-locate runtime with core banking LAN                           |

***

## 2.1 Packaging profiles (Maven)

| Profile              | Artifact                                | Deploy target                         |
| -------------------- | --------------------------------------- | ------------------------------------- |
| `boot-jar` (default) | `h2h-runtime-{version}.jar`             | `java -jar`, systemd, Windows Service |
| `war`                | `h2h-runtime-{version}.war`             | WebLogic, WebSphere, JBoss EAP        |
| `docker`             | OCI image `heirs-h2h/runtime:{version}` | Kubernetes / OpenShift                |

Admin API and dispatcher modules follow the same pattern. **Docker is one packaging option**, not a runtime requirement.

### Profile B — Standalone JVM (legacy VM)

```bash
# Linux systemd example
java -jar h2h-runtime.jar \
  --spring.config.additional-location=file:/etc/h2h/application.yml
```

| Aspect          | Approach                                                  |
| --------------- | --------------------------------------------------------- |
| Process manager | systemd unit, Windows Service, IBM SCM                    |
| Config          | `/etc/h2h/` or bank-standard config directory             |
| Logs            | JSON to file → bank log aggregator (Splunk, ELK)          |
| Health          | `http://localhost:8080/actuator/health` for load balancer |
| Scaling         | Active/passive pair behind hardware LB, or vertical scale |

### Profile C — Legacy application server (WAR)

| Server                  | Notes                                                                  |
| ----------------------- | ---------------------------------------------------------------------- |
| **Oracle WebLogic**     | Deploy `h2h-runtime.war`; datasource via JNDI; exclude embedded Tomcat |
| **IBM WebSphere**       | Same pattern; bind JDBC and JMS via cell-scoped resources              |
| **JBoss EAP / WildFly** | `jboss-deployment-structure.xml`; datasource in standalone.xml         |

Spring Boot `SpringBootServletInitializer` entry point; **same route and CBS JARs** as container deployment.

***

## 2.2 When to choose each profile

| Situation                                       | Recommended profile                     |
| ----------------------------------------------- | --------------------------------------- |
| New cloud or OpenShift rollout                  | **A — Kubernetes**                      |
| Bank DC with no container platform              | **B — Standalone JAR**                  |
| Mandate to use existing WebLogic/WebSphere farm | **C — WAR**                             |
| Finacle on isolated LAN, admin in cloud         | **D — Hybrid** (B/C runtime + A admin)  |
| MVP pilot, fastest path                         | **B** on single VM near Finacle sandbox |

***

## 3. Deployment Topology

### 3.1 Standard Kubernetes Layout

```
Namespace: h2h-production
├── Deployment: h2h-runtime          (3+ replicas, HPA)
├── Deployment: h2h-admin-api        (2 replicas)
├── Deployment: h2h-admin-ui         (2 replicas)
├── Deployment: h2h-webhook-dispatcher (2 replicas)
├── StatefulSet: kafka               (or managed Kafka external)
├── StatefulSet: postgresql          (or managed DB external)
├── Deployment: vault-agent-injector
├── Deployment: otel-collector
├── Ingress: h2h-api                 (partner API)
├── Ingress: h2h-admin               (internal admin)
└── NetworkPolicy: deny-all-default
```

### 3.2 Multi-Region Layout

See [Multi-Country Deployment](/docs/07-multi-country-deployment.md) for regional assignment. Each region is an independent Kubernetes cluster with the same Helm chart and region-specific values.

***

## 4. Container Images

### 4.1 Image List

| Image                 | Base                                      | Dockerfile                 |
| --------------------- | ----------------------------------------- | -------------------------- |
| `heirs-h2h/runtime`   | `eclipse-temurin:21-jre-alpine`           | `h2h-runtime/Dockerfile`   |
| `heirs-h2h/admin-api` | `eclipse-temurin:21-jre-alpine`           | `h2h-admin-api/Dockerfile` |
| `heirs-h2h/admin-ui`  | `node:20-alpine` (build) → `nginx:alpine` | `h2h-admin-ui/Dockerfile`  |

### 4.2 Runtime Image Standards

| Requirement          | Implementation                                              |
| -------------------- | ----------------------------------------------------------- |
| Non-root user        | `USER 1000`                                                 |
| Read-only filesystem | `readOnlyRootFilesystem: true` + emptyDir mounts            |
| No secrets in image  | Vault agent injection at runtime                            |
| Health endpoints     | `/actuator/health/liveness`, `/actuator/health/readiness`   |
| Graceful shutdown    | `terminationGracePeriodSeconds: 60`, Camel shutdown timeout |
| Image signing        | Cosign signatures in CI                                     |

***

## 5. Helm Chart Structure

```
helm/h2h-platform/
├── Chart.yaml
├── values.yaml                    # Defaults
├── values-aws-eks.yaml
├── values-azure-aks.yaml
├── values-gcp-gke.yaml
├── values-onprem-openshift.yaml
├── templates/
│   ├── runtime/
│   │   ├── deployment.yaml
│   │   ├── service.yaml
│   │   ├── hpa.yaml
│   │   └── pdb.yaml
│   ├── admin/
│   │   ├── admin-api-deployment.yaml
│   │   └── admin-ui-deployment.yaml
│   ├── ingress.yaml
│   ├── networkpolicy.yaml
│   ├── serviceaccount.yaml
│   ├── configmap.yaml
│   ├── secret-provider-class.yaml   # Vault / CSI secrets
│   ├── otel-collector.yaml
│   └── servicemonitor.yaml          # Prometheus Operator
└── charts/                          # Sub-charts (optional)
    ├── kafka/                       # Strimzi or disable if managed
    └── postgresql/                  # Or disable if managed
```

### 5.1 Install Examples

```bash
# AWS EKS
helm upgrade --install h2h ./helm/h2h-platform \
  -f helm/h2h-platform/values.yaml \
  -f helm/h2h-platform/values-aws-eks.yaml \
  --namespace h2h-production

# On-prem OpenShift
helm upgrade --install h2h ./helm/h2h-platform \
  -f helm/h2h-platform/values.yaml \
  -f helm/h2h-platform/values-onprem-openshift.yaml \
  --namespace h2h-production
```

***

## 6. Cloud Provider Mapping

### 6.1 Managed Services Matrix

| Capability     | AWS                           | Azure                            | GCP                           | On-Prem                     |
| -------------- | ----------------------------- | -------------------------------- | ----------------------------- | --------------------------- |
| Kubernetes     | EKS                           | AKS                              | GKE                           | OpenShift / RKE2            |
| Database       | RDS PostgreSQL                | Azure Database for PostgreSQL    | Cloud SQL PostgreSQL          | PostgreSQL HA               |
| Object storage | S3                            | Azure Blob (S3 API gateway)      | GCS (S3 interop)              | MinIO                       |
| Kafka          | MSK                           | Event Hubs (Kafka protocol)      | Confluent Cloud               | Strimzi on K8s              |
| Secrets        | Vault on EKS / AWS SM + Vault | Vault on AKS / Key Vault + Vault | Vault on GKE / Secret Manager | HashiCorp Vault             |
| Load balancer  | ALB Ingress Controller        | Azure Application Gateway        | GCE Ingress                   | MetalLB / HAProxy           |
| TLS certs      | cert-manager + ACM            | cert-manager + Key Vault         | cert-manager + GCP CAS        | cert-manager + internal CA  |
| DNS            | Route 53                      | Azure DNS                        | Cloud DNS                     | Internal DNS                |
| Observability  | AMP + ADOT                    | Azure Monitor + OTel             | Cloud Monitoring + OTel       | Prometheus + Grafana on K8s |

### 6.2 Application Configuration per Cloud

Only **infrastructure values** change — application JARs are identical:

```yaml
# values-aws-eks.yaml
global:
  cloud: aws
database:
  host: h2h-config.xxxx.af-south-1.rds.amazonaws.com
  vendor: postgresql
storage:
  type: s3
  endpoint: https://s3.af-south-1.amazonaws.com
  bucket: h2h-files-prod
kafka:
  bootstrapServers: b-1.h2h-msk.af-south-1.amazonaws.com:9092
vault:
  address: https://vault.bank.internal
observability:
  otelEndpoint: http://otel-collector:4317
```

```yaml
# values-onprem-openshift.yaml
global:
  cloud: onprem
database:
  host: postgresql.h2h-infra.svc.cluster.local
  vendor: postgresql
storage:
  type: s3
  endpoint: https://minio.h2h-infra.svc.cluster.local
  bucket: h2h-files
kafka:
  bootstrapServers: h2h-kafka-bootstrap.h2h-infra.svc.cluster.local:9092
vault:
  address: https://vault.h2h-infra.svc.cluster.local:8200
```

***

## 7. Infrastructure as Code (Terraform)

### 7.1 Module Layout

```
terraform/
├── modules/
│   ├── kubernetes/          # EKS / AKS / GKE abstraction
│   ├── database/            # RDS / Azure DB / Cloud SQL
│   ├── storage/             # S3 / Blob / GCS bucket
│   ├── kafka/               # MSK / Event Hubs / Strimzi
│   ├── vault/               # Vault cluster
│   └── networking/          # VPC, subnets, security groups
├── environments/
│   ├── aws-prod/
│   ├── azure-prod/
│   └── onprem-prod/
└── README.md
```

### 7.2 Environment Pattern

Each environment directory:

```
terraform/environments/aws-prod/
├── main.tf
├── variables.tf
├── terraform.tfvars
├── backend.tf              # S3 state backend
└── outputs.tf              # Values fed to Helm
```

Terraform **provisions infrastructure**; Helm **deploys application**. CI pipeline connects them:

```
Terraform apply → output DB host, bucket name → Helm upgrade with values
```

***

## 8. Secrets Management (Cloud Agnostic)

### 8.1 Vault on Kubernetes

HashiCorp Vault is the **primary secrets store** on all clouds:

| Pattern                   | Description                               |
| ------------------------- | ----------------------------------------- |
| Vault Agent Injector      | Sidecar injects secrets as files/env vars |
| CSI Secret Store Driver   | Mount secrets as volumes                  |
| External Secrets Operator | Sync Vault → K8s Secret (optional)        |

**Application code** uses `VaultClient` from `h2h-security` — unaware of injection mechanism.

### 8.2 Kubernetes Secrets Policy

| Rule                                   | Rationale                   |
| -------------------------------------- | --------------------------- |
| No secrets in ConfigMap                | Security                    |
| No secrets in Helm values files in Git | Use Vault references only   |
| Rotate via Vault                       | No pod rebuild for rotation |

***

## 9. Networking

### 9.1 Network Topology

```mermaid
flowchart TB
  Internet --> WAF[WAF / DDoS]
  WAF --> Ingress[Ingress Controller]
  Ingress --> GW[API Gateway Pod]
  Ingress --> SFTP[SFTP Gateway Pod]
  GW --> Runtime[h2h-runtime]
  SFTP --> Runtime
  Runtime --> Finacle[Finacle - core banking zone]
  Runtime --> DB[(Database)]
  Runtime --> Kafka[Kafka]
  Admin[Admin UI] --> AdminAPI[Admin API]
  AdminAPI --> DB
```

### 9.2 Network Policies

| Policy             | Rule                                         |
| ------------------ | -------------------------------------------- |
| `runtime-ingress`  | Accept from gateway namespace only           |
| `runtime-egress`   | Allow Finacle, DB, Kafka, Vault, S3 endpoint |
| `admin-ingress`    | Internal network / VPN only                  |
| `deny-all-default` | Default deny inter-namespace                 |

### 9.3 Service Mesh (Optional)

Istio or Linkerd for mTLS between pods — same config on all clouds.

***

## 10. Storage (Cloud Agnostic)

File management uses **S3-compatible API** only (see [File Management System](/docs/15-file-management-system.md)):

| Cloud  | Endpoint config                                       |
| ------ | ----------------------------------------------------- |
| AWS S3 | `https://s3.{region}.amazonaws.com`                   |
| MinIO  | `https://minio.internal:9000`                         |
| Azure  | Blob S3 gateway or native adapter via `FileStore` SPI |
| GCS    | S3 interop endpoint or `GcsFileStore`                 |

Switch storage by changing Helm values — no code change.

***

## 11. Database (Cloud Agnostic)

Persistence SPI supports PostgreSQL, Oracle, SQL Server (see [Extensibility Framework](/docs/14-extensibility-framework.md)):

```yaml
database:
  vendor: postgresql    # postgresql | oracle | sqlserver
  host: ${DB_HOST}
  port: ${DB_PORT:5432}
  name: h2h_config
  credentialsRef: vault:secret/db/h2h-runtime
```

Managed or self-hosted — application sees JDBC URL only.

***

## 12. CI/CD Pipeline (Cloud Neutral)

```mermaid
flowchart LR
  Code[Git Push] --> CI[GitHub Actions / Jenkins]
  CI --> Build[Maven + Docker Build]
  Build --> Scan[Trivy + SonarQube]
  Scan --> Push[Container Registry]
  Push --> Deploy{Target}
  Deploy --> EKS[EKS Helm Upgrade]
  Deploy --> AKS[AKS Helm Upgrade]
  Deploy --> OnPrem[OpenShift Helm Upgrade]
```

### 12.1 Container Registry

Same image pushed to:

* AWS ECR
* Azure ACR
* GCP Artifact Registry
* On-prem Harbor

Image tag: `{version}` + `{git-sha}` — immutable.

### 12.2 Deployment Strategy

| Strategy       | Use                          |
| -------------- | ---------------------------- |
| Rolling update | Default for runtime          |
| Blue/green     | Major version upgrades       |
| Canary         | Optional via Flagger / Istio |

```yaml
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1
    maxUnavailable: 0
```

***

## 13. Observability Deployment

OpenTelemetry Collector deployed as DaemonSet or sidecar — same on all clouds.

```yaml
# otel-collector-config.yaml
exporters:
  otlp:
    endpoint: ${OTEL_BACKEND}
  prometheus:
    endpoint: 0.0.0.0:8889

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
```

See [Monitoring and Logging](/docs/17-monitoring-and-logging.md).

***

## 14. High Availability

| Component     | HA approach                               |
| ------------- | ----------------------------------------- |
| `h2h-runtime` | 3+ replicas, HPA, PDB `minAvailable: 2`   |
| PostgreSQL    | Managed multi-AZ or Patroni cluster       |
| Kafka         | 3 brokers, replication factor 3           |
| Vault         | HA cluster (3+ nodes)                     |
| MinIO / S3    | Native cloud HA or MinIO distributed mode |
| Ingress       | Multiple controller replicas              |

**RTO target:** < 15 minutes\
**RPO target:** < 1 minute (Kafka + DB replication)

***

## 15. Environment Matrix

| Environment  | Cluster                 | Purpose             |
| ------------ | ----------------------- | ------------------- |
| `dev`        | Shared dev cluster      | Developer testing   |
| `sandbox`    | Isolated namespace      | Partner onboarding  |
| `uat`        | UAT cluster             | Business acceptance |
| `staging`    | Pre-prod cluster        | Release validation  |
| `production` | Prod cluster per region | Live traffic        |

Each environment: separate namespace, Vault namespace, DB schema, Kafka topic prefix.

***

## 16. Hybrid Deployment Model

Common pattern for African banking:

| Component       | Location            | Rationale                |
| --------------- | ------------------- | ------------------------ |
| Finacle         | On-prem data center | Core banking policy      |
| H2H runtime     | On-prem or cloud    | Near Finacle for latency |
| SFTP gateway    | DMZ on-prem         | Partner file exchange    |
| API gateway     | Cloud               | Public API scalability   |
| Admin portal    | Cloud or on-prem    | Internal access          |
| Archive storage | Cloud (S3)          | Cost-effective retention |
| Observability   | Cloud or on-prem    | Bank preference          |

Same Helm chart — different `values-hybrid.yaml`.

***

## 17. Disaster Recovery

| Scenario        | Procedure                                         |
| --------------- | ------------------------------------------------- |
| Pod failure     | K8s auto-restart                                  |
| AZ failure      | Multi-AZ replicas                                 |
| Region failure  | Failover to secondary region (DNS + Kafka mirror) |
| Cluster failure | Restore from Terraform + Helm to DR cluster       |
| DB failure      | Promote read replica / restore from backup        |

**DR drill:** Quarterly automated failover test to secondary region.

***

## 18. Local Development

```bash
# Start local infrastructure
docker-compose up -d    # PostgreSQL, Kafka, MinIO, Vault, Mock Finacle

# Run runtime locally
cd h2h-runtime && mvn spring-boot:run -Dspring-boot.run.profiles=local
```

`docker-compose.yml` mirrors production services — no cloud dependency for development.

***

## 19. Deployment Checklist

| Step | Action                                            |
| ---- | ------------------------------------------------- |
| 1    | Terraform provision cluster + managed services    |
| 2    | Install cert-manager, ingress, Vault              |
| 3    | Configure Vault policies and secrets              |
| 4    | Run Flyway migrations against config DB           |
| 5    | Helm install with environment values              |
| 6    | Import country pack configuration                 |
| 7    | Configure Finacle endpoints and test connectivity |
| 8    | Onboard pilot partner in sandbox                  |
| 9    | Verify observability dashboards                   |
| 10   | Penetration test and go-live approval             |

***

## 20. Related Documents

* [Multi-Country Deployment](/docs/07-multi-country-deployment.md) — regional topology
* [Technology Stack](/docs/02-technology-stack.md) — component choices
* [Repository Structure](/docs/11-repository-structure.md) — Helm and Docker paths
* [File Management System](/docs/15-file-management-system.md) — S3-compatible storage
* [Security Library](/docs/16-security-library.md) — Vault on Kubernetes
* [Monitoring and Logging](/docs/17-monitoring-and-logging.md) — OTel deployment
* [Implementation Roadmap](/docs/10-implementation-roadmap.md) — phased rollout


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://host2host.onibonje.com/docs/19-cloud-agnostic-deployment.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
