Deployment en omgevingen¶
Deze pagina legt uit hoe de portal is opgebouwd, hoe een omgeving wordt beschreven en hoe een wijziging productie bereikt. Ze beschrijft het referentieontwerp: pipelines, repositorylayout en namen kunnen in jouw deployment afwijken. Volg voor de eerste deployment van een omgeving Een klant onboarden.
Overzicht¶
flowchart LR
pr[Pull request] --> lint[Lint and<br/>Terraform tests]
lint --> build[Build image once<br/>no Azure credential]
build --> r1[Ring 1<br/>plan, approve, apply]
r1 --> r2[Ring 2]
r2 --> r3[Ring 3]
| Principe | Detail |
|---|---|
| Eén keer bouwen, vaak deployen | Per run wordt één container image gebouwd en naar de registry van elke omgeving gepusht. De buildjob heeft geen Azure-credential. |
| Eén Terraform root per omgeving | Elke klant en omgeving heeft een eigen main.tf, zodat een wijziging voor de ene klant een andere niet per ongeluk kan aanpassen. |
| Het plan wordt ongewijzigd toegepast | Het plan dat is gemaakt en getoond, is het plan dat wordt toegepast. Het wordt niet opnieuw berekend tijdens het toepassen. |
| Configuratie in een bestand | De gegevens van een omgeving zijn rijen in één JSON-bestand, geen pipelinevariabelen. |
Terraform roots¶
infra/
modules/ shared modules
platform/ado private connections from the provider network
platform/pagerduty shared escalation policy and schedule
<customer>/<env>/ one root per environment
De gedeelde modules:
| Module | Maakt aan |
|---|---|
backstage |
Web app met staging slot, identities, private endpoints, PostgreSQL, role assignments |
postgresql |
PostgreSQL Flexible Server 16 |
key_vault |
Key Vault met RBAC, purge protection, geen publieke toegang |
container_registry |
Premium registry, geen publieke toegang |
azure_monitor |
Application Insights en Log Analytics |
tenant_configuration |
Secrets van de tenant in Key Vault |
cost_insights |
Data Factory, storage, Data Lake, Azure SQL (Cost insights setup) |
foundry_platform |
Azure AI Foundry account, project, modeldeployments (AI setup) |
pagerduty |
Service, afhankelijkheid en Azure Monitor action group |
landing_zone_spoke_canvas |
Alleen data: leest de bestaande resource group, VNet, subnets, Key Vault en Log Analytics van de spoke |
Een typische omgevingsroot combineert: spoke canvas, naming, resource group, App Service plan, Key Vault, een secret voor het MCP-token, container registry, Azure Monitor, tenantconfiguratie, backstage, foundry_platform en pagerduty. De root geeft de app settings van de web app door: APP_CONFIG_organization_name, feature flags, het modelendpoint, het MCP-token en optionele instellingen voor integraties en de module registry. Zie Configuratie.
Bronnen van gedeelde modules
Sommige omgevingsroots verwijzen naar gedeelde modules uit een registry of repository buiten deze codebase. De bron beschrijft dat mechanisme niet, dus bevestig bij de provider waar die modules vandaan komen.
Het omgevingenbestand¶
Elke omgeving is één rij in infra/customer-environments.json. Een schema valideert het bestand zodra een pull request wordt geopend, dus een ontbrekend veld faalt vóór de merge.
| Veld | Betekenis |
|---|---|
owner, environment |
Naam van klant en omgeving (acc, prod) |
deploymentEnvironment |
Naam van het GitHub Environment, <owner>_<env> |
ring |
Deployvolgorde |
enabled |
Sla de rij over als dit false is |
terraform.directory |
Pad van de root van de omgeving |
terraform.backend |
Resource group, storage account en container (standaard tfstate) van de state |
terraform.backstageClientSecretName |
Naam van het repository secret met de Terraform client secret |
terraform.appSecretNames |
Namen van optionele app-secrets (GitHub App) |
azure.clientId, tenantId, subscriptionId |
Identity en subscription voor plan en apply |
azure.clientSecretName |
Alleen voor de terugval op een client secret |
azure.useDeployEnvironmentForPlan |
Koppel het GitHub Environment aan de planjob |
backstage.containerRegistry |
Login server van de registry |
backstage.appService.name, resourceGroup |
De web app |
Voorbeeldrij (placeholders):
{
"owner": "<customer>",
"environment": "acc",
"deploymentEnvironment": "<customer>_acc",
"ring": 2,
"terraform": {
"directory": "infra/<customer>/acc",
"backstageClientSecretName": "BACKSTAGE_CLIENT_SECRET_<CUSTOMER>_ACC",
"backend": {
"resourceGroup": "<backend-resource-group>",
"storageAccount": "<backend-storage-account>"
}
},
"azure": {
"clientId": "<client-id>",
"tenantId": "<tenant-id>",
"subscriptionId": "<subscription-id>"
},
"backstage": {
"containerRegistry": "<registry>.azurecr.io",
"appService": { "name": "<web-app-name>", "resourceGroup": "<resource-group>" }
}
}
Uitrol in rings¶
Omgevingen worden in genummerde rings gedeployd. Ring N start pas als ring N-1 als geheel is afgerond: als één omgeving in een ring faalt, start de volgende ring niet. Dit is een veiligheidspoort voor de hele ring en geen isolatie per klant. De ring van elke omgeving staat in het veld ring, dus controleer het bestand voor de actuele indeling.
Voor elke omgeving in een ring doet de pipeline het volgende:
- Maakt een Terraform plan en een leesbare samenvatting, standaard zonder GitHub Environment.
- Wacht bij de poort van het GitHub Environment.
- Past het opgeslagen plan toe.
- Deployt de portal, als de run dat bevat (Slot swap).
Elke omgeving heeft bovendien een eigen concurrency slot voor de hele deployment, zodat twee runs niet tegelijk dezelfde Terraform state kunnen wijzigen. De pipeline vergelijkt geen branches of commits, dus een engineer kan bewust een branch of een oudere commit deployen, bijvoorbeeld voor een rollback.
Pipelines¶
| Workflow | Doel |
|---|---|
| CI/CD (push naar main) | Lint, Terraform tests, build, daarna ring 1, 2 en 3 met infrastructuur en portal |
| Dispatch | Handmatige run. Inputs: deploy_to (ring 1, 2 of 3), run_lint, deploy_infra, build_and_deploy_backstage |
| Terraform plan | Maakt plannen voor gewijzigde roots op pull requests en voor elke omgeving aan het begin van haar ring |
| Deploy environment | Past het opgeslagen plan toe en deployt optioneel de portal |
| Platform private connections | Plant op pull requests, past toe bij een merge |
| Platform alerting | Past het gedeelde escalation policy en schedule toe |
De run heeft een timeout van 210 minuten, omdat het aanmaken van een Foundry account meer dan twee uur kan duren.
Environment gate¶
Het GitHub Environment dat in deploymentEnvironment staat, bevat de goedkeuring. Acceptatie heeft normaal geen reviewers; productie vereist goedkeuring door het platformteam. De planjob gebruikt het environment niet, tenzij azure.useDeployEnvironmentForPlan true is, zodat het leesbare plan bestaat voordat iemand goedkeurt.
Slot swap¶
De portal wordt gedeployd via het staging slot van de web app:
- Push de image naar de registry van de omgeving.
- Start het staging slot.
- Zet de container image op het slot.
- Preview swap.
- Smoke test: het readiness-endpoint geeft 200 terug en een responseheader
x-build-idis gelijk aan de run-ID. Timeout 600 seconden. - Bij succes: swap. Bij een fout: reset de swap.
- Stop het staging slot.
Authenticatie naar Azure¶
Plan en apply authenticeren met OIDC via een federated credential op een app registration in de doeltenant. Er wordt geen Azure-secret in GitHub opgeslagen.
| Federated credential | Subject |
|---|---|
| Pull requests | repo:<owner-id>/<repo-id>:pull_request |
| Main branch | repo:<owner-id>/<repo-id>:ref:refs/heads/main |
| Elke omgeving | repo:<owner-id>/<repo-id>:environment:<owner>_<env> |
Alle hebben audience api://AzureADTokenExchange. De issuer is de OIDC-issuer van de GitHub Enterprise-tenant die de repository host. Die verschilt van de publieke GitHub-issuer, dus kopieer hem niet uit generieke voorbeelden. Het subject gebruikt de onveranderlijke owner- en repository-ID's, zodat een hernoeming of overdracht de credentials niet breekt.
| Secret | Gebruik |
|---|---|
BACKSTAGE_CLIENT_SECRET_<OWNER>_<ENV> |
Repository secret met de client secret van de app registration van de portal, doorgegeven aan Terraform. Het moet een repository secret zijn, omdat het plan zonder GitHub Environment draait. |
GH_APP_* |
Optionele GitHub App-waarden, benoemd in appSecretNames, aan Terraform doorgegeven als var.app_secrets en opgeslagen in Key Vault, waarnaar de app settings verwijzen |
AZURE_CLIENT_SECRET_<OWNER>_<ENV> |
Alleen als er geen federated credential kan worden aangemaakt. Een laatste redmiddel: een langlevend secret dat je handmatig roteert. |
Plan en apply delen één identity
De federated credential per omgeving scheidt de planfase nog niet van de applyfase, omdat beide dezelfde identity gebruiken. Het besluitenlog noemt dit als openstaand risico (Decisions).
De portal bijwerken¶
Een wijziging in de code gaat via een pull request en daarna door de rings. Een configuratiewijziging voor één klant is een wijziging in diens app-config.<customer>.yaml of in de app settings in diens Terraform root. Zie Configuratie. Er worden geen klantspecifieke codewijzigingen gedaan.