Definire i processi contenitore (YAML)

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

Per impostazione predefinita, i processi vengono eseguiti nel computer host in cui è installato l'agente. Questo è pratico e in genere adatto per i progetti che iniziano ad adottare Azure Pipelines. Nel corso del tempo, si potrebbe notare che si vuole un maggiore controllo sul contesto in cui vengono eseguite le attività. Le pipeline YAML offrono processi contenitore per questo livello di controllo.

Negli agenti Linux e Windows i processi possono essere eseguiti nell'host o in un contenitore. In macOS e Red Hat Enterprise Linux 6 i processi del contenitore non sono disponibili. I contenitori forniscono l'isolamento dall'host e consentono di aggiungere versioni specifiche di strumenti e dipendenze. I processi host richiedono meno installazione iniziale e infrastruttura da gestire.

I contenitori offrono un'astrazione leggera sul sistema operativo host. È possibile selezionare le versioni esatte dei sistemi operativi, degli strumenti e delle dipendenze richieste dalla compilazione. Quando si specifica un contenitore nella pipeline, l'agente recupera e avvia prima il contenitore. Ogni passaggio del processo verrà quindi eseguito all'interno del contenitore. Non è possibile avere contenitori annidati. I contenitori non sono supportati quando un agente è già in esecuzione all'interno di un contenitore.

Se è necessario un controllo granulare a livello di singolo passaggio, le destinazioni dei passaggi consentono di scegliere il contenitore o l'host per ogni passaggio.

Requisiti

Contenitori basati su Linux

Il sistema Azure Pipelines richiede alcuni aspetti nei contenitori basati su Linux:

  • Bash
  • basato su glibc
  • Può eseguire Node.js (fornito dall'agente)
  • Non definisce un oggetto ENTRYPOINT
  • USER ha accesso a groupadd e altri comandi di privilegi senza sudo

E nell'host dell'agente:

  • Verificare che Docker sia installato
  • L'agente deve disporre dell'autorizzazione per accedere al daemon Docker

Assicurarsi che ognuno di questi strumenti sia disponibile nel contenitore. Alcuni dei contenitori rimossi disponibili nell'hub Docker, in particolare quelli basati su Alpine Linux, non soddisfano questi requisiti minimi. I contenitori con un ENTRYPOINT oggetto potrebbero non funzionare, poiché Azure Pipelines sarà docker create un contenitore in attesa e docker exec una serie di comandi, che prevedono che il contenitore sia sempre operativo.

Nota

Per i contenitori Linux basati su Windows, Node.js deve essere preinstallato.

Contenitori di Windows

Azure Pipelines può anche eseguire contenitori Windows. È necessario Windows Server versione 1803 o successiva. Docker deve essere installato. Assicurarsi che l'agente di pipeline disponga dell'autorizzazione per accedere al daemon Docker.

Il contenitore windows deve supportare l'esecuzione di Node.js. Per eseguire Node non è necessario un contenitore Windows Nano Server di base.

Agenti ospitati

Solo windows-2019 le immagini e ubuntu-* supportano l'esecuzione di contenitori. L'immagine macOS non supporta l'esecuzione di contenitori.

Processo singolo

Un semplice esempio:

pool:
  vmImage: 'ubuntu-latest'

container: ubuntu:18.04

steps:
- script: printenv

Questo indica al sistema di recuperare l'immagine ubuntu contrassegnata 18.04 dall'hubDocker e quindi avviare il contenitore. Quando il printenv comando viene eseguito, verrà eseguito all'interno del ubuntu:18.04 contenitore.

Esempio di Windows:

pool:
  vmImage: 'windows-2019'

container: mcr.microsoft.com/windows/servercore:ltsc2019

steps:
- script: set

Nota

Windows richiede che la versione kernel dell'host e del contenitore corrisponda. Poiché questo esempio usa l'immagine di Windows 2019, useremo il 2019 tag per il contenitore.

Più processi

I contenitori sono utili anche per eseguire gli stessi passaggi in più processi. Nell'esempio seguente vengono eseguiti gli stessi passaggi in più versioni di Ubuntu Linux. E non è necessario menzionare la jobs parola chiave, poiché è presente solo un singolo processo definito.

pool:
  vmImage: 'ubuntu-latest'

strategy:
  matrix:
    ubuntu16:
      containerImage: ubuntu:16.04
    ubuntu18:
      containerImage: ubuntu:18.04
    ubuntu20:
      containerImage: ubuntu:20.04

container: $[ variables['containerImage'] ]

steps:
- script: printenv

Endpoint

I contenitori possono essere ospitati in registri diversi dai registri dell'hub Docker pubblico. Per ospitare un'immagine in Registro Azure Container o in un altro registro contenitori privato (incluso un registro dell'hub Docker privato), aggiungere una connessione al servizio al registro privato. È quindi possibile farvi riferimento in una specifica di contenitore:

container:
  image: registry:ubuntu1804
  endpoint: private_dockerhub_connection

steps:
- script: echo hello

oppure

container:
  image: myprivate.azurecr.io/windowsservercore:1803
  endpoint: my_acr_connection

steps:
- script: echo hello

Anche altri registri contenitori possono funzionare. Amazon ECR attualmente non funziona, poiché sono disponibili altri strumenti client necessari per convertire le credenziali AWS in un elemento che Docker può usare per l'autenticazione.

Nota

La build Red Hat Enterprise Linux 6 dell'agente non eseguirà il processo del contenitore. Scegliere un altro tipo di Linux, ad esempio Red Hat Enterprise Linux 7 o versione successiva.

Opzioni

Se è necessario controllare l'avvio del contenitore, è possibile specificare options.

container:
  image: ubuntu:18.04
  options: --hostname container-test --ip 192.168.0.1

steps:
- script: echo hello

L'esecuzione docker create --help consentirà di visualizzare l'elenco delle opzioni che possono essere passate alla chiamata a Docker. Non tutte queste opzioni sono supportate per l'uso con Azure DevOps. Controllare prima di tutto se è possibile usare una proprietà contenitore per raggiungere lo stesso obiettivo. Per altre informazioni, vedere resources.containers.container negli schemi YAML e nelle informazioni di riferimento sui docker create comandi.

Definizione di contenitore riutilizzabile

Nell'esempio seguente i contenitori vengono definiti nella sezione resources. Ogni contenitore viene quindi fatto riferimento in un secondo momento, facendo riferimento al relativo alias assegnato. In questo caso, la parola chiave viene elencata jobs in modo esplicito per maggiore chiarezza.

resources:
  containers:
  - container: u16
    image: ubuntu:16.04

  - container: u18
    image: ubuntu:18.04

  - container: u20
    image: ubuntu:20.04

jobs:
- job: RunInContainer
  pool:
    vmImage: 'ubuntu-latest'

  strategy:
    matrix:
      ubuntu16:
        containerResource: u16
      ubuntu18:
        containerResource: u18
      ubuntu20:
        containerResource: u20

  container: $[ variables['containerResource'] ]

  steps:
  - script: printenv

Contenitori non basati su glibc

L'agente di Azure Pipelines fornisce una copia di Node.js, necessaria per eseguire attività e script. Per scoprire la versione di Node.js per un agente ospitato, vedere Agenti ospitati da Microsoft. La versione di Node.js viene compilata in base al runtime C usato nel cloud ospitato, in genere glibc. Alcune varianti di Linux usano altri runtime C. Ad esempio, Alpine Linux usa musl.

Se si vuole usare un contenitore non basato su glibc come contenitore di processi, è necessario disporre alcuni elementi autonomamente. In primo luogo, è necessario fornire la propria copia di Node.js. In secondo luogo, è necessario aggiungere un'etichetta all'immagine che indica all'agente dove trovare il file binario Node.js. Infine, alpine non include altre dipendenze che Azure Pipelines dipende da: bash, sudo, che e groupadd.

Bring your own Node.js

L'utente è responsabile dell'aggiunta di un file binario Node al contenitore. Il nodo 14 è una scelta sicura. È possibile iniziare dall'immagine node:14-alpine .

Informazioni sull'agente su Node.js

L'agente leggerà un'etichetta contenitore "com.azure.dev.pipelines.handler.node.path". Se questa etichetta esiste, deve essere il percorso del file binario Node.js. Ad esempio, in un'immagine basata su node:10-alpineaggiungere questa riga al Dockerfile:

LABEL "com.azure.dev.pipelines.agent.handler.node.path"="/usr/local/bin/node"

Aggiungere i requisiti

Azure Pipelines presuppone un sistema basato su Bash con pacchetti di amministrazione comuni installati. Alpine Linux in particolare non include diversi pacchetti necessari. L'installazione di bash, sudoe shadow coprirà le esigenze di base.

RUN apk add bash sudo shadow

Se si dipende da qualsiasi attività predefinita o del Marketplace, sarà necessario specificare anche i file binari necessari.

Esempio completo di dockerfile

FROM node:10-alpine

RUN apk add --no-cache --virtual .pipeline-deps readline linux-pam \
  && apk add bash sudo shadow \
  && apk del .pipeline-deps

LABEL "com.azure.dev.pipelines.agent.handler.node.path"="/usr/local/bin/node"

CMD [ "node" ]

Più processi con pool di agenti in un singolo agente ospitato

Il processo contenitore usa l'agente host sottostante Docker config.json per l'autorizzazione del Registro immagini, che si disconnette alla fine dell'inizializzazione del contenitore del registro Docker. L'autorizzazione pull dell'immagine del Registro di sistema successiva potrebbe essere negata per l'autenticazione non autorizzata perché il file Docker config.json registrato nel sistema per l'autenticazione è già stato disconnesso da uno degli altri processi del contenitore in esecuzione in parallelo.

La soluzione consiste nell'impostare la variabile DOCKER_CONFIG di ambiente Docker specifica per ogni servizio del pool di agenti in esecuzione nell'agente ospitato. Esportare l'oggetto DOCKER_CONFIG nello script di runsvc.sh di ogni pool di agenti:

#insert anything to set up env when running as a service
export DOCKER_CONFIG=./.docker