コンテナー ジョブを定義する (YAML)

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

既定では、エージェントがインストールされているホスト マシンでジョブが稼働します。 これは便利で、Azure Pipelines の導入を開始したばかりのプロジェクトに通常適しています。 時間の経過と共に、タスクを実行するコンテキストをより詳細に制御する必要がある場合があります。 YAML パイプラインはこのレベルの制御のためのコンテナー ジョブを提供します。

Linux エージェントと Windows エージェントでは、ジョブはホストまたはコンテナーで実行できます。 (macOS および Red Hat Enterprise Linux 6 では、コンテナー ジョブは使用できません。)コンテナーはホストからの分離を提供し、コンテナーにより特定のバージョンのツールと依存関係をピン留めできます。 ホスト ジョブでは、初期セットアップと管理するインフラストラクチャが少なくて済みます。

コンテナーを使用すると、ホスト オペレーティング システムと比べ軽量の抽象化を実現できます。 ビルドに必要な正確なバージョンのオペレーティング システム、ツール、依存関係を選択できます。 パイプラインでコンテナーを指定すると、エージェントは最初にコンテナーをフェッチして開始します。 その後、ジョブの各ステップがコンテナー内で稼働します。 入れ子になったコンテナーを使用することはできません。 エージェントがコンテナー内で既に稼働している場合、コンテナーはサポートされません。

個々のステップ レベルできめ細かな制御が必要な場合は、ステップ ターゲットを使用すると、各ステップのコンテナーまたはホストを選択できます。

必要条件

Linux ベースのコンテナー

Azure Pipelines システムの場合、Linux ベースのコンテナーで以下が必要です。

  • Bash
  • glibc ベース
  • (エージェントが提供する) Node.js を実行できる
  • ENTRYPOINT を定義しない
  • USERsudo を使用せずに groupadd とその他の特権コマンドにアクセスできる

また、エージェント ホストには以下が必要です。

  • Docker がインストールされている
  • エージェントには、Docker デーモンにアクセスするためのアクセス許可が必要

コンテナーにこれらのツールが用意されていることを確認します。 Docker Hub で使用できる一部の削除されたコンテナー (特に Alpine Linux に基づくコンテナー) は、これらの最小要件を満たしていません。 ENTRYPOINT を含むコンテナーは機能しない可能性があります。これは、Azure Pipelines が待機しているコンテナーに docker create を実行し、コンテナーが常に稼働していることを想定する一連のコマンドに docker exec を実行するためです。

注意

Windows ベースの Linux コンテナーの場合は、Node.js がプレインストールされている必要があります。

Windows コンテナー

Azure Pipelines は Windows コンテナーを実行することもできます。 Windows Server バージョン 1803 以降が必要です。 Docker をインストールする必要があります。 パイプライン エージェントに Docker デーモンにアクセスするためのアクセス許可があることを確認します。

Windows コンテナーは Node.js の実行をサポートする必要があります。 基本の Windows Nano Server コンテナーには、Node を実行するために必要な依存関係がありません。

ホステッド エージェント

windows-2019ubuntu-* のイメージのみがコンテナーの実行をサポートします。 macOS イメージはコンテナーの実行をサポートしません。

1 つのジョブ

単純な例を次に示します。

pool:
  vmImage: 'ubuntu-latest'

container: ubuntu:18.04

steps:
- script: printenv

この例では、Docker Hub からタグ付けされた ubuntu イメージ 18.04 をフェッチし、コンテナーを起動するようにシステムに指示します。 printenv コマンドを実行すると、ubuntu:18.04 コンテナー内で稼働します。

Windows の例:

pool:
  vmImage: 'windows-2019'

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

steps:
- script: set

注意

Windows では、ホストとコンテナーのカーネル バージョンが一致している必要があります。 この例では Windows 2019 イメージを使用するため、コンテナーには 2019 タグを使用します。

複数のジョブ

コンテナーは、複数のジョブで同じ手順を実行する場合にも役立ちます。 次の例では、同じ手順が複数のバージョンの Ubuntu Linux で稼働します。 (また、1 つのジョブしか定義されていないため、jobs キーワードをメンションする必要はありません。)

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

エンドポイント

コンテナーは、パブリック Docker Hub レジストリ以外のレジストリでホストできます。 Azure Container Registry または別のプライベート コンテナー レジストリ (プライベート Docker Hub レジストリを含む) でイメージをホストするには、プライベート レジストリにサービス接続を追加します。 その後、コンテナー仕様で参照できます。

container:
  image: registry:ubuntu1804
  endpoint: private_dockerhub_connection

steps:
- script: echo hello

または

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

steps:
- script: echo hello

他のコンテナー レジストリも機能する場合があります。 AWS の資格情報を Docker が認証に使用できる情報に変換するために必要な他のクライアント ツールがあるため、Amazon ECR は現在機能しません。

注意

エージェントの Red Hat Enterprise Linux 6 ビルドはコンテナー ジョブを実行しません。 Red Hat Enterprise Linux 7 以上など、別の Linux フレーバーを選択してください。

Options

コンテナーの起動を制御する必要がある場合は、options を指定できます。

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

steps:
- script: echo hello

docker create --help を実行すると、Docker 呼び出しに渡すことができるオプションの一覧が表示されます。 これらのオプションの一部が、Azure DevOps で動作するように保証されているわけではありません。 最初に、コンテナー プロパティを使用して同じ目標を達成できるかどうかを確認します。 詳細については、YAML スキーマresources.containers.containerdocker create コマンド リファレンスを参照してください。

再利用可能なコンテナー定義

次の例では、コンテナーは resources セクションで定義されます。 その後、割り当てられたエイリアスを参照することで、各コンテナーが参照されます。 (ここでは、わかりやすくするために jobs キーワードを明示的に表示します。)

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

glibc ベースでないコンテナー

Azure Pipelines エージェントは、タスクとスクリプトを実行するために必要な Node.js のコピーを提供します。 ホステッド エージェントの Node.js のバージョンについては、「Microsoft ホステッド エージェント」を参照してください。 Node.js のバージョンは、ホステッド クラウド (通常は glibc) で使用する C ランタイムに対してコンパイルされます。 Linux の一部のバリアントはその他の C ランタイムを使用します。 たとえば、Alpine Linux は musl を使用します。

glibc ベースでないコンテナーをジョブ コンテナーとして使用する場合は、独自にいくつかの要素を配置する必要があります。 まず、Node.js の独自のコピーを提供する必要があります。 次に、Node.js バイナリを検索する場所をエージェントに伝えるラベルをイメージに追加する必要があります。 最後に、stock Alpine には Azure Pipelines が依存する他の依存関係 (bash、sudo、which、groupadd) がありません。

独自の Node.js を提供する

コンテナーに Node バイナリを追加する必要があります。 Node 14 を選択するのが安全です。 node:14-alpine イメージから開始できます。

エージェントに Node.js について伝える

エージェントは、コンテナー ラベル "com.azure.dev.pipelines.handler.node.path" を読み取ります。 このラベルが存在する場合は、Node.js バイナリへのパスのはずです。 たとえば、node:10-alpine に基づくイメージで次の行を Dockerfile に追加します。

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

要件の追加

Azure Pipelines では、共通の管理パッケージがインストールされた Bash ベースのシステムを想定しています。 特に、Alpine Linux には必要なパッケージがいくつかありません。 bashsudoshadow をインストールすると、基本的なニーズをカバーできます。

RUN apk add bash sudo shadow

インボックスタ スクまたは Marketplace タスクに依存している場合は、必要なバイナリも提供する必要があります。

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" ]

1 つのホステッド エージェント上のエージェント プールに対する複数のジョブ

コンテナー ジョブでは、基になるホスト エージェント Docker config.json を使用してイメージ レジストリの承認を行います。これは、Docker レジストリ コンテナーの初期化が完了するとログアウトします。 認証のためにシステムに登録されている Docker config.json ファイルが並列で稼働している他のコンテナー ジョブのいずれかにより既にログアウトされているため、後続のレジストリ イメージのプルの承認が "承認されていない認証" のため拒否される可能性があります。

解決策は、ホステッド エージェントで稼働している各エージェント プール サービスに固有の Docker 環境変数 DOCKER_CONFIG を設定することです。 各エージェント プールの runsvc.sh スクリプトで DOCKER_CONFIG を エクスポートします。

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