YAML パイプライン内のコンテナー ジョブ
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
この記事では、Azure Pipelines のコンテナー ジョブについて説明します。
既定では、Azure Pipelines jobs エージェントはインストールされているホスト マシン上で直接実行されます。 ホストされるエージェント ジョブは便利で、初期セットアップと保守のためのインフラストラクチャはほとんど必要なく、基本的なプロジェクトに適しています。
タスク コンテキストをより詳細に制御する場合は、コンテナーでジョブを定義して実行できます。 コンテナーは、ホストからの分離を実現する、ホスト オペレーティング システム上の軽量な抽象化です。 コンテナー内でジョブを実行する場合、ビルドに必要なオペレーティング システム、ツール、依存関係の正確なバージョンを選択できます。
Linux および Windows エージェント は、ホストまたはコンテナーでパイプライン ジョブを直接実行できます。 コンテナー ジョブは macOS では使用できません。
コンテナー ジョブの場合、エージェントは最初にコンテナーをフェッチして開始します。 その後、ジョブの各ステップがコンテナー内で稼働します。
個々のビルド ステップ レベルできめ細かな制御が必要な場合は、ステップ ターゲットを使用すると、各ステップのコンテナーまたはホストを選択できます。
前提条件
- YAML パイプラインを使用します。 クラシック パイプラインでは、コンテナー ジョブはサポートされていません。
- ホストされている Windows または Ubuntu エージェントを使用します。
windows-*
とubuntu-*
のエージェントのみがコンテナーの実行をサポートします。macos-*
エージェントは、コンテナーの実行をサポートしていません。 - エージェントはコンテナー ジョブ用に設定されています。
- Windows および Linux エージェントには Docker がインストールされていて、Docker デーモンにアクセスするためのアクセス許可が必要です。
- エージェントがコンテナー内で既に稼働している場合、コンテナーはサポートされません。 入れ子になったコンテナーを使用することはできません。
追加のコンテナー要件
Linux ベースのコンテナーには、次の要件があります。 回避策については、「Nonglibc ベースのコンテナー」を参照してください。
- Bash がインストールされている
- GNU C ライブラリ (glibc) ベース
ENTRYPOINT
なしsudo
を使用せずに、USER
やその他の特権コマンドへのアクセスをgroupadd
に提供する- (エージェントが提供する) Node.js を実行できる
Note
Windows ホスト上の Linux コンテナーには、Node.js が事前にインストールされている必要があります。
Docker Hub で利用できる一部の簡素化されたコンテナ、特に Alpine Linux ベースのコンテナは、これらの要件を満たしていません。 Azure Pipelines docker create
と docker exec
はコンテナーが常に稼働していることを想定しているため、ENTRYPOINT
を持つコンテナーが機能しない可能性があります。
単一ジョブの例
次の例では、1 つのジョブの Windows または Linux コンテナーを定義します。
次の簡単な例では、Linux コンテナーを定義します。
pool:
vmImage: 'ubuntu-latest'
container: ubuntu:18.04
steps:
- script: printenv
前の例では、Docker Hub からタグ付けされた ubuntu
イメージ 18.04
をフェッチし、コンテナーを起動するようにシステムに指示します。 printenv
コマンドは ubuntu:18.04
コンテナー内で実行されます。
複数のジョブ
コンテナーを使用して、複数のジョブで同じ手順を実行できます。 次の例では、同じ手順が複数のバージョンの 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
1 つのホステッド エージェント上のエージェント プールに対する複数のジョブ
コンテナー ジョブは、基になるホスト エージェントの Docker 構成ファイルを使用して、イメージ レジストリの承認を行います。 このファイルは、Docker レジストリ コンテナーの初期化の最後にサインアウトします。 並列で実行されている別のジョブが既に Docker 構成ファイルをサインアウトしているため、後続のコンテナー ジョブのレジストリ イメージ プルが unauthorized authentication
に対して拒否される可能性があります。
解決策は、ホステッド エージェントで稼働している各エージェント プールに固有の Docker 環境変数 DOCKER_CONFIG
を設定することです。 各エージェント プールの runsvc.sh スクリプトで DOCKER_CONFIG
をエクスポートします。
export DOCKER_CONFIG=./.docker
スタートアップ オプション
次の例のように、コンテナーの起動を制御する 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 で動作することが保証されているわけではありません。 最初に、container
プロパティを使用して同じ目標を達成できるかどうかを確認します。
詳細については、Azure DevOps YAML スキーマ リファレンスの docker create コマンド リファレンスと resources.containers.container 定義を参照してください。
再利用可能なコンテナー定義
次の例では、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
サービス エンドポイント
パブリック Docker Hub 以外のレジストリでコンテナーをホストできます。 Azure Container Registry または別のプライベート コンテナー レジストリ (プライベート Docker Hub レジストリを含む) でイメージをホストするには、サービス接続を追加してレジストリにアクセスします。 その後、コンテナー定義内のエンドポイントを参照できます。
プライベート Docker Hub 接続:
container:
image: registry:ubuntu1804
endpoint: private_dockerhub_connection
Azure Container Registry 接続:
container:
image: myprivate.azurecr.io/windowsservercore:1803
endpoint: my_acr_connection
Note
Azure Pipelines は Amazon Elastic Container Registry (ECR) のサービス接続を設定できません。Amazon ECR では、AWS 認証情報を Docker が認証に使用できるものに変換するための他のクライアント ツールが必要になるためです。
glibc ベースでないコンテナー
Azure Pipelines エージェントは、タスクとスクリプトを実行するために必要な Node.js のコピーを提供します。 ホステッド エージェントの Node.js のバージョンを確認するには、「Microsoft ホステッド エージェント」を参照してください。
Node.js のバージョンは、ホステッド クラウド (通常は glibc) で使用する C ランタイムに対してコンパイルされます。 Linux の一部のバリアントはその他の C ランタイムを使用します。 たとえば、Alpine Linux は musl を使用します。
glibc ベースではないのコンテナーを使用する場合は、次の手順を実行する必要があります。
- Node.js の独自のコピーを指定します。
- Node.js バイナリを検索する場所をエージェントに伝えるラベルをイメージに追加します。
- Azure Pipelines が依存するその他の依存関係 (
bash
、sudo
、which
、およびgroupadd
) を提供します。
独自の Node.js を提供する
glibc ベースでないコンテナーを使用する場合は、Node バイナリをコンテナーに追加する必要があります。 Node.js 18 を選択するのが安全です。 node:18-alpine
イメージから開始します。
エージェントに Node.js について伝える
エージェントは、コンテナー ラベル "com.azure.dev.pipelines.handler.node.path"
を読み取ります。 このラベルが存在する場合は、Node.js バイナリへのパスのはずです。
たとえば、node:18-alpine
に基づくイメージで次の行を Dockerfile に追加します。
LABEL "com.azure.dev.pipelines.agent.handler.node.path"="/usr/local/bin/node"
必要なパッケージを追加する
Azure Pipelines では、共通の管理パッケージがインストールされた Bash ベースのシステムを想定しています。 特に、Alpine Linux には必要なパッケージがいくつかありません。 bash
、sudo
、shadow
をインストールすると、基本的なニーズをカバーできます。
RUN apk add bash sudo shadow
インボックスタ スクまたは Marketplace タスクに依存している場合は、必要なバイナリも提供します。
完全な Dockerfile の例
FROM node:18-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" ]