Martin Rylko
  • Služby
  • Blog
  • O mně
  • Kontakt
  • Spolupráce
Martin Rylko

Senior Cloud Architect & DevOps Engineer. Specializace na Microsoft Azure, IaC, Cloud Security a AI.

Navigace

  • Služby
  • Blog
  • O mně
  • Kontakt

Spolupráce

Hledáte zkušeného architekta pro Váš Azure projekt? Ozvěte se.

rylko@cloudmasters.cz

© 2026 Martin Rylko. Všechna práva vyhrazena.

Buduji v cloudu. Nasazuji přes Azure Static Web Apps.

Domů/Blog/Bicep shared moduly: Skip-if-exists pattern místo --force
Všechny článkyRead in English

Bicep shared moduly: Skip-if-exists pattern místo --force

15. 4. 2026 3 min
#Bicep#Azure#DevOps#IaC#CI/CD

Bicep shared moduly: Skip-if-exists pattern místo --force

V Christie's máme veřejně dobře zdokumentovaný setup – platform tým spravuje 76 sdílených Bicep modulů v Azure Container Registry a desítky workloadových repozitářů je konzumují přes br:registry/module:tag reference. Verze jsou pinované, semver disciplinovaný, schémata stabilní. Až do dne, kdy mi Russell, vedoucí platform týmu, ukázal nedávný incident.

Storage modul cmn-storage:1.4.2 se přepsal v rámci hotfixu. Konzument v retail subskripci na další az deployment viděl propertyName Foo of ResourceType Bar is not allowed. Pinned verze 1.4.2 se mu změnila pod rukama, protože publish pipeline používala --force.

Tahle událost rozjela ticket DO-429: nahradit --force skip-if-exists patternem a vynutit semver bump v PR validaci. Tady je playbook.

Proč --force vůbec existoval

Historický důvod byl pohodlí. CI pipeline publikovala při každém merge do main, a když někdo nezvedl verzi, build padl. Tým si zvykl psát --force jako rychlou opravu, místo aby řešil semver. Po roce a půl to bylo defaultní chování v hlavní pipeline.

# Před – publish-modules.yml (špatně)
- task: AzureCLI@2
  inputs:
    azureSubscription: $(azureServiceConnection)
    scriptType: bash
    inlineScript: |
      for module in modules/*/; do
        name=$(basename "$module")
        az bicep publish \
          --file "$module/main.bicep" \
          --target "br:$(acrName).azurecr.io/bicep/$name:$(version)" \
          --force   # <-- problém
      done

Problém shrnu třemi body: silently overwrites publikované verze, neexistuje audit, neexistuje žádný kontrolní bod, kdy se verze měla zvednout.

Skip-if-exists pattern

Princip: zkontroluj, jestli verze už existuje. Pokud ano, log a skip. Pokud ne, publish.

#!/usr/bin/env bash
set -euo pipefail
 
ACR_NAME="$1"
MODULE_NAME="$2"
VERSION="$3"
 
# Check, jestli tag existuje
if az acr repository show-tags \
     --name "$ACR_NAME" \
     --repository "bicep/$MODULE_NAME" \
     --query "[?@=='$VERSION'] | [0]" -o tsv | grep -q "$VERSION"; then
  echo "::notice::Module $MODULE_NAME:$VERSION already exists, skipping."
  exit 0
fi
 
# Publish (bez --force)
az bicep publish \
  --file "modules/$MODULE_NAME/main.bicep" \
  --target "br:$ACR_NAME.azurecr.io/bicep/$MODULE_NAME:$VERSION"
 
echo "::notice::Published $MODULE_NAME:$VERSION"

Tři vlastnosti, které tenhle skript dělají enterprise-ready:

  1. set -euo pipefail – jakákoliv chyba zhasne pipeline, žádné silent failure
  2. Skip log přes GitHub ::notice:: – v job summary vidíte přesně, co se publikovalo a co bylo přeskočeno
  3. Žádný --force – pokud verze existuje, je to konec; ne se starší verze přepíše

PR validace: vynutit verze bump

Skip-if-exists řeší produkční riziko. Ale stále hrozí, že developer udělá změnu v modulu, nezvedne verzi, a merge projde – produkční konzumenti s pinned verzí novou změnu nikdy neuvidí.

Řešení: PR check, který sleduje diff a vyžaduje semver bump pro každý změněný modul.

# .github/workflows/pr-validate-bicep.yml
name: Validate Bicep module changes
on:
  pull_request:
    paths:
      - 'modules/**'
 
jobs:
  semver-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0   # potřeba pro diff vůči main
 
      - name: Check semver bump for changed modules
        run: |
          changed_modules=$(git diff --name-only origin/main...HEAD modules/ | awk -F'/' '{print $2}' | sort -u)
          fail=0
          for module in $changed_modules; do
            metadata_file="modules/$module/metadata.json"
            if ! git diff origin/main...HEAD -- "$metadata_file" | grep -q '"version"'; then
              echo "::error::Module $module changed but version in $metadata_file not bumped."
              fail=1
            fi
          done
          exit $fail

Kombinace skip-if-exists v publish + PR check na verze znamená, že nelze omylem nasadit změnu se starou verzí.

Konzument: jak verzi pinovat správně

Konzumentský repository pak pinuje konkrétní verzi:

module storage 'br:cmnregistry.azurecr.io/bicep/cmn-storage:1.4.3' = {
  name: 'storageDeployment'
  params: {
    storageAccountName: name
    location: location
    sku: 'Standard_LRS'
  }
}

Co nedělat:

  • Nepoužívat latest tag – v ACR fyzicky existuje, ale popírá smysl semver
  • Nepoužívat rozsahy – Bicep registr range syntax (^1.4.0) neumí; vždy konkrétní tag
  • Nepublikovat moduly z feature větve do produkčního registru – mějte oddělený bicep-dev/ repository v ACR

Renovate / Dependabot pro Bicep moduly

Pro udržování konzumentských repozitářů aktuálních doporučuji Renovate, který od verze 39 nativně rozumí Bicep registry referencím:

// renovate.json
{
  "extends": ["config:recommended"],
  "bicep": { "enabled": true },
  "packageRules": [
    {
      "matchManagers": ["bicep"],
      "matchUpdateTypes": ["minor", "patch"],
      "automerge": true,
      "automergeType": "pr"
    },
    {
      "matchManagers": ["bicep"],
      "matchUpdateTypes": ["major"],
      "labels": ["bicep-major-bump", "needs-review"]
    }
  ]
}

Patch a minor verze se mergují automaticky (semver kontrakt říká, že jsou kompatibilní). Major bumpy padají na review – ten labeluje a notifikuje cloud platform team.

Audit: kdo a kdy přepsal modul

I s break-glass postupem chceme vědět, kdy se použil --force. V Christie's to řešíme přes ACR Activity Log s alertem:

resource forcePublishAlert 'Microsoft.Insights/scheduledQueryRules@2023-03-15-preview' = {
  name: 'alert-bicep-module-overwrite'
  location: location
  properties: {
    severity: 1
    enabled: true
    evaluationFrequency: 'PT15M'
    windowSize: 'PT15M'
    scopes: [logAnalyticsWorkspaceId]
    criteria: {
      allOf: [
        {
          query: '''
            ContainerRegistryRepositoryEvents
            | where Repository startswith "bicep/"
            | where OperationName == "Push"
            | summarize PushCount = count() by Repository, Tag = MediaType, Identity
            | where PushCount > 1
          '''
          timeAggregation: 'Count'
          operator: 'GreaterThan'
          threshold: 0
        }
      ]
    }
    actions: {
      actionGroups: [securityActionGroupId]
    }
  }
}

Pokud do stejného tagu přijde druhý push v 15-minutovém okně, jde alert na security team. Většinou je to legitimní break-glass, občas se tím chytí pipeline misconfiguration.

Rollout: jak nahradit --force v existujícím prostředí

V Christie's jsme to dělali ve čtyřech krocích:

KrokTýdenRiziko
Implementovat skip-if-exists, ponechat --force jako fallback flag1Žádné – nic se nemění
Spustit oba módy paralelně, monitorovat skip-rate2–3Žádné – jen sběr dat
Komunikovat změnu napříč týmy, dát 1 týden notice4Žádné
Odebrat --force flag, vynutit semver PR check5Nízké – občasný PR padne, dev opraví

Po pěti týdnech jsme měli zero overwrite incidentů a žádný team se nestěžoval na pomalost publish procesu (skip je rychlejší než publish).

Závěr

--force v az bicep publish je v multi-team prostředí mina. Skip-if-exists pattern, semver PR validation a audit alert ji zneškodní za pět týdnů rolloutu. Cena je nula – jen disciplína a 50 řádků Bash skriptu.

Pokud řešíte podobnou situaci se sdílenými Bicep nebo Terraform moduly v enterprise měřítku, podívejte se na naše služby cloudové architektury nebo se ozvěte pro review vaší IaC supply chain.

Tagy:#Bicep#Azure#DevOps#IaC#CI/CD
LinkedInX / Twitter

O autorovi

Martin Rylko

Martin Rylko

Senior Cloud Architect & DevOps Engineer

Více než 14 let v IT – od on-premises datacenter a Hyper-V clusteringu po cloudovou infrastrukturu v Microsoft Azure. Specializuji se na Landing Zones, IaC automatizaci, Kubernetes a bezpečnostní compliance.

Email LinkedInCelý profil

Nejcastejsi dotazy

Proč je --force při publikaci Bicep modulů problém?▾
Příznak --force u az bicep publish přepíše existující verzi modulu v ACR bez varování. V malém prostředí to znamená nepříjemnost. V enterprise prostředí, kde 50 konzumentů má pinned verze, to znamená, že někdo silent broke produkci jiného týmu. Skutečný incident, který jsem řešil v Christie's: hotfix v shared modulu pro Storage přepsal v1.4.2 a všechny konzumenty s pinned 1.4.2 začaly mít drift při dalším deploymentu.
Jak se semver vztahuje k publikaci Bicep modulů?▾
Striktně. Patch verze (1.4.2 → 1.4.3) pro bug fixy bez API změn. Minor (1.4 → 1.5) pro zpětně kompatibilní nové vstupy. Major (1.x → 2.0) pro breaking změny ve schématu parametrů, povinných hodnotách nebo výstupech. Konzumenti potom v main.bicep pinují na konkrétní verzi (br:registry/module:1.4.3) a nedostávají nečekané chování při novém publishi.
Co když potřebuji přepsat publikovanou verzi v krajní situaci?▾
Mít proceduru, ale ne v pipeline. V Christie's máme break-glass postup: požadavek do Jiry se schválením Cloud Platform leadem, dočasně udělit AcrPush role na konkrétní service principal, manuální az bicep publish --force se zápisem do audit logu, okamžitý revoke role. V průměru se použije jednou za rok. Pokud se používá častěji, neřešíte symptom, ale špatný versioning proces.
Funguje skip-if-exists pattern i pro Azure DevOps i pro GitHub Actions?▾
Ano, je to úplně CLI-driven (az acr repository show + bash exit code). V GitHub Actions je to o pět řádků v workflow, v Azure DevOps stejně v YAML pipeline. Patrnou výhodu má GitHub Actions, protože jeho job summary skvěle renderuje skip vs publish tabulku – v ADO musíte výsledek zapsat do logu nebo do extension output.

Mohlo by vás zajímat

Bicep CI/CD: GitHub Actions pipeline pro Azure

Produkční deployment pipeline pro Bicep v GitHub Actions. What-if náhledy, schvalování prostředí, OIDC autentizace a rollback strategie.

Číst

Bicep Deployment Stacks: Lifecycle management bez ručního cleanupu

Deployment Stacks v Bicepu jsou způsob, jak Azure resources spravovat jako koherentní celek s denyAssignments, auto-cleanup a controlled deletion. Praktický průvodce s migration plánem z klasických deploymentů.

Číst

Terraform Azure moduly: Privátní registr a testování

Znovupoužitelné Terraform moduly pro Azure s publikací do privátního registru, automatizované testování Terratest a verzovaná spotřeba modulů v produkci.

Číst