Module können nicht über Repository-Grenzen wiederverwendet werden? Eine Bicep-Registry veröffentlichen

Veröffentlicht am:

Der CloudTrips-Speicher-Wrapper ist innerhalb dieses Repositorys wiederverwendbar, aber ein anderes Repository kann ./modules/storage.bicep nicht referenzieren. Das Kopieren der Datei erzeugt getrennte Versionen, die auseinanderlaufen, Korrekturen zu unterschiedlichen Zeitpunkten erhalten und keinen gemeinsamen Eigentümer mehr haben.

Veröffentliche den Wrapper in einer privaten Bicep-Registry. Eine Bicep-Registry ist eine Azure Container Registry (ACR), die kompilierte Bicep-Module als versionierte OCI-Artefakte speichert. Andere Repositorys können eine genehmigte Version abrufen, ohne den Quellcode zu kopieren.

Diese Registry unterscheidet sich von der öffentlichen Registry der Azure Verified Modules: AVM enthält von Microsoft gepflegte Module, während die private Registry CloudTrips-Module und -Konventionen enthält.

Dieser Trip baut auf folgendem Trip auf: Azure Verified Modules verwenden. Schließe ihn zuerst ab, da dieses Lab den dort entstandenen CloudTrips-Storage-Wrapper versioniert veröffentlicht.

Registry-Infrastruktur erstellen

Die Registry benötigt eine gemeinsame Ressourcengruppe und eine ACR. Erstelle in cloudtrips-bicep/registry/registry.bicep die Ressourcengruppe und rufe ein Modul mit Ressourcengruppen-Gültigkeitsbereich auf:

targetScope = 'subscription'

param location string = deployment().location
param resourceGroupName string = 'rg-cloudtrips-bicep-registry-weu'
param registryName string = 'crctbicep${uniqueString(subscription().id)}'

var commonTags = {
  Application: 'CloudTrips'
  Environment: 'Shared'
  ManagedBy: 'Bicep'
  Purpose: 'BicepModuleRegistry'
}

resource registryResourceGroup 'Microsoft.Resources/resourceGroups@2025-04-01' = {
  name: resourceGroupName
  location: location
  tags: commonTags
}

module moduleRegistry './registry-resource.bicep' = {
  name: '${deployment().name}-registry'
  scope: registryResourceGroup
  params: {
    location: location
    registryName: registryName
    tags: commonTags
  }
}

output registryId string = moduleRegistry.outputs.registryId
output registryName string = moduleRegistry.outputs.registryName
output registryLoginServer string = moduleRegistry.outputs.registryLoginServer
output storageModuleTarget string = 'br:${moduleRegistry.outputs.registryLoginServer}/bicep/modules/storage-account:1.0.0'

Erstelle cloudtrips-bicep/registry/registry-resource.bicep:

param location string = resourceGroup().location
param registryName string
param tags object = {}

resource moduleRegistry 'Microsoft.ContainerRegistry/registries@2025-11-01' = {
  name: registryName
  location: location
  tags: tags
  sku: {
    name: 'Basic'
  }
  properties: {
    adminUserEnabled: false
    anonymousPullEnabled: false
    dataEndpointEnabled: false
    policies: {
      azureADAuthenticationAsArmPolicy: {
        status: 'enabled'
      }
    }
    publicNetworkAccess: 'Enabled'
    roleAssignmentMode: 'AbacRepositoryPermissions'
    zoneRedundancy: 'Disabled'
  }
}

output registryId string = moduleRegistry.id
output registryName string = moduleRegistry.name
output registryLoginServer string = moduleRegistry.properties.loginServer

Der Registry-Name wird aus der Abonnement-ID abgeleitet, weil ACR-Namen global eindeutig sein müssen. Die Basic-SKU reicht für diese Lern-Registry aus. Das Administratorkonto und anonymer Pull sind deaktiviert; Identitäten authentifizieren sich über Microsoft Entra ID.

publicNetworkAccess: 'Enabled' bedeutet, dass authentifizierte Clients die Registry über ihren öffentlichen Azure-Endpunkt erreichen können. „Private Registry“ beschreibt die Zugriffssteuerung und nicht die Netzwerkisolation. Ein Produktionsdesign kann eine Premium-Registry mit privatem Endpunkt verwenden, wenn Netzwerkisolation erforderlich ist.

Erstelle cloudtrips-bicep/registry/registry.bicepparam:

using './registry.bicep'

param location = 'westeurope'
param resourceGroupName = 'rg-cloudtrips-bicep-registry-weu'

Registry anzeigen und bereitstellen

Wähle in cloudtrips-bicep das Abonnement aus, dem die gemeinsame Registry gehören soll:

az account set \
  --subscription "<Name oder ID des CloudTrips-Abonnements>"

Validiere die Bereitstellung und zeige die Vorschau an:

az deployment sub validate \
  --location westeurope \
  --name validate-cloudtrips-bicep-registry \
  --parameters registry/registry.bicepparam \
  --validation-level Provider

az deployment sub what-if \
  --location westeurope \
  --name preview-cloudtrips-bicep-registry \
  --parameters registry/registry.bicepparam

Die Vorschau soll eine Ressourcengruppe, eine verschachtelte Bereitstellung und eine Basic-Container-Registry erstellen. Stelle sie bereit:

az deployment sub create \
  --location westeurope \
  --name deploy-cloudtrips-bicep-registry \
  --parameters registry/registry.bicepparam \
  --query "properties.outputs" \
  --output yaml

Kopiere die Ausgaben registryName, registryLoginServer und storageModuleTarget.

Erfolgreiche Abonnementbereitstellung mit Registry-Name und Login-Server-Ausgaben von CloudTrips

Zugriff zum Veröffentlichen und Wiederherstellen gewähren

Öffne die neue Container Registry im Azure-Portal und wähle Access control (IAM) > Add role assignment.

Diese Registry verwendet RBAC Registry + ABAC Repository Permissions:

  • Gib der Person oder Pipeline, die Module veröffentlicht, die Rolle Container Registry Repository Writer.
  • Gib Consumer-Identitäten und Bereitstellungspipelines die Rolle Container Registry Repository Reader.
  • Füge Container Registry Repository Catalog Lister nur hinzu, wenn eine Identität alle Repositorys der Registry auflisten muss.

Die Azure-Abonnementrolle Contributor oder Owner ersetzt diese Repository-Datenebenenrollen nicht. Warte nach einer neuen Rollenzuweisung einige Minuten, bevor du veröffentlichst.

CloudTrips-Speichermodul veröffentlichen

Setze die Ausgabewerte in der aktuellen Shell:

registry_name="<registryName-Ausgabe>"
registry_login_server="<registryLoginServer-Ausgabe>"

Veröffentliche den Wrapper mit seinem Quellcode:

az bicep publish \
  --file modules/storage.bicep \
  --target "br:${registry_login_server}/bicep/modules/storage-account:1.0.0" \
  --with-source

Bicep kompiliert das Modul vor der Veröffentlichung. Das Artefakt enthält die bereitstellbare ARM-Vorlage, während --with-source für Consumer außerdem Go to Definition in der Bicep-Erweiterung von VS Code ermöglicht.

Bestätige die Version:

az acr repository show-tags \
  --name "$registry_name" \
  --repository bicep/modules/storage-account \
  --output table

Das Ergebnis soll 1.0.0 enthalten. Du kannst auch die Registry öffnen und Services > Repositories > bicep/modules/storage-account wählen.

CloudTrips-Repository für das Speicherkontomodul mit Version 1.0.0 in Azure Container Registry

Behandle eine veröffentlichte Version als unveränderlich. Verwende nicht --force, um 1.0.0 zu ersetzen, nachdem Consumer davon abhängen. Veröffentliche eine Korrektur als 1.0.1, eine kompatible Funktion als 1.1.0 und eine inkompatible Parameter- oder Ausgabeänderung als 2.0.0.

Modul aus einem anderen Repository wiederherstellen

Verwende für dieses Lab den enthaltenen Ordner cloudtrips-bicep/registry-consumer als separates Consumer-Projekt.

Erstelle oder aktualisiere im Consumer-Repository bicepconfig.json. Ersetze den Registry-Wert durch den kopierten Login-Server ohne https://:

{
  "moduleAliases": {
    "br": {
      "cloudtrips": {
        "registry": "<registry-name>.azurecr.io",
        "modulePath": "bicep/modules"
      }
    }
  }
}

Der Alias verkürzt den vollständigen Registry-Pfad. Erstelle im Consumer eine Datei main.bicep:

param location string = resourceGroup().location

module storage 'br/cloudtrips:storage-account:1.0.0' = {
  name: '${deployment().name}-storage'
  params: {
    applicationName: 'CloudTrips'
    containerNames: [
      'reports'
    ]
    costCenter: 'CC-DATA-200'
    deployAuditContainer: false
    environment: 'dev'
    location: location
    owner: 'CloudTrips Data Team'
    storageSku: 'Standard_LRS'
  }
}

output storageAccountName string = storage.outputs.storageAccountName
output blobEndpoint string = storage.outputs.blobEndpoint

Melde dich mit einer Identität an, die Container Registry Repository Reader besitzt, und stelle das Modul wieder her:

az bicep restore \
  --file main.bicep \
  --force

az bicep lint \
  --file main.bicep

restore lädt Version 1.0.0 in den lokalen Bicep-Cache. Verwende Go to Definition auf der Modulreferenz, um den mit dem Artefakt veröffentlichten Quellcode zu sehen.

Consumer-Repository beim Wiederherstellen des versionierten CloudTrips-Moduls und Öffnen seines veröffentlichten Quellcodes

Das Consumer-Repository enthält jetzt nur die Modulreferenz und seine eigenen Parameterwerte. Eine neu veröffentlichte Modulversion ändert den Consumer nicht unerwartet, da er auf 1.0.0 fixiert bleibt, bis sein Eigentümer die Referenz prüft und aktualisiert.

Pipeline-Identitäten benötigen ebenfalls Container Registry Repository Reader und müssen sich vor restore, Linting, Build oder Bereitstellung bei Azure authentifizieren, damit sie ein privates Modul herunterladen können. Öffentliche AVM-Referenzen benötigen diese zusätzliche Authentifizierung für die private Registry nicht.