Skip to content

Provisioning

How the code provisions a platform environment, from the build infrastructure to the last layer. The order is described in the platform deploy flow; this page explains each part.

Infra: the job runners

Step by step, including the state storage account and the service connections: Prepare pipelines and agents.

The infrastructure pipeline (stage-infrastructure.yaml → Invoke-XebiaInfrastructure) deploys the build infrastructure from src/Xebia.Mcp/Files/bicep/deploy/initialize/main.bicep into the subscription and resource group in mcp.json → Azure.JobRunner:

Resource Configured by (mcp.json)
Virtual network, subnets and NAT gateway Azure.JobRunner.IpAddressPrefixes (Vnet, AgentSubnet, PepSubnet, CaeSubnet, DnsResolverSubnet)
Azure Container Registry –
Managed DevOps Pool <AgentPool> AzureDevops.AgentPool, Azure.JobRunner.MaximumAgents, Azure.JobRunner.Sku
Container Apps environment (for container jobs, pool <AgentPool>-CTR) –
DNS resolver –

It also creates the blob container in the hub Terraform state storage account (Initialize-XebiaMcpTerraformStateContainer). The storage account itself, the spoke state container and the deployment service principals are prerequisites; no pipeline creates them.

In the reference configuration repository, infrastructure.yaml is CI-triggered on changes to itself or pipelines/variables.yaml, and runs canary and prod with sequential locking.

Container: the mcp image

The container pipeline (Invoke-XebiaContainer -Action Prepare|Build) builds src/Dockerfile from the pinned code version and pushes it to the job runner ACR. The image contains PowerShell 7, Terraform, the Azure CLI, the Xebia.Mcp module and the hub Terraform (copied from infra/ at build time). Image names come from AzureDevops.ContainerImageName (normally ["mcp"]).

Tags are set by Get-XebiaMcpContainerTags.ps1; see Releasing. The entry pipelines run on imageRef: mcp:latest.

Layers, per environment and region

The hub pipeline provisions the hub layers for one platform environment (one mcp.json) per stage:

  1. Environment. The platform environment name is the name of the folder that holds mcp.json, for example canary or prod. It is used in the state key and is passed to Terraform as config_path.
  2. Regions. The region matrix is built from <env-folder>/global.auto.tfvars (Get-XebiaRegion.ps1, Set-XebiaRegionMatrix.ps1):

    primary_region       = "weu"
    active_regions       = ["weu", "neu"]
    active_regions_names = ["westeurope", "northeurope"]
    

    primary_region must be in active_regions. Level 1 runs in the primary region, level 2 in the other regions, level 3 in all regions, and level 4 (postdeployment) in the primary region only. 3. Layers. For every layer and region, the module plans Terraform from terraform/cloud-platform/deploy/<layer> with the var files of that region and environment, and stores state in <env>-<region>-<layer>.tfstate. See Deployment layers.

flowchart TB
    mcp["environments/prod/mcp.json"] --> env["Environment = prod<br/>config_path = environments/prod"]
    env --> g["global.auto.tfvars<br/>primary_region, active_regions"]
    g --> r1["weu (primary)"]
    g --> r2["neu"]
    r1 --> l1["foundation, connectivity (level 1)"]
    r2 --> l2["foundation, connectivity (level 2)"]
    r1 --> l3["firewall, identity, management (level 3)"]
    r2 --> l3
    r1 --> l4["postdeployment (level 4)"]

Spokes

The spoke pipeline provisions spokes with the Terraform in src/Xebia.Mcp/Files/terraform/spoke-canvas/:

Step Terraform root State key
Subscription deploy/subscription <wl>_<env>_Subscription.tfstate
Spoke canvas deploy/spoke spoke_<wl>_<env>.tfstate

<wl> and <env> are the lower-cased workloadShortName and environment of the spoke JSON. See Spoke config.

The subscription step comes first, so that the spoke canvas always has a subscription to work in. It is a separate step on purpose, instead of a pool of free subscriptions: see Subscription provisioning. What the canvas step creates is described in Spoke canvas; its Terraform inputs and outputs are in the module reference.

Local provisioning

dev/dev.ps1 runs the same functions locally, in the dev container, against MCP_CONFIG (default config/Demo/canary/mcp.json). WhatIf is on unless you pass -SkipWhatIf.

pwsh ./dev/dev.ps1 -Action Test
pwsh ./dev/dev.ps1 -Action Infrastructure -SkipWhatIf
pwsh ./dev/dev.ps1 -Action Container -SkipTests

For hub layers and spokes, see Run a single layer locally; the dev.ps1 hub and spoke actions don't work on main yet (Known issues).