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:
| Resource | Purpose |
|---|---|
| AKS | Runs the web app, API gateway, and backend services. |
| Azure Container Registry | Stores deployment images built by GitHub Actions. |
| Key Vault | Stores runtime secrets used by the Kubernetes workloads. |
| Azure PostgreSQL | Stores relational service data for auth, users, RBAC, and projects. |
| Cosmos DB Mongo API | Stores BOM service data. |
| Azure Cache for Redis | Provides shared cache infrastructure for services that need it. |
| Storage account | Holds Terraform remote state and application storage such as uploads. |
| Azure DNS | Owns the grinea-demo.embiggenx.com DEV zone and public records. |
| Static public IP | Gives 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:
| Workload | Role |
|---|---|
procurement-web-app | Internal Grinea frontend. |
api-gateway-service | Public API entry point for the web app. |
auth-service | Authentication service. |
user-service | User data and user-related operations. |
rbac-service | Role and permission checks. |
project-service | Project profile data. |
bill-of-materials-service | BOM 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:
| Endpoint | What it serves |
|---|---|
https://app.grinea-demo.embiggenx.com | Procurement Web App |
https://api.grinea-demo.embiggenx.com | API 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:
| Change | Source of truth |
|---|---|
| Azure resource, DNS record, managed database, public IP | Terraform |
| Deployment, Kubernetes service, ingress route, runtime ConfigMap | Kubernetes manifests |
| Runtime secret value | Azure Key Vault |
| Image build and rollout process | GitHub Actions |
| Product documentation site | Docs 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.