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¶
- Root dependencies and state names
- Ingress and HTTP routes
- Private networking and RDS access
- GKE configuration
- Cloud SQL and Private Service Access
- Thesis: PDF 29–30 and 49–55; printed 23–24 and 43–49. Thesis map.