Skip to content

Architecture

The system has two flows coordinated from GitLab: one provisions and configures infrastructure; the other delivers an application version onto that infrastructure. Deployment repositories preserve image references, while OpenTofu states preserve the relationship between configuration and cloud resources.

Responsibilities and control

flowchart TB
  source["Application repositories"] --> ci["Application pipeline"]
  templates["Shared templates"] --> ci
  ci --> registry["Container Registry"]
  ci --> manifests["Versioned manifests"]
  manifests --> apply["Deploy job"]
  apply --> agent["GitLab Agent and selected cluster"]
  infra["OpenTofu pipeline"] --> cloud["Infrastructure and platform"]
  infra <--> state["HTTP states in GitLab"]
  cloud --> agent

The application pipeline produces an image and updates a manifest repository. It then applies the repository contents through a context provided by GitLab Agent. DEPLOY_TARGET=eks|gke selects the context. This is CI-initiated delivery; the reviewed code contains no continuous reconciler that periodically reapplies Git or independently corrects manual cluster changes.

The infrastructure pipeline comprises network, kubernetes, database and platform. Each root has its own remote state and consumes outputs from other roots when needed. platform creates the application namespace, database secret and agent; on AWS it also installs the load balancer controller.

AWS runtime

flowchart TB
  client["HTTPS client"] --> alb["Public ALB"]
  alb --> web["Web Service and frontend"]
  alb --> rest["Rest Service and API"]
  rest --> db["Private RDS MySQL"]
  web -. "Same-origin API" .-> rest
  nodes["Private EKS nodes"] --> nat["NAT Gateway"]
  nat --> external["Registry and external services"]

The frontend Ingress routes /api/v1 to rest:8080 and / to web:8080, using ingressClassName: alb. The JavaScript client calls the API under the same origin; the diagram's functional relationship does not imply that the frontend server acts as a proxy. It declares HTTP/HTTPS listeners, an HTTPS redirect and an existing ACM certificate. The historical DNS name and certificate reference must be adapted to the destination; this manifest does not establish that the DNS record or certificate is provisioned.

EKS and RDS use private subnets. The VPC has three private and three public subnets, with a NAT Gateway for egress. The RDS ingress rule allows MySQL from the EKS node security group. RDS has no public address and explicitly sets multi_az = false.

The node group has minimum, maximum and desired sizes. This does not establish that a load-driven node-scaling controller has been installed: neither Cluster Autoscaler nor Karpenter appears in the reviewed resources. AWS covers the details and implications.

GCP runtime

flowchart TB
  web["Web Service and frontend"] --> api["Rest Service and API"]
  api --> private["Private Service Access"]
  private --> sql["Private Cloud SQL MySQL"]
  nodes["Private GKE nodes"] --> nat["Cloud NAT and Cloud Router"]
  nat --> external["Registry and external services"]
  network["VPC and secondary ranges"] --> nodes

The VPC is global and contains regional subnets. GKE uses VPC-native networking and secondary pod and Service ranges. Its nodes are private; the management endpoint is configured separately and defaults to public access. Cloud NAT provides node egress, and Cloud SQL uses a private connection with ipv4_enabled = false.

The diagram represents dependencies and internal connectivity. The versioned Ingress does not establish HTTP exposure on GKE: it selects AWS's ALB controller and references ACM. The GCP platform code does not install a controller compatible with that manifest. Reproducing external access on GKE requires destination-specific configuration or the external configuration originally used by the author. See GCP.

Contracts between components

Contract Producer Consumer Operating condition
Registry/branch:SHA image Each application's build web or rest Deployment The image exists and is downloadable
rest secret platform root Backend through envFrom Credentials and endpoint match the provisioned database
registry secret Additional environment configuration Both Deployments Referenced, but not created by the reviewed resources
…:eks-agent or …:gke-agent context GitLab Agent and CI permissions deploy job Connected agent and authorised access
State outputs Earlier IaC roots terraform_remote_state Matching provider/environment and read permissions
Manifests on main update-k8s-manifests deploy job A token with actual repository read/write capability

Namespaces and Service names match across clouds, but accounts, networks and databases remain independent. Kubernetes compatibility does not remove provider-specific ingress, IAM, storage or networking requirements.

Architectural boundaries

There is no cross-cloud MySQL replication, global load balancing, automatic regional recovery or transactional deployment of both services. Frontend and backend projects have independent pipelines and promote their images separately.

ENVIRONMENT distinguishes state names and pipeline concurrency groups; it does not automatically propagate to every cloud resource name or tag, several of which retain fixed development values. Different state prefixes do not guarantee isolated infrastructure. The state guide explains this boundary.

Sources