Kontenery usługi

Usługa Azure DevOps Services

Jeśli potok wymaga obsługi co najmniej jednej usługi, w wielu przypadkach należy utworzyć, nawiązać połączenie i wyczyścić każdą usługę dla poszczególnych zadań. Na przykład potok może uruchamiać testy integracji, które wymagają dostępu do bazy danych i pamięci podręcznej pamięci. Baza danych i pamięć podręczna muszą zostać nowo utworzone dla każdego zadania w potoku.

Kontener zapewnia prosty i przenośny sposób uruchamiania usługi, od której zależy potok. Kontener usługi umożliwia automatyczne tworzenie i łączenie z siecią cyklu życia usługi konteneryzowanej oraz zarządzanie nim. Każdy kontener usługi jest dostępny tylko dla zadań, które go wymagają. Kontenery usługi działają z dowolnym rodzajem zadań, ale są najczęściej używane z zadaniami kontenera.

Wymagania

Kontenery usługi muszą definiować element CMD lub ENTRYPOINT. Potok zostanie uruchomiony docker run dla podanego kontenera bez dodatkowych argumentów.

Usługa Azure Pipelines może uruchamiać kontenery systemu Linux lub Windows. Użyj hostowanego systemu Ubuntu dla kontenerów systemu Linux lub hostowanej puli kontenerów systemu Windows dla kontenerów systemu Windows. (Hostowana pula systemu macOS nie obsługuje uruchomionych kontenerów).

Jedno zadanie kontenera

Prosty przykład użycia zadań kontenera:

resources:
  containers:
  - container: my_container
    image: buildpack-deps:focal
  - container: nginx
    image: nginx


pool:
  vmImage: 'ubuntu-latest'

container: my_container
services:
  nginx: nginx

steps:
- script: |
    curl nginx
  displayName: Show that nginx is running

Ten potok pobiera nginx kontenery i buildpack-deps z Docker Hub, a następnie uruchamia kontenery. Kontenery są połączone w sieć, aby mogły się ze sobą łączyć według ich services nazwy.

Z poziomu tego kontenera nginx zadań nazwa hosta jest rozpoznawana jako poprawne usługi korzystające z sieci platformy Docker. Wszystkie kontenery w sieci automatycznie uwidaczniają sobie wszystkie porty.

Jedno zadanie

Kontenery usług można również używać bez kontenera zadań. Prosty przykład:

resources:
  containers:
  - container: nginx
    image: nginx
    ports:
    - 8080:80
    env:
      NGINX_PORT: 80
  - container: redis
    image: redis
    ports:
    - 6379

pool:
  vmImage: 'ubuntu-latest'

services:
  nginx: nginx
  redis: redis

steps:
- script: |
    curl localhost:8080
    echo $AGENT_SERVICES_REDIS_PORTS_6379

Ten potok uruchamia najnowsze nginx kontenery. Ponieważ zadanie nie jest uruchomione w kontenerze, nie ma automatycznego rozpoznawania nazw. W tym przykładzie pokazano, jak zamiast tego można uzyskać dostęp do usług przy użyciu polecenia localhost. W powyższym przykładzie jawnie udostępniamy port (na przykład 8080:80).

Alternatywną metodą jest dynamiczne przypisywanie losowego portu w czasie wykonywania. Następnie możesz uzyskać dostęp do tych portów dynamicznych przy użyciu zmiennych. W skryscie powłoki Bash można uzyskać dostęp do zmiennej przy użyciu środowiska przetwarzania. Te zmienne mają postać: agent.services.<serviceName>.ports.<port>. W powyższym przykładzie redis przypisano losowy dostępny port na hoście. Zmienna agent.services.redis.ports.6379 zawiera numer portu.

Wiele zadań

Kontenery usług są również przydatne do uruchamiania tych samych kroków w wielu wersjach tej samej usługi. W poniższym przykładzie te same kroki są wykonywane w wielu wersjach bazy danych PostgreSQL.

resources:
  containers:
  - container: my_container
    image: ubuntu:22.04
  - container: pg15
    image: postgres:15
  - container: pg14
    image: postgres:14

pool:
  vmImage: 'ubuntu-latest'

strategy:
  matrix:
    postgres15:
      postgresService: pg15
    postgres14:
      postgresService: pg14

container: my_container

services:
  postgres: $[ variables['postgresService'] ]
steps:
- script: printenv

Porty

Podczas określania zasobu kontenera lub kontenera wbudowanego można określić tablicę, która ma być uwidaczniana ports w kontenerze.

resources:
  containers:
  - container: my_service
    image: my_service:latest
    ports:
    - 8080:80
    - 5432

services:
  redis:
    image: redis
    ports:
    - 6379/tcp

Określenie ports nie jest wymagane, jeśli zadanie jest uruchomione w kontenerze, ponieważ kontenery w tej samej sieci platformy Docker automatycznie uwidaczniają wszystkie porty domyślnie.

Jeśli zadanie jest uruchomione na hoście, ports wymagane jest uzyskanie dostępu do usługi. Port przyjmuje formularz <hostPort>:<containerPort> lub tylko <containerPort>, z opcjonalnym /<protocol> na końcu, na przykład 6379/tcp uwidacznianym tcp za pośrednictwem portu 6379, powiązanym z losowym portem na maszynie hosta.

W przypadku portów powiązanych z losowym portem na maszynie hosta potok tworzy zmienną formularza agent.services.<serviceName>.ports.<port> , aby można było uzyskać do niego dostęp przez zadanie. Na przykład agent.services.redis.ports.6379 jest rozpoznawany losowo przypisany port na maszynie hosta.

Woluminy

Woluminy są przydatne do udostępniania danych między usługami lub do utrwalania danych między wieloma przebiegami zadania.

Instalację woluminu można określić jako tablicę volumes. Woluminy mogą mieć nazwę Woluminy platformy Docker, anonimowe woluminy platformy Docker lub powiązane instalacje na hoście.

services:
  my_service:
    image: myservice:latest
    volumes:
    - mydockervolume:/data/dir
    - /data/dir
    - /src/dir:/dst/dir

Woluminy mają postać <source>:<destinationPath>, gdzie <source> może być nazwanym woluminem lub ścieżką bezwzględną na maszynie hosta i <destinationPath> jest ścieżką bezwzględną w kontenerze.

Uwaga

Jeśli używasz naszych pul hostowanych, woluminy nie będą utrwalane między zadaniami, ponieważ maszyna hosta zostanie oczyszczona po zakończeniu zadania.

Inne opcje

Kontenery usługi współdzielą te same zasoby kontenera co zadania kontenera. Oznacza to, że można użyć tych samych opcji dodatkowych.

Sprawdzanie kondycji

Opcjonalnie, jeśli jakikolwiek kontener usługi określa HEALTHCHECK, agent czeka, aż kontener jest w dobrej kondycji przed uruchomieniem zadania.

Przykład wielu kontenerów z usługami

W tym przykładzie istnieje kontener internetowy Django Python połączony z dwoma kontenerami bazy danych — PostgreSQL i MySQL. Baza danych PostgreSQL jest podstawową bazą danych, a jej kontener ma nazwę db. Kontener db używa woluminu /data/db:/var/lib/postgresql/data i istnieją trzy zmienne bazy danych przekazywane do kontenera za pośrednictwem polecenia env. Kontener mysql używa portu 3306:3306 i istnieją również zmienne bazy danych przekazywane za pośrednictwem polecenia env. Kontener web jest otwarty za pomocą portu 8000. W krokach instalowane są zależności, pip a następnie test Django jest uruchamiany. Jeśli chcesz skonfigurować działający przykład, musisz skonfigurować witrynę Django z dwoma bazami danych. W tym przykładzie przyjęto założenie, że manage.py plik znajduje się w katalogu głównym, a projekt Django znajduje się w tym katalogu. Może być konieczne zaktualizowanie ścieżki /__w/1/s/ w pliku /__w/1/s/manage.py test.

resources:
  containers:
    - container: db
      image: postgres
      volumes:
          - '/data/db:/var/lib/postgresql/data'
      env:
        POSTGRES_DB: postgres
        POSTGRES_USER: postgres
        POSTGRES_PASSWORD: postgres
    - container: mysql
      image: 'mysql:5.7'
      ports:
         - '3306:3306'
      env:
        MYSQL_DATABASE: users
        MYSQL_USER: mysql
        MYSQL_PASSWORD: mysql
        MYSQL_ROOT_PASSWORD: mysql
    - container: web
      image: python
      volumes:
      - '/code'
      ports:
        - '8000:8000'

pool:
  vmImage: 'ubuntu-latest'

container: web
services:
  db: db
  mysql: mysql

steps:
    - script: |
        pip install django
        pip install psycopg2
        pip install mysqlclient
      displayName: set up django
    - script: |
          python /__w/1/s/manage.py test