Skip to main content

Azure

Azure DEV is the shared cloud environment for the lean Grinea stack. It runs the Procurement Web App, the API gateway, and the core backend services on AKS, with managed Azure services for storage, databases, secrets, container images, DNS, and public ingress.

The environment is split into two ownership layers. Terraform owns Azure resources. Kubernetes owns the workloads that run inside the cluster. GitHub Actions builds images, pushes them to ACR, applies manifests, and runs the deployment checks.

The Grinea web app is accessible at https://app.grinea-demo.embiggenx.com.

Architecture

Public traffic enters through Azure DNS records for app.grinea-demo.embiggenx.com and api.grinea-demo.embiggenx.com. Both records point to the static public IP used by the AKS ingress controller.

The app host routes to procurement-web-app. The API host routes to api-gateway-service. Backend services stay private inside the cluster and communicate through Kubernetes service DNS.

Resource Layer

Terraform manages the Azure DEV resource layer in the rg-grinea-embiggen-dev resource group.

The main Azure resources are:

ResourcePurpose
AKSRuns the web app, API gateway, and backend services.
Azure Container RegistryStores deployment images built by GitHub Actions.
Key VaultStores runtime secrets used by the Kubernetes workloads.
Azure PostgreSQLStores relational service data for auth, users, RBAC, and projects.
Cosmos DB Mongo APIStores BOM service data.
Azure Cache for RedisProvides shared cache infrastructure for services that need it.
Storage accountHolds Terraform remote state and application storage such as uploads.
Azure DNSOwns the grinea-demo.embiggenx.com DEV zone and public records.
Static public IPGives ingress a stable address for app and api.

Terraform should be treated as the source of truth for Azure resources, DNS records, and the ingress public IP. Avoid changing these manually in the Azure Portal unless the change is also imported or codified afterward.

Workload Layer

Kubernetes manifests define what runs inside AKS.

The current DEV workload set is intentionally small:

WorkloadRole
procurement-web-appInternal Grinea frontend.
api-gateway-servicePublic API entry point for the web app.
auth-serviceAuthentication service.
user-serviceUser data and user-related operations.
rbac-serviceRole and permission checks.
project-serviceProject profile data.
bill-of-materials-serviceBOM data and BOM workflow integration.

Non-secret runtime values live in the Kubernetes ConfigMap. Secrets are read from Key Vault during deployment and written into the grinea-runtime-secrets Kubernetes secret.

Deployment Flow

terraform-azure-dev validates and applies Azure infrastructure changes. deploy-azure-dev deploys application changes to AKS.

The deploy workflow checks that the static ingress IP and DNS records already exist before it deploys. If those checks fail, apply the Terraform stack first. This prevents a deployment from succeeding inside AKS while the public app and API hosts still point nowhere useful.

Public Endpoints

The DEV environment exposes two main public endpoints:

EndpointWhat it serves
https://app.grinea-demo.embiggenx.comProcurement Web App
https://api.grinea-demo.embiggenx.comAPI Gateway

TLS is handled through ingress configuration that references the letsencrypt-prod cert-manager issuer. The issuer must exist in the cluster before certificates can be issued.

The docs site runs as a small nginx workload in AKS. grinea-docs builds into a static Docusaurus site, is packaged as the grinea-docs image in ACR, and is exposed at https://docs.grinea-demo.embiggenx.com.

Source Of Truth

Use the right layer for the change:

ChangeSource of truth
Azure resource, DNS record, managed database, public IPTerraform
Deployment, Kubernetes service, ingress route, runtime ConfigMapKubernetes manifests
Runtime secret valueAzure Key Vault
Image build and rollout processGitHub Actions
Product documentation siteDocs image, AKS docs deployment, and docs ingress

When adding a service to Azure DEV, it needs more than a Docker image. The service needs an ACR image, Kubernetes deployment and service, non-secret config, Key Vault secret mapping, database ownership if needed, health checks, and a gateway route if it is reachable through the public API.

Common Surprises

Ingress returning 404 at / does not always mean the cluster is broken. The public routes depend on host headers for app and api.

If the public app does not load after a deploy, check DNS and the static ingress IP before debugging the web app.

If a pod starts but cannot connect to a database or dependency, check grinea-runtime-config and grinea-runtime-secrets before changing code.

If Terraform wants to recreate a resource that already exists, import the resource into state before applying. Azure DEV includes resources that were originally created manually.