Jak Zautomatyzować Wdrożenia Docker na Zewnętrznym Hoście za Pomocą Azure DevOps?
Pełny przewodnik krok po kroku do tworzenia potoków CI/CD wykorzystujących zdalne środowiska Docker.
Tworzenie potoku (pipeline) w Azure DevOps, który współpracuje z obrazem Docker na zewnętrznym hoście, to częsty scenariusz pozwalający na elastyczne zarządzanie środowiskami i wdrożeniami. Można to osiągnąć na kilka sposobów, w zależności od konkretnych potrzeb – czy chcesz uruchomić zadania potoku w specyficznym kontenerze, czy też wdrożyć aplikację na zdalnym serwerze Docker.
Kluczowe Aspekty Konfiguracji
- Połączenia Usług (Service Connections): Niezbędne do bezpiecznego uwierzytelniania z zewnętrznymi rejestrami kontenerów (np. Azure Container Registry, Docker Hub) oraz potencjalnie ze zdalnymi hostami Docker.
- Definicje Zadań w Kontenerach (YAML): Użycie sekcji
containerw pliku YAML potoku pozwala na wykonywanie zadań wewnątrz kontenera pobranego z określonego obrazu Docker. - Agenci Self-Hosted: Instalacja agenta Azure DevOps bezpośrednio na zewnętrznym hoście (lub w kontenerze Docker na tym hoście) jest najpewniejszym sposobem na bezpośrednie wykonywanie poleceń Docker na tej maszynie.
Główne Podejścia do Integracji z Zewnętrznym Hostem Docker
Istnieją dwie główne metody integracji potoków Azure DevOps z obrazami Docker na zewnętrznych hostach:
Podejście 1: Uruchamianie Zadań Potoku w Kontenerze z Zewnętrznego Rejestru
Ta metoda jest idealna, gdy środowisko wykonawcze Twojego potoku (np. do budowania, testowania) wymaga specyficznych narzędzi lub konfiguracji dostępnych w niestandardowym obrazie Docker. Obraz ten może być przechowywany w zewnętrznym rejestrze (prywatnym lub publicznym).
Krok 1: Konfiguracja Połączenia Usługi z Rejestrem Kontenerów
Aby Azure DevOps mógł pobrać obraz z zewnętrznego rejestru (np. Azure Container Registry (ACR), prywatnego Docker Hub, innego rejestru), musisz skonfigurować Połączenie Usługi (Service Connection):
- Przejdź do Ustawień Projektu (Project Settings) -> Potoki (Pipelines) -> Połączenia usług (Service connections).
- Kliknij "New service connection" i wybierz typ "Docker Registry".
- Wybierz swój typ rejestru (ACR, Docker Hub, Others).
- Podaj wymagane dane: adres URL rejestru, nazwę użytkownika/ID jednostki usługi, hasło/klucz jednostki usługi oraz nazwę połączenia usługi.
Krok 2: Definicja Zadania Kontenerowego w YAML
W pliku azure-pipelines.yml zdefiniuj zadanie (job), które ma być uruchomione w kontenerze:
pool:
vmImage: 'ubuntu-latest' # Agent hostujący (może być też self-hosted)
resources:
containers:
- container: my_container_alias # Alias kontenera
type: ACR # Typ rejestru (ACR, Docker Hub, etc.)
azureSubscription: 'MyAzureSubscriptionServiceConnection' # Opcjonalne dla ACR
resourceGroup: 'MyResourceGroup' # Opcjonalne dla ACR
registry: 'youracrname.azurecr.io' # Nazwa twojego rejestru
repository: 'your-image-name' # Nazwa repozytorium obrazu
endpoint: 'MyDockerRegistryServiceConnection' # Nazwa połączenia usługi (jeśli nie ACR lub publiczny Docker Hub)
image: 'yourregistry.com/your-image-name:tag' # Pełna nazwa obrazu (alternatywa dla endpoint/registry/repository)
jobs:
- job: BuildInContainer
displayName: 'Build inside custom container'
container: my_container_alias # Użyj zdefiniowanego kontenera
steps:
- script: |
echo "Ten skrypt działa wewnątrz kontenera!"
# Tutaj umieść kroki budowania, testowania itp.
# Masz dostęp do narzędzi zainstalowanych w obrazie Docker.
displayName: 'Run script in container'
Wszystkie kroki (steps) w ramach zadania BuildInContainer będą wykonywane wewnątrz kontenera uruchomionego z obrazu yourregistry.com/your-image-name:tag.
Architektura aplikacji skonteneryzowanej przy użyciu Docker.
Podejście 2: Wdrażanie/Uruchamianie Kontenerów na Zewnętrznym Hoście przez Agenta Self-Hosted
To podejście jest stosowane, gdy celem potoku jest wdrożenie lub zarządzanie kontenerami bezpośrednio na konkretnej maszynie zewnętrznej (np. serwerze deweloperskim, maszynie wirtualnej w innej chmurze). Wymaga to zainstalowania agenta Azure DevOps na tym hoście.
Krok 1: Instalacja i Konfiguracja Agenta Self-Hosted na Zewnętrznym Hoście
- Zainstaluj Docker na zewnętrznym hoście.
- Przejdź do Ustawień Organizacji (Organization Settings) -> Pule agentów (Agent pools).
- Utwórz nową pulę agentów (lub użyj istniejącej, np. 'Default').
- Kliknij "New agent" i postępuj zgodnie z instrukcjami, aby pobrać i skonfigurować agenta na zewnętrznym hoście (Linux, macOS lub Windows). Będziesz potrzebował adresu URL organizacji Azure DevOps i tokenu PAT (Personal Access Token) z odpowiednimi uprawnieniami.
- (Opcjonalnie, zalecane) Uruchomienie agenta w kontenerze Docker: Możesz uruchomić agenta w kontenerze na hoście, co zapewnia izolację. Użyj oficjalnego obrazu agenta Microsoft:
Ważne: Montowanie gniazda Docker (# Przykład dla Linuksa docker run -d --name azdevops-agent \ -e AZP_URL=https://dev.azure.com/YOUR_ORG_NAME \ -e AZP_TOKEN=YOUR_PAT_TOKEN \ -e AZP_POOL=YOUR_AGENT_POOL_NAME \ -e AZP_AGENT_NAME=my-docker-agent \ -v /var/run/docker.sock:/var/run/docker.sock \ -v /path/on/host/_work:/opt/agent/_work \ mcr.microsoft.com/azure-pipelines/agent:latest-v /var/run/docker.sock:/var/run/docker.sock) pozwala agentowi (działającemu w kontenerze) na wykonywanie poleceń Docker na hoście. Jest to potężne, ale niesie ze sobą implikacje bezpieczeństwa – kontener agenta zyskuje uprawnienia do zarządzania wszystkimi kontenerami na hoście.
Krok 2: Wycelowanie Potoku w Pulę Agentów Self-Hosted
W pliku azure-pipelines.yml wskaż pulę agentów, w której znajduje się Twój skonfigurowany agent:
pool:
name: 'YOUR_AGENT_POOL_NAME' # Nazwa puli zawierającej agenta na zewnętrznym hoście
Krok 3: Wykonywanie Poleceń Docker na Zewnętrznym Hoście
Teraz możesz używać kroków script lub zadania Docker@2 do interakcji z Dockerem na hoście, na którym działa agent.
steps:
- script: |
echo "Running on the external host: $(hostname)"
docker pull yourregistry.com/your-app-image:latest
docker stop my-app-container || true # Zatrzymaj stary kontener, jeśli istnieje
docker rm my-app-container || true # Usuń stary kontener
docker run -d --name my-app-container -p 8080:80 yourregistry.com/your-app-image:latest
displayName: 'Deploy application container on external host'
# Alternatywnie, używając zadania Docker@2 (wymaga Docker Host Service Connection lub wykonania na agencie z dostępem do dockerd)
# - task: Docker@2
# displayName: 'Run image on external host'
# inputs:
# command: 'run'
# # dockerHostEndpoint: 'MyExternalDockerHostConnection' # Jeśli używasz Docker Host Service Connection
# imageName: 'yourregistry.com/your-app-image:latest'
# containerName: 'my-app-container'
# ports: '8080:80'
# # ... inne argumenty 'run'
W tym scenariuszu potok najpierw buduje i wypycha obraz do rejestru (w poprzednim etapie lub zadaniu, zazwyczaj na agencie hostowanym przez Microsoft), a następnie zadanie uruchamiane na agencie self-hosted pobiera najnowszy obraz i uruchamia go na zewnętrznym hoście.
Architektura CI/CD w środowisku hybrydowym z agentami self-hosted.
Wizualizacja Procesu i Komponentów
Mapa Myśli: Kluczowe Elementy Konfiguracji
Poniższa mapa myśli ilustruje główne komponenty i zależności podczas konfiguracji potoku Azure DevOps do pracy z Dockerem na zewnętrznym hoście.
Porównanie Podejść (Radar Chart)
Ten wykres radarowy porównuje dwa główne podejścia ("Zadanie w Kontenerze" vs "Agent Self-Hosted") pod względem kilku kluczowych czynników. Wyższe wartości oznaczają generalnie lepsze dopasowanie do danego kryterium (skala 1-5, gdzie 1=Niska, 5=Wysoka).
Interpretacja: Podejście z agentem self-hosted daje znacznie większą kontrolę nad docelowym hostem i ułatwia lokalne debugowanie, ale może być nieco bardziej złożone w konfiguracji i wymaga starannego zarządzania bezpieczeństwem (zwłaszcza przy montowaniu gniazda Docker). Podejście z zadaniem w kontenerze jest prostsze w konfiguracji dla samego środowiska wykonawczego zadania i oferuje dużą elastyczność środowiska, ale ma ograniczoną kontrolę nad samym hostem agenta.
Przykład Kompletnego Potoku (Build, Push, Deploy)
Poniższy przykład YAML łączy budowanie obrazu, wypychanie go do Azure Container Registry (ACR) i wdrażanie na zewnętrznym hoście za pomocą agenta self-hosted.
trigger:
- main
variables:
# Połączenie usługi do Twojego ACR
dockerRegistryServiceConnection: 'YourACRServiceConnectionName'
# Nazwa Twojego ACR
containerRegistry: 'youracrname.azurecr.io'
# Nazwa repozytorium obrazu w ACR
imageRepository: 'my-app-image'
# Ścieżka do Dockerfile
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
# Tag obrazu (używamy ID buildu dla unikalności)
tag: '$(Build.BuildId)'
# Nazwa puli z agentem self-hosted na zewnętrznym hoście
externalHostAgentPool: 'YourSelfHostedAgentPoolName'
# Nazwa kontenera na zewnętrznym hoście
containerName: 'my-live-app'
stages:
- stage: BuildAndPush
displayName: 'Build and Push Image'
jobs:
- job: Build
displayName: 'Build and Push to ACR'
pool:
vmImage: 'ubuntu-latest' # Użyj agenta hostowanego przez Microsoft do budowania
steps:
- task: Docker@2
displayName: 'Login to ACR'
inputs:
command: 'login'
containerRegistry: $(dockerRegistryServiceConnection)
- task: Docker@2
displayName: 'Build and Push image'
inputs:
command: 'buildAndPush'
repository: $(imageRepository)
dockerfile: $(dockerfilePath)
containerRegistry: $(dockerRegistryServiceConnection)
tags: |
$(tag)
latest
- task: Docker@2
displayName: 'Logout from ACR'
inputs:
command: 'logout'
containerRegistry: $(dockerRegistryServiceConnection)
- stage: DeployToExternalHost
displayName: 'Deploy to External Host'
dependsOn: BuildAndPush # Uruchom ten etap po zakończeniu BuildAndPush
jobs:
- job: Deploy
displayName: 'Deploy Container on External Host'
pool:
name: $(externalHostAgentPool) # Użyj agenta self-hosted
steps:
- script: |
echo "Deploying image $(containerRegistry)/$(imageRepository):$(tag) on host $(hostname)"
# Zaloguj się do ACR (jeśli agent nie ma stałych poświadczeń)
# Możesz użyć <code>docker login z poświadczeniami z Key Vault lub Service Connection
# Przykład: docker login $(containerRegistry) -u $(ACR_USER) -p $(ACR_PASSWORD)
# Gdzie ACR_USER i ACR_PASSWORD są zmiennymi tajnymi
docker pull $(containerRegistry)/$(imageRepository):$(tag)
echo "Stopping and removing existing container..."
docker stop $(containerName) || true
docker rm $(containerName) || true
echo "Starting new container..."
docker run -d --name $(containerName) \
-p 80:80 \
--restart always \
$(containerRegistry)/$(imageRepository):$(tag)
echo "Deployment complete."
displayName: 'Pull and Run Docker Container'
# env: # Przykład przekazania zmiennych tajnych
# ACR_USER: $(ACRUsernameFromSecretVariable)
# ACR_PASSWORD: $(ACRPasswordFromSecretVariable)
Wideo: Wdrożenie Aplikacji .NET z Dockerem na Azure
Chociaż ten film koncentruje się na wdrażaniu na Azure App Service, demonstruje kluczowe etapy tworzenia potoku CI/CD w Azure DevOps do budowania obrazu Docker i jego publikacji, co jest fundamentalnym elementem procesu opisanego powyżej.
Ten przewodnik wideo pokazuje krok po kroku, jak wdrożyć aplikację .NET Web App za pomocą Dockera na Azure, w tym konfigurację potoku DevOps.
Podsumowanie Kluczowych Komponentów
Poniższa tabela podsumowuje najważniejsze elementy używane podczas konfiguracji potoków Azure DevOps z Dockerem na zewnętrznych hostach.
| Komponent | Opis | Kiedy Używać | Przykładowe Użycie w YAML |
|---|---|---|---|
| Połączenie Usługi (Service Connection) - Docker Registry | Umożliwia bezpieczne uwierzytelnienie i połączenie z rejestrami kontenerów (ACR, Docker Hub, inne). | Do pobierania (pull) i wypychania (push) obrazów z/do prywatnych rejestrów. | endpoint: 'MyDockerRegistryConnection' (w definicji kontenera) lub containerRegistry: 'MyDockerRegistryConnection' (w zadaniu Docker@2). |
| Połączenie Usługi (Service Connection) - Docker Host | Umożliwia bezpośrednie połączenie z demonem Docker na zdalnym hoście (wymaga konfiguracji TLS). | Rzadziej używane; alternatywą jest agent self-hosted. Do wykonywania poleceń Docker na zdalnym hoście bez agenta. | dockerHostEndpoint: 'MyExternalDockerHostConnection' (w zadaniu Docker@2). |
| Agent Microsoft-Hosted | Agenci zarządzani przez Microsoft, dostępni w chmurze Azure DevOps. | Do zadań budowania, testowania, wypychania obrazów, gdy nie jest wymagany dostęp do specyficznej infrastruktury zewnętrznej. Używany często z podejściem "Zadanie w Kontenerze". | pool: vmImage: 'ubuntu-latest' (lub inne obrazy). |
| Agent Self-Hosted | Agent instalowany i zarządzany przez użytkownika na własnej infrastrukturze (fizycznej, wirtualnej, w kontenerze). | Gdy potok wymaga dostępu do zasobów lokalnych, specyficznego oprogramowania na hoście lub bezpośredniego wykonywania poleceń na zewnętrznym hoście Docker. Kluczowy dla podejścia "Wdrożenie na Zewnętrznym Hoście". | pool: name: 'MySelfHostedPoolName'. |
YAML: resources: containers: |
Definiuje alias, obraz i połączenie dla kontenera, który będzie używany do uruchamiania zadań. | W podejściu "Zadanie w Kontenerze". | resources: containers: - container: myalias ... |
YAML: job: container: |
Określa, że kroki danego zadania (job) mają być wykonane wewnątrz zdefiniowanego kontenera. | W podejściu "Zadanie w Kontenerze". | jobs: - job: MyJob container: myalias steps: ... |
Zadanie Docker@2 |
Wbudowane zadanie Azure DevOps do wykonywania typowych operacji Docker (build, push, run, login, logout). | Do standaryzacji operacji Docker w potoku. Może działać na agentach hostowanych i self-hosted. | - task: Docker@2 inputs: command: 'buildAndPush' ... |
Krok script: |
Umożliwia wykonywanie dowolnych poleceń powłoki (bash, PowerShell, cmd). | Do elastycznego wykonywania poleceń, w tym docker pull, docker run, docker compose itp., zwłaszcza na agentach self-hosted. |
- script: 'docker run hello-world' |
Najlepsze Praktyki i Uwagi
- Bezpieczeństwo: Zawsze używaj połączeń usług do zarządzania poświadczeniami. Unikaj umieszczania haseł i tokenów bezpośrednio w pliku YAML. Rozważ użycie Azure Key Vault do przechowywania sekretów. Zabezpiecz dostęp do demona Docker na zewnętrznym hoście za pomocą TLS, jeśli łączysz się zdalnie bez agenta.
- Zarządzanie Agentami Self-Hosted: Regularnie aktualizuj agentów self-hosted. Monitoruj ich stan i zasoby (CPU, pamięć, dysk). Rozważ uruchamianie agentów w kontenerach dla lepszej izolacji i zarządzania.
- Sieć: Upewnij się, że agent (hostowany lub self-hosted) ma dostęp sieciowy do rejestru kontenerów. Jeśli używasz agenta self-hosted na zewnętrznym hoście, upewnij się, że może on komunikować się z usługą Azure DevOps (wymagane porty i adresy URL są w dokumentacji Microsoft). Skonfiguruj firewalle odpowiednio.
- Idempotentność: Projektuj kroki wdrożenia tak, aby były idempotentne – wielokrotne uruchomienie tego samego kroku powinno dawać ten sam rezultat (np. używaj
docker stopidocker rmprzeddocker run). - Docker Compose: Jeśli Twoja aplikacja składa się z wielu kontenerów, możesz użyć
docker-composena agencie self-hosted. Wykonaj poleceniadocker-compose pull,docker-compose up -ditp. w krokuscript.
Często Zadawane Pytania (FAQ)
Co to jest Połączenie Usługi (Service Connection) w Azure DevOps?
Połączenie Usługi to mechanizm w Azure DevOps, który pozwala na bezpieczne przechowywanie i zarządzanie poświadczeniami (takimi jak klucze API, hasła, certyfikaty, tokeny) potrzebnymi do łączenia się z zewnętrznymi usługami z poziomu potoków. Przykłady obejmują połączenia do Azure, rejestrów Docker, repozytoriów kodu (GitHub, Bitbucket), serwerów SSH i wielu innych. Użycie połączeń usług jest bezpieczniejsze niż przechowywanie wrażliwych danych bezpośrednio w skryptach potoku.
Kiedy powinienem użyć agenta self-hosted zamiast agenta hostowanego przez Microsoft?
Agenta self-hosted należy użyć, gdy:
- Potrzebujesz zainstalować niestandardowe oprogramowanie lub narzędzia, które nie są dostępne na agentach hostowanych przez Microsoft.
- Twój potok musi mieć dostęp do zasobów w Twojej sieci prywatnej (np. baz danych, serwerów wewnętrznych).
- Chcesz mieć pełną kontrolę nad środowiskiem budowania/wdrażania, w tym konfiguracją sprzętową i systemem operacyjnym.
- Musisz wdrożyć aplikację lub wykonać operacje bezpośrednio na konkretnym zewnętrznym hoście (jak w scenariuszu wdrażania kontenera Docker na zewnętrznym serwerze).
- Chcesz uniknąć limitów czasowych lub kosztów związanych z agentami hostowanymi przez Microsoft dla dużych lub długotrwałych zadań.
Agenci hostowani przez Microsoft są wygodni dla standardowych zadań budowania i testowania w chmurze, gdy nie ma specyficznych wymagań dotyczących środowiska lub dostępu do zasobów prywatnych.
Jak zabezpieczyć połączenie z moim zewnętrznym hostem Docker?
Najbezpieczniejszym i zalecanym sposobem interakcji z zewnętrznym hostem Docker jest użycie agenta self-hosted zainstalowanego na tym hoście. Komunikacja między agentem a Azure DevOps jest szyfrowana (HTTPS). Agent wykonuje polecenia Docker lokalnie na hoście, eliminując potrzebę otwierania portu demona Docker na zewnątrz.
Jeśli musisz użyć bezpośredniego połączenia zdalnego (np. przez Docker Host Service Connection lub docker --host tcp://...):
- Używaj TLS: Skonfiguruj demona Docker na hoście do używania szyfrowania TLS. Wymaga to wygenerowania certyfikatów CA, serwera i klienta. Klient Docker (w potoku) będzie musiał używać tych certyfikatów do bezpiecznego połączenia.
- Ogranicz Dostęp Sieciowy: Użyj reguł firewalla, aby zezwolić na dostęp do portu demona Docker (domyślnie 2376 dla TLS) tylko z zaufanych adresów IP (np. adresów IP agentów Azure DevOps, jeśli używasz hostowanych).
- Unikaj Portu Nieszyfrowanego: Nie używaj nieszyfrowanego portu TCP (domyślnie 2375) w środowiskach produkcyjnych lub niezaufanych sieciach.
Generalnie, agent self-hosted jest preferowanym rozwiązaniem ze względu na prostszą i bezpieczniejszą konfigurację.
Czy mogę używać Docker Compose w potoku Azure DevOps na zewnętrznym hoście?
Tak, możesz używać Docker Compose. Najprostszym sposobem jest zainstalowanie Docker Compose na zewnętrznym hoście, na którym działa agent self-hosted. Następnie w potoku możesz użyć kroku script do wykonania poleceń docker-compose:
steps:
- script: |
cd /path/to/your/compose/file # Przejdź do katalogu z plikiem docker-compose.yml
docker-compose pull # Pobierz najnowsze obrazy zdefiniowane w pliku compose
docker-compose up -d --remove-orphans # Uruchom/zaktualizuj usługi w tle i usuń osierocone kontenery
displayName: 'Deploy application using Docker Compose'
workingDirectory: '$(System.DefaultWorkingDirectory)' # Opcjonalnie, ustaw katalog roboczy
Upewnij się, że plik docker-compose.yml jest dostępny dla agenta (np. pobrany z repozytorium kodu w poprzednim kroku).
Co zrobić, jeśli mój zewnętrzny host jest za firewallem?
Jeśli używasz agenta self-hosted na hoście za firewallem, agent inicjuje połączenie wychodzące do usługi Azure DevOps (na porcie 443 HTTPS). Zazwyczaj ruch wychodzący na porcie 443 jest dozwolony w większości sieci. Musisz upewnić się, że agent może dotrzeć do adresów URL usług Azure DevOps (https://dev.azure.com/your_org, *.visualstudio.com itp.). Sprawdź dokumentację Microsoft dotyczącą dozwolonych adresów URL i zakresów IP.
Jeśli próbujesz połączyć się z demonem Docker bezpośrednio z agenta hostowanego przez Microsoft (lub innego agenta spoza sieci hosta), musisz:
- Skonfigurować reguły firewalla na zewnętrznym hoście, aby zezwalały na ruch przychodzący na porcie demona Docker (np. 2376 dla TLS) z adresów IP agentów Azure DevOps. Zakresy IP agentów Microsoft są publikowane.
- Upewnić się, że routing sieciowy pozwala na dotarcie do hosta z sieci, w której działa agent.
Ponownie, użycie agenta self-hosted jest generalnie prostsze w scenariuszach z firewallem, ponieważ wymaga tylko zezwolenia na ruch wychodzący.
Rekomendowane Zapytania
- Jak skonfigurować agenta self-hosted Azure DevOps w kontenerze Docker?
- Bezpieczne zarządzanie sekretami w potokach Azure DevOps przy użyciu Azure Key Vault.
- Jak używać Docker Compose w potoku wdrożeniowym Azure DevOps?
- Porównanie Azure Container Registry (ACR) i Docker Hub dla prywatnych obrazów.
Referencje
Last updated May 4, 2025