Azure Pipelines の Self Hosted Agent の使い方と注意点
Azure DevOps には CI/CD パイプラインを構築するための Azure Pipelines という機能があります。
Azure Pipelines は Microsoft が提供する CI/CD ツールで、GitHub Actions や Jenkins などと同様にビルドやデプロイの自動化を行うことができます。
Azure Pipelines ではデフォルトで Microsoft が提供するホストされたエージェント [1] を使うことになりますが、以下のようなケースでは問題が発生します。
- ビルド時間が長い
- ビルドに特殊な環境が必要
- プライベートなリソースにアクセスする必要がある
このような場合、自分でエージェントを用意して自前でホストする Self Hosted Agent を使うことができます。
この記事では Self Hosted Agent の使い所と注意点について紹介します。
Self Hosted Agent とは
Self Hosted Agent は Azure Pipelines のエージェントの一種で、自分で用意した仮想マシンや物理マシンを使ってビルドやデプロイのジョブを実行するためのエージェントです。
ホストされたエージェントと異なり、自前で用意したエージェントなので、以下のようなメリットがあります。
- キャッシュを使ってビルド時間を短縮できる
- 事前に必要な環境を用意できる
- プライベートなリソースにアクセスする環境を用意できる
ただし、Self Hosted Agent を使う場合は以下のような注意点があります。
- エージェントが自動で破棄されない
- サーバーの管理が必要
- セキュリティへの対応
これらの注意点を踏まえて、Self Hosted Agent を使うかどうかを検討する必要があります。
以下ではより具体的な使い方や注意点について紹介します。
Self Hosted Agent の立ち上げ方法
Self Hosted Agent を用意するには主に 2 つの方法があります。
- OS に直接インストールする
- Docker コンテナとして立ち上げる
OS に直接インストールする場合、ドキュメントの以下記述にある通り複数エージェントの利用時に問題が発生する可能性があります。
1 台のマシンに複数のエージェントをインストールできますが、1 台のマシンに 1 つのエージェントのみをインストールすることを強くお勧めします。 複数のエージェントをインストールすると、パフォーマンスやパイプラインの結果に悪影響が及ぶ可能性があります。
引用元: Azure Pipelines エージェント - Azure Pipelines | Microsoft Learn
そのため、基本的には Docker コンテナとして立ち上げるのが良いでしょう。
Docker コンテナとして立ち上げる場合は、以下のような手順で立ち上げることができます。
-
Self Hosted Agent 立ち上げスクリプトを用意
- スクリプトはドキュメント上で提供されているもの使用を推奨
Linux 用のスクリプト例 (start.sh)
```bash:start.sh #!/bin/bash set -e if [ -z "${AZP_URL}" ]; then echo 1>&2 "error: missing AZP_URL environment variable" exit 1 fi if [ -z "${AZP_TOKEN_FILE}" ]; then if [ -z "${AZP_TOKEN}" ]; then echo 1>&2 "error: missing AZP_TOKEN environment variable" exit 1 fi AZP_TOKEN_FILE="/azp/.token" echo -n "${AZP_TOKEN}" > "${AZP_TOKEN_FILE}" fi unset AZP_TOKEN if [ -n "${AZP_WORK}" ]; then mkdir -p "${AZP_WORK}" fi cleanup() { trap "" EXIT if [ -e ./config.sh ]; then print_header "Cleanup. Removing Azure Pipelines agent..." # If the agent has some running jobs, the configuration removal process will fail. # So, give it some time to finish the job. while true; do ./config.sh remove --unattended --auth "PAT" --token $(cat "${AZP_TOKEN_FILE}") && break echo "Retrying in 30 seconds..." sleep 30 done fi } print_header() { lightcyan="\033[1;36m" nocolor="\033[0m" echo -e "\n${lightcyan}$1${nocolor}\n" } # Let the agent ignore the token env variables export VSO_AGENT_IGNORE="AZP_TOKEN,AZP_TOKEN_FILE" print_header "1. Determining matching Azure Pipelines agent..." AZP_AGENT_PACKAGES=$(curl -LsS \ -u user:$(cat "${AZP_TOKEN_FILE}") \ -H "Accept:application/json;" \ "${AZP_URL}/_apis/distributedtask/packages/agent?platform=${TARGETARCH}&top=1") AZP_AGENT_PACKAGE_LATEST_URL=$(echo "${AZP_AGENT_PACKAGES}" | jq -r ".value[0].downloadUrl") if [ -z "${AZP_AGENT_PACKAGE_LATEST_URL}" -o "${AZP_AGENT_PACKAGE_LATEST_URL}" == "null" ]; then echo 1>&2 "error: could not determine a matching Azure Pipelines agent" echo 1>&2 "check that account "${AZP_URL}" is correct and the token is valid for that account" exit 1 fi print_header "2. Downloading and extracting Azure Pipelines agent..." curl -LsS "${AZP_AGENT_PACKAGE_LATEST_URL}" | tar -xz & wait $! source ./env.sh trap "cleanup; exit 0" EXIT trap "cleanup; exit 130" INT trap "cleanup; exit 143" TERM print_header "3. Configuring Azure Pipelines agent..." ./config.sh --unattended \ --agent "${AZP_AGENT_NAME:-$(hostname)}" \ --url "${AZP_URL}" \ --auth "PAT" \ --token $(cat "${AZP_TOKEN_FILE}") \ --pool "${AZP_POOL:-Default}" \ --work "${AZP_WORK:-_work}" \ --replace \ --acceptTeeEula & wait $! print_header "4. Running Azure Pipelines agent..." chmod +x ./run.sh # To be aware of TERM and INT signals call ./run.sh # Running it with the --once flag at the end will shut down the agent after the build is executed ./run.sh "$@" & wait $! ```
-
ENTRYPOINT
にエージェント立ち上げスクリプト(start.sh)の実行を指定した Dockerfile を用意FROM hoge-image # Setup environment # ... # Start the agent COPY path/to/start.sh ./ ENTRYPOINT ["./start.sh"]
-
Docker コンテナをビルドして立ち上げ
docker build -t self-hosted-agent . docker run -e AZP_URL="<Azure DevOps instance>" -e AZP_TOKEN="<Personal Access Token>" -e AZP_POOL="<Agent Pool Name>" -e AZP_AGENT_NAME="Docker Agent - Linux" --name "azp-agent-linux" azp-agent:linux
コンテナ立ち上げ時の各パラメータは以下の通りです
パラメータ | 意味 |
---|---|
AZP_URL |
Azure DevOps プロジェクトの URL |
AZP_TOKEN |
Agent Pools の Read & Manage が有効な Personal Access Token |
AZP_POOL |
エージェントを登録する Agent Pool 名、Project Settings/Pipelines/Agent pools で確認可能 |
AZP_AGENT_NAME |
エージェントの識別名称、任意につけて良い |
立ち上げに成功すれば、Azure DevOps の Project Settings/Pipelines/Agent pools
に登録されたエージェントが表示されるはずです。
Pipeline からの利用方法
Pipeline で利用する場合 YAML ファイルに以下のような記述を追加することで、指定した Agent Pool に登録されているエージェントが利用できます。
pool:
name: "<Agent Pool Name>"
Agent Pool には複数のエージェントが登録できるため、複数登録している場合は以下のようにエージェント名を指定することで特定のエージェントを利用することもできます。
pool:
name: "<Agent Pool Name>"
demands:
- Agent.Name -equals <Agent Name>
名前以外にも指定方法はいくつかありますので、詳しくは公式ドキュメントを参照してください。
利用するうえでの注意点
Self Hosted Agent は便利な半面、Microsoft がホストするエージェントとは異なる点も多いため、注意すべき点がいくつかあります。
私が利用した際に気をつけた点を以下にまとめます。
エージェント内にゴミを残さない
Microsoft 提供のエージェントを利用する場合、Pipeline の完了に伴いエージェントが破棄されるため、常にクリーンな状態で利用できます。
しかし Self Hosted Agent は実行完了後に環境が自動で破棄されることはありません。
これは、過去のビルド時に生成されたキャッシュなどが残り高速化に繋がる一方で、不要なファイルが残り続ける可能性があるため注意が必要です。
私が直面した問題としては、ビルドの成果物をアップロードするための中間ファイルにバージョン番号が含まれていた関係で、ビルドが完了するたびに新しいファイルが生成されていました。
これが積み重なるとディスク容量を圧迫するため、完了直前に中間ファイルを削除するようにしました。
セキュリティ対策
Self Hosted Agent は自前で用意したエージェントなので、セキュリティ対策も自前で行う必要があります。
幸いなことに Self Hosted Agent はサーバーではなくクライアントとして動作するため、外部からの攻撃に対して過度に警戒する必要はありませんが、以下のような対策は必要です。
- Personal Access Token など機密情報の管理
- 定期的なセキュリティパッチの適用
まとめ
簡単にですが Azure Pipelines の Self Hosted Agent について使い方と注意点について紹介しました。
Self Hosted Agent は Microsoft 提供のエージェントとは異なる点が多いため、利用する際には注意が必要ですが、特殊な環境やプライベートなリソースにアクセスする必要がある場合には非常に便利な機能です。
ユースケースによっては Self Hosted Agent を使うだけで簡単に問題が解決することもあるため、ぜひ活用してみてください。
-
エージェントとは、ビルドやデプロイのジョブを実行するための仮想マシンのことです。 ↩︎
Discussion