Poznaj jak zbudować pipeline CI/CD na Azure DevOps. Poradnik krok po kroku: continuous integration, automatyzacja wdrożeń i dobre praktyki DevOps Azure.
Problem, który znasz z autopsji
Każdy zespół deweloperski, który choć raz wdrażał aplikację ręcznie o 3:00 w nocy przed release'em, wie, dlaczego automatyzacja to nie luksus — to konieczność. Według raportu DORA (DevOps Research and Assessment) z 2023 roku, organizacje z wysokim poziomem automatyzacji wdrożeń dostarczają oknet 208 razy szybciej niż te z niskim poziomem. Ryzyko awarii spada o 2-3 razy. Jeśli więc nadal klikasz "Publish" w Visual Studio i logujesz się ręcznie na serwer produkcyjny — ten artykuł jest dla Ciebie.
W Ciro Cloud regularnie wdrażamy pipeline DevOps na Azure dla klientów z sektora finansowego, e-commerce i logistyki. Poniżej dzielę się sprawdzoną metodologią, którą wypracowaliśmy na przestrzeni setek projektów.
Co to jest Azure DevOps i dlaczego warto go używać w chmurze?
Azure DevOps (wcześniej Visual Studio Team Services) to kompletna platforma SaaS od Microsoft do zarządzania cyklem życia aplikacji. Składa się z pięciu głównych usług:
- Azure Repos — prywatne repozytoria Git (bez limitu w planie Basic)
- Azure Pipelines — engine CI/CD z obsługą YAML i visual designers
- Azure Boards — tracking zadań (Kanban, Scrum)
- Azure Test Plans — testowanie manualne i automated
- Azure Artifacts — zarządzanie pakietami (NuGet, npm, Maven)
Dlaczego chmura? Ponieważ Azure Pipelines oferuje bezpłatne build minutes: 1,800 minut miesięcznie na publiczne projekty i 500 minut na prywatne (w planie Free). Dla małych zespołów to często wystarczające, żeby zacząć bez żadnych kosztów operacyjnych.
Cennik Azure DevOps (stan na 2024):
- Basic: ~6 USD/użytkownika/miesiąc — obejmuje repozytoria, Azure Pipelines (5 użytkowników Basic), Boards
- Basic + Test Plans: ~52 USD/użytkownika/miesiąc
- Visual Studio Enterprise subscribers: dostęp Basic w cenie subskrypcji
Architektura pipeline CI/CD na Azure DevOps
Zanim napiszesz pierwszą linię YAML, musisz zrozumieć architekturę. Typowy pipeline DevOps Azure składa się z trzech warstw:
- Source Stage — kod w Azure Repos (lub GitHub, Bitbucket)
- Build Stage — kompilacja, testy jednostkowe, statyczna analiza
- Release Stage — wdrożenie do środowisk (Dev, Staging, Production)
Każda warstwa działa na Azure Pipeline Agents. Microsoft oferuje dwa typy:
- Microsoft-hosted agents — maszyny w Azure, zarządzane przez Microsoft. Są resetowane po każdym zadaniu. Idealne dla prostych buildów.
- Self-hosted agents — instalowane na Twoich maszynach (VM, kontener). Utrzymujesz je sam. Dają większą kontrolę, cache Buildkite'a, i dostęp do prywatnej sieci. Koszt: tylko koszt infrastruktury.
Rekomendacja z praktyki: Jeśli budujesz aplikacje .NET Core lub Node.js na Windows — Microsoft-hosted wystarczy. Jeśli potrzebujesz specyficznych narzędzi (np. Android SDK, специфічних bibliotek Linux), rozważ self-hosted na Azure VM Scale Set. Kosztuje to około 40-60 USD miesięcznie za maszynę (Standard B2s), ale drastycznie przyspiesza buildy dzięki caching.
Krok po kroku: tworzenie pipeline'u CI/CD na Azure DevOps
Krok 1: Utwórz projekt w Azure DevOps
- Przejdź do dev.azure.com
- Kliknij "Create New Project"
- Wybierz "Git" jako Version Control
- Ustaw Visibility: Private (chyba że open source)
- Kliknij "Create"
Krok 2: Skonfiguruj Azure Repos
Możesz użyć wbudowanego Azure Repos lub połączyć zewnętrzny Git (GitHub, Bitbucket). Dla GitHub integracja jest native — wystarczy zainstalować Azure Pipelines app z GitHub Marketplace.
git init
git add .
git commit -m "Initial commit with Azure DevOps pipeline"
git remote add origin https://dev.azure.com/your-org/your-project/_git/repo
git push -u origin --all
Krok 3: Utwórz plik azure-pipelines.yml
To jest sedno Twojego pipeline'u. Umieść go w korzeniu repozytorium:
# azure-pipelines.yml
trigger:
branches:
include:
- main
- develop
paths:
include:
- src/**
- tests/**
- azure-pipelines.yml
pr:
branches:
include:
- main
pool:
vmImage: 'ubuntu-latest' # Microsoft-hosted, Ubuntu 22.04
variables:
buildConfiguration: 'Release'
dotnetVersion: '8.0.x'
nodeVersion: '20.x'
stages:
- stage: Build
displayName: 'Build and Test'
jobs:
- job: BuildJob
displayName: 'Build Application'
steps:
# .NET build
- task: UseDotNet@2
displayName: 'Use .NET $(dotnetVersion)'
inputs:
packageType: 'sdk'
version: $(dotnetVersion)
- script: |
dotnet restore
dotnet build --configuration $(buildConfiguration)
dotnet test --configuration $(buildConfiguration) --verbosity normal
displayName: 'Build and Test .NET'
# Publish artifact
- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact'
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'drop'
publishLocation: 'Container'
- stage: Deploy_Dev
displayName: 'Deploy to Dev'
dependsOn: Build
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployDev
displayName: 'Deploy to Azure App Service Dev'
environment: 'dev'
strategy:
runOnce:
deploy:
steps:
- task: AzureWebApp@1
displayName: 'Azure App Service Deploy: dev-api'
inputs:
azureSubscription: 'AzureServiceConnection-Dev'
appType: 'webApp'
appName: 'dev-cirocloud-api'
package: '$(Pipeline.Workspace)/drop/**/*.zip'
deploymentMethod: 'auto'
- stage: Deploy_Prod
displayName: 'Deploy to Production'
dependsOn: Deploy_Dev
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: DeployProd
displayName: 'Deploy to Azure App Service Production'
environment: 'production'
strategy:
runOnce:
deploy:
steps:
- task: AzureWebApp@1
displayName: 'Azure App Service Deploy: prod-api'
inputs:
azureSubscription: 'AzureServiceConnection-Prod'
appType: 'webApp'
appName: 'prod-cirocloud-api'
package: '$(Pipeline.Workspace)/drop/**/*.zip'
deploymentMethod: 'auto'
Krok 4: Skonfiguruj Service Connections
Aby Azure Pipelines mógł wdrażać do Azure, potrzebujesz Service Connection:
- Przejdź do Project Settings → Service connections
- Kliknij New service connection → Azure Resource Manager
- Wybierz Service principal (automatic) — zalecane dla CI/CD
- Ustaw Scope level: Subscription lub Resource Group
- Nazwij połączenie (np. "AzureServiceConnection-Dev")
Uwaga bezpieczeństwa: Nigdy nie używaj Credentials użytkownika. Service principal z RBAC to podstawa. Najmniejsze uprawnienia: "Website Contributor" dla App Service, "Storage Blob Data Contributor" dla Blob Storage.
Krok 5: Skonfiguruj środowiska (Environments)
Environments w Azure DevOps to nie tylko tagging — to kontrola uprawnień i historia wdrożeń:
- Przejdź do Pipelines → Environments
- Utwórz środowiska: "dev", "staging", "production"
- Dla "production" włącz Approvals and checks:
- Approval — wymagaj akceptacji od co najmniej jednego revisera
- Azure resource group deployment check — waliduj, że zasoby istnieją
- Business hours gate — blokuj wdrożenia poza godzinami pracy (opcjonalne)
Automatyzacja wdrożeń — strategie zaawansowane
Wdrożenie typu Rolling vs. Canary vs. Blue-Green
W pliku YAML powyżej użyłem prostego "runOnce". Dla aplikacji krytycznych rozważ:
Canary Deployment (polecam dla mikroserwisów):
- stage: Deploy_Canary
jobs:
- deployment: DeployCanary
strategy:
canary:
increments: 10 # 10% ruchu na nową wersję
steps:
- task: AzureAppServiceManage@0
inputs:
Action: 'Swap Slots'
WebAppName: 'prod-cirocloud-api'
SourceSlot: 'staging'
Blue-Green z Traffic Routing:
Azure App Service ma wbudowane Traffic Routing. W Azure Portal włącz "Production" i "Staging" slots, skonfiguruj DNS, a pipeline swapuje sloty atomowo. Czas przestoju: ~0 sekund.
Continuous Integration Cloud — build matrix
Dla aplikacji cross-platform (Windows/Linux/macOS), użyj matrix strategy:
jobs:
- job: Build
strategy:
matrix:
linux:
imageName: 'ubuntu-latest'
windows:
imageName: 'windows-latest'
macos:
imageName: 'macOS-latest'
pool:
vmImage: $(imageName)
steps:
- script: ./build.sh
Ograniczenie: macOS build minutes kosztują więcej w Microsoft-hosted. MacOS-small pool daje 6 vCPU, 14 GB RAM za ~40 USD/10 godzin. Dla React Native lub iOS builds to jedyna opcja (bez Mac Mini na biurku).
Integracja z Azure Container Instances (ACI) dla testów
Zamiast buildować na VM, możesz wdrożyć testy do kontenera:
- task: Docker@2
displayName: 'Build and push test image'
inputs:
containerRegistry: 'acr-cirocloud.azurecr.io'
repository: 'integration-tests'
command: 'buildAndPush'
Dockerfile: 'tests/Dockerfile'
- task: AzureContainerApps@0
displayName: 'Run integration tests in ACA'
inputs:
azureSubscription: 'AzureServiceConnection-Prod'
containerAppEnvironment: 'test-env'
containerAppName: 'integration-tests-runner'
imageToDeploy: 'acr-cirocloud.azurecr.io/integration-tests:$(Build.BuildId)'
Typowe problemy i jak ich unikać
Problem 1: Build minutes timeout
Symptom: "The job has timed out after 60 minutes."
Rozwiązanie:
- Włącz caching dla NuGet/npm packages:
- task: Cache@2
inputs:
key: 'npm | $(Agent.OS) | package-lock.json'
path: '$(Pipeline.Workspace)/.npm'
restoreKeys: |
npm | $(Agent.OS)
- Użyj parallel jobs (dostępne w planie paid)
- Rozważ self-hosted agents z szybszym dyskiem (Premium SSD zamiast Standard)
Problem 2: Secrets w pipeline'u
Nigdy nie hardcoduj haseł w YAML. Używaj:
- Azure Key Vault integration:
- task: AzureKeyVault@2
inputs:
azureSubscription: 'AzureServiceConnection-Prod'
KeyVaultName: 'kv-cirocloud-prod'
SecretsFilter: '*'
RunAsPreJob: true
- Variable groups z "Lock" option w Library
Problem 3: Wdrożenie na niewłaściwe środowisko
Symptom: Kod z brancha "feature/fix-bug" wdrożył się na production.
Rozwiązanie:
- Filtry w
triggericondition(jak w przykładzie YAML powyżej) - Environment-level approvals — wymuszają manual review przed Prod
- Branch policies — wymagaj PR reviews i status checks przed merge do main
Problem 4: Flaky tests blokują pipeline
Rozwiązanie:
- Oddziel testy unitowe (szybkie, uruchamiane w Build stage) od integration tests (w osobnym, opcjonalnym stage)
- Używaj
continueOnError: truez raportowaniem:
- script: npm test
continueOnError: true
displayName: 'Run tests (non-blocking)'
- Monitoruj flaky tests ratio — powyżej 2% to czerwona flaga
Integracje i rozszerzenia warte uwagi
Z GitHub Marketplace możesz rozszerzyć Azure Pipelines o:
- SonarCloud — static code analysis (bezpłatny dla open source, ~100 EUR/miesiąc dla private)
- Snyk Security Scan — vulnerability scanning w kontenerach (~$250/miesiąc za zespół)
- LaunchDarkly — feature flags bez redeploya
- Slack notifications — integracja z kanałami DevOps
Podsumowanie i kolejne kroki
Pipeline CI/CD na Azure DevOps to nie jednorazowa konfiguracja — to ewoluujący system. Zacznij od prostego build → deploy pipeline'u (jak pokazano powyżej), a potem iteracyjnie dodawaj:
- Testy automatyczne (unit, integration, E2E)
- Security scanning (SAST, DAST)
- Infrastructure as Code (Terraform + Azure DevOps pipelines)
- Monitoring i alerting (Application Insights integration)
- Release gates (automatyczne rollback na podstawie metryk)
Jeśli potrzebujesz pomocy we wdrożeniu pipeline'u DevOps Azure w swojej organizacji — sprawdź nasze usługi na Ciro Cloud lub zostaw komentarz. Chętnie pomogę dobrać architekturę do specyfiki Twojego projektu.
Źródła i further reading:
- Azure Pipelines Documentation — oficjalna dokumentacja Microsoft
- DORA State of DevOps Report 2023 — benchmarki i metryki
- Azure DevOps Pricing — aktualny cennik
Weekly cloud insights — free
Practical guides on cloud costs, security and strategy. No spam, ever.
Comments