Definir trabalhos de contêiner (YAML)

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

Por padrão, os trabalhos são executados no computador host em que o agente está instalado. Isso é prático e normalmente adequado para projetos que estão apenas começando a adotar o Azure Pipelines. Com o passar do tempo, você poderá concluir que deseja ter mais controle sobre o contexto em que suas tarefas são executadas. Os pipelines YAML oferecem trabalhos de contêiner para esse nível de controle.

Nos agentes do Linux e do Windows, os trabalhos podem ser executados no host ou em um contêiner. (No macOS e no Red Hat Enterprise Linux 6, os trabalhos de contêiner não estão disponíveis). Os contêineres fornecem isolamento do host e permitem fixar versões específicas de ferramentas e dependências. Os trabalhos de host exigem menos configuração inicial e infraestrutura para manter.

Os contêineres oferecem uma abstração leve sobre o sistema operacional host. Você pode selecionar as versões exatas de sistemas operacionais, ferramentas e dependências que o build requer. Quando você especificar um contêiner no seu pipeline, o agente buscará primeiro e iniciará o contêiner. Em seguida, cada etapa do trabalho será executada dentro do contêiner. Você não pode ter contêineres aninhados. Não há suporte para contêineres quando um agente já está em execução dentro de um contêiner.

Se você precisar de controle refinado no nível de etapa individual, os destinos das etapas permitirão que você escolha contêiner ou host de cada etapa.

Requisitos

Contêineres baseados em Linux

O sistema do Azure Pipelines exige algumas coisas nos contêineres baseados em Linux:

  • Bash
  • Baseado em glibc
  • Pode executar Node.js (que o agente fornece)
  • Não define um ENTRYPOINT
  • USER tem acesso a groupadd e outros comandos de privilégios sem sudo

E no host do agente:

  • Verifique se o Docker está instalado
  • O agente deve ter permissão para acessar o daemon do Docker

Verifique se o contêiner tem cada uma dessas ferramentas disponíveis. Alguns dos contêineres despojados disponíveis no Docker Hub, especialmente os baseados no Alpine Linux, não atendem a esses requisitos mínimos. Os contêineres com um ENTRYPOINT podem não funcionar, pois o Azure Pipelines terá docker create um contêiner aguardando e docker exec uma série de comandos, que esperam que o contêiner esteja sempre em funcionamento.

Observação

Para contêineres do Linux baseados no Windows, o Node.js deve ser pré-instalado.

Contêineres do Windows

O Azure Pipelines também pode executar os contêineres do Windows. Windows Server versão 1803 ou posterior é necessária. O Docker deve ser instalado. Verifique se o agente de pipelines tem permissão para acessar o daemon do Docker.

O contêiner do Windows deve dar suporte à execução do Node.js. Um contêiner base do Windows Nano Server não tem as dependências necessárias para executar o Node.

Agentes hospedados

Somente as imagens windows-2019 e ubuntu-* dão suporte à execução de contêineres. A imagem do macOS não dá suporte à execução de contêineres.

Trabalho único

Um exemplo simples:

pool:
  vmImage: 'ubuntu-latest'

container: ubuntu:18.04

steps:
- script: printenv

Isso informa ao sistema para buscar a ubuntu imagem marcada 18.04 do Docker Hub e, em seguida, iniciar o contêiner. Quando o comando printenv for executado, ele ocorrerá dentro do contêiner ubuntu:18.04.

Uma exemplo do Windows:

pool:
  vmImage: 'windows-2019'

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

steps:
- script: set

Observação

O Windows exige que a versão do kernel do host e do contêiner corresponda. Como este exemplo usa a imagem do Windows 2019, usaremos a marca 2019 para o contêiner.

Vários trabalhos

Os contêineres também são úteis para executar as mesmas etapas em vários trabalhos. No exemplo a seguir, as mesmas etapas são executadas em várias versões do Ubuntu Linux. (E não precisamos mencionar a palavra-chave jobs, pois há apenas um único trabalho definido.)

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

Pontos de extremidade

Os contêineres podem ser hospedados em registros diferentes dos registros públicos do Docker Hub. Para hospedar uma imagem no Registro de Contêiner do Azure ou em outro registro de contêiner privado (incluindo um registro privado do Docker Hub), adicione uma conexão de serviço ao registro privado. Em seguida, você poderá referenciá-lo em uma especificação de contêiner:

container:
  image: registry:ubuntu1804
  endpoint: private_dockerhub_connection

steps:
- script: echo hello

ou

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

steps:
- script: echo hello

Outros registros de contêiner também podem funcionar. No momento, o Amazon ECR não funciona, pois há outras ferramentas de cliente necessárias para converter as credenciais do AWS em algo que o Docker pode usar para autenticar.

Observação

O build do Red Hat Enterprise Linux 6 do agente não executará o trabalho de contêiner. Escolha outro tipo do Linux, como Red Hat Enterprise Linux 7 ou superior.

Opções

Se você precisar controlar a inicialização do contêiner, poderá especificar options.

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

steps:
- script: echo hello

A execução de docker create --help fornecerá a lista de opções que podem ser transmitidas para a chamada do Docker. Não há garantia de que todas essas opções funcionarão com o Azure DevOps. Verifique primeiro se você pode usar uma propriedade de contêiner para atingir o mesmo objetivo. Para obter mais informações, consulte resources.containers.container no esquema YAML e na referência do comandodocker create.

Definição de contêiner reutilizável

No exemplo a seguir, os contêineres são definidos na seção de recursos. Cada contêiner é referenciado posteriormente, referindo-se ao alias atribuído. (Aqui, listamos explicitamente a palavra-chave jobs para maior clareza.)

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

Contêineres não baseados em glibc

O agente do Azure Pipelines fornece uma cópia do Node.js, que é necessária para executar tarefas e scripts. Para descobrir a versão do Node.js para um agente hospedado, confira Agentes hospedados pela Microsoft. A versão do Node.js é compilada no runtime C que usamos em nossa nuvem hospedada, normalmente o glibc. Algumas variantes do Linux usam outros runtimes C. Por exemplo, o Alpine Linux usa musl.

Se você quiser usar um contêiner não baseado em glibc como contêiner de trabalho, precisará organizar algumas coisas por conta própria. Primeiro, você deve fornecer sua própria cópia do Node.js. Segundo, você deve adicionar um rótulo à sua imagem informando ao agente onde encontrar o binário do Node.js. Por fim, o Stock Alpine não vem com outras dependências das quais o Azure Pipelines depende: bash, sudo, which e groupadd.

Traga seu próprio Node.js

Você é responsável por adicionar um binário do Node ao seu contêiner. O Node 14 é uma opção segura. Você pode começar com a imagem node:14-alpine.

Conte ao agente sobre o Node.js

O agente lerá um rótulo de contêiner "com.azure.dev.pipelines.handler.node.path". Se esse rótulo existir, ele deverá ser o caminho para o binário do Node.js. Por exemplo, em uma imagem com base em node:10-alpine, adicione esta linha ao Dockerfile:

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

Adicionar requisitos

O Azure Pipelines pressupõe um sistema baseado em Bash com pacotes de administração comuns instalados. O Alpine Linux, em particular, não vem com vários dos pacotes necessários. A instalação de bash, sudo e shadow abrangerá as necessidades básicas.

RUN apk add bash sudo shadow

Se você depender de tarefas internas ou do Marketplace, também precisará fornecer os binários necessários.

Exemplo completo de um 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" ]

Vários trabalhos com pools de agentes em um único agente hospedado

O trabalho de contêiner usa o agente host subjacente Docker config.json para autorização do registro de imagem, que faz logoff no final da inicialização do contêiner do Registro do Docker. A autorização subsequente de pulls de imagem do registro pode ser negada devido a "autenticação não autorizada", pois o arquivo Docker config.json registrado no sistema para autenticação já foi registrado por um dos outros trabalhos de contêiner que estão sendo executados paralelamente.

A solução é definir a variável de ambiente do Docker DOCKER_CONFIG específica para cada serviço de pool de agentes em execução no agente hospedado. Exporte o DOCKER_CONFIG no script de runsvc.sh de cada pool de agentes:

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