日程Fit|「いつ空いてますか?」の往復はもう不要。候補日を選んでURLを送るだけ|登録不要|今すぐ無料で使う →

TerraformのCIでazd downがハングする原因と対処法|1.28.1で修正

Terraformを使うAzure Developer CLIプロジェクトで、CIからazd down --no-promptを実行すると処理が止まる、または「backend initialization required」で失敗する場合は、CI上のAzure Developer CLIを1.28.1以上へ更新してください。

Azure Developer CLI 1.28.1では、非対話環境でTerraformのバックエンドを自動初期化する処理が追加されました。また、--forceがない場合は削除プレビューを表示して正常終了し、--forceがある場合は確認なしでリソースを削除するよう修正されています。(GitHub)

実際にCIからリソースを削除する基本コマンドは、次のとおりです。

azd down --environment "$AZURE_ENV_NAME" --no-prompt --force

削除対象を確認するだけなら、--forceを付けません。

azd down --environment "$AZURE_ENV_NAME" --no-prompt

重要なのは、--no-prompt--forceは同じ意味ではないことです。--no-promptだけでは、Azure Developer CLI 1.28.1以降の非対話環境ではリソースが削除されません。

日程Fit。無料・登録不要。「いつ空いてる?」を、ひとつのリンクで。リンクを送って、○△×でかんたん日程調整。無料で日程を作る。
目次

azd downがCIで止まる問題はAzure Developer CLI 1.28.1で修正

Azure Developer CLI 1.28.1は、2026年7月22日付のリリースとして公開されました。このバージョンでは、Terraformベースのプロジェクトにおけるazd downについて、次の2つの問題が修正されています。

  • azd down --no-promptがCI/CDで入力待ちになり、ハングする
  • fresh agentでazd down --forceを実行すると、Terraformバックエンドの未初期化エラーになる

1.28.1での主な挙動は次のとおりです。

実行環境--force1.28.1での処理リソース削除
CIまたは--no-promptなしterraform init後に削除プレビューを表示して終了しない
CIまたは--no-promptありterraform init後に自動承認でdestroyを実行する
対話可能な端末なしTerraformの通常の確認プロンプトを表示回答による
対話可能な端末あり確認を省略してdestroyを実行する

非対話環境で--forceがない場合は、terraform plan -destroy -input=false相当の処理が実行されます。削除は行われず、警告を表示したうえで終了コード0を返します。--forceがある場合は、terraform destroy-auto-approveが追加されます。(GitHub)

なぜazd down –no-promptがCIでハングしていたのか

Terraform側の確認プロンプトが残っていた

修正前のAzure Developer CLIでは、azd down --no-promptを実行しても、内部ではTerraformのdestroy確認が完全には無効化されていませんでした。

Terraformのdestroyは、通常、実行前に削除確認を求めます。しかし、CI/CDではユーザーがキーボードから回答できるTTYがありません。そのため、Terraformが標準入力からの回答を待ち続け、パイプラインが終わらない状態になっていました。

つまり、問題は次のような構造です。

CIで azd down --no-prompt を実行
        ↓
azd自身は非対話モードになる
        ↓
Terraform destroyの確認入力は残る
        ↓
CIには回答するユーザーがいない
        ↓
標準入力待ちのままハング

元の不具合報告でも、azd down --no-promptがAzure DevOpsパイプライン上で停止し、--forceを併用しなければdestroyを進められない状況が説明されています。(GitHub)

–no-promptは削除の自動承認を意味しない

--no-promptは、Azure Developer CLIをプロンプトなしで実行するための共通オプションです。既存の設定値を使って処理し、自動的に解決できない入力や判断が残っている場合は失敗します。

一方、--forceは、リソース削除前の確認を不要にするオプションです。Microsoft Learnのコマンドリファレンスでも、両者は別のオプションとして定義されています。(Microsoft Learn)

オプション役割削除の許可
--no-prompt対話入力を使わずに実行するそれだけでは許可しない
--force削除確認を省略する許可する
--purge論理削除された対象も完全削除する対象によって実行

現在のAzure Developer CLIは、認識可能なCI/CD環境やAIエージェント環境では--no-promptを自動的に有効化します。ただし、独自のセルフホステッドランナーやカスタム実行環境では検出条件に依存するため、CI定義には明示的に--no-promptを記述した方が安全です。(Microsoft Learn)

fresh agentでbackend初期化エラーが発生していた理由

fresh agentとは、前回の実行結果や作業ディレクトリを引き継がない、新しいCIエージェントやコンテナを指します。

TerraformのstateファイルをAzure Storageなどのリモートバックエンドに保存していても、新しいエージェントではTerraformのローカル初期化情報が存在しません。そのため、destroyの前にterraform initを実行し、バックエンド設定を読み込む必要があります。

修正前のazd downは、fresh agent上でバックエンドを初期化しないままterraform outputterraform destroyへ進むことがありました。その結果、次のようなエラーになっていました。

backend initialization required

不具合報告では、回避策として先にazd provision --previewを実行し、Terraformを初期化する方法が使われていました。しかし、削除のためにプロビジョニングのプレビューを先行実行するのは、意図が分かりにくく、CIの処理も複雑になります。(GitHub)

Azure Developer CLI 1.28.1では、CI/CD環境または明示的な--no-promptモードを自動実行コンテキストとして判定し、destroyの前に次の初期化を行います。

terraform init -input=false

この初期化は、削除プレビューと--forceによる実削除の両方で実行されます。

destroy時のinitでは-upgradeが付かない

1.28.1の実装では、destroy前のterraform init-upgradeを付けません。

これは、リソースを削除するタイミングで新しいプロバイダーやモジュールを選択したり、.terraform.lock.hclを書き換えたりすることを避けるためです。削除処理では、プロビジョニング時に使った依存関係を可能な限り維持する設計になっています。

CIで.terraformディレクトリをキャッシュしていても、キャッシュの有無を正常動作の前提にするべきではありません。キャッシュは高速化には役立ちますが、バックエンド初期化は各実行で正しく行われる構成にします。

CIで削除対象だけを確認する方法

削除前にTerraformのdestroy planを確認する場合は、--forceを付けずに実行します。

azd version

azd down \
  --environment "$AZURE_ENV_NAME" \
  --no-prompt

Azure Developer CLI 1.28.1以降では、次の順番で処理されます。

  1. Terraformバックエンドを-input=falseで初期化する
  2. terraform plan -destroy -input=falseで削除プレビューを表示する
  3. リソースを削除していないことを警告する
  4. 終了コード0で処理を終了する

ここで注意したいのは、パイプラインが成功してもリソースは残っていることです。

1.28.1では、ハングやエラーを避けるため、削除しなかった場合でも正常終了します。そのため、CIの緑色の成功表示だけを見て「環境の削除が完了した」と判断してはいけません。

ログに次の趣旨の警告が出ていないか確認してください。

No resources were deleted
Re-run with --force to delete resources

また、この削除プレビューはterraform plan -destroyの結果をコンソールに表示するもので、実行用の保存済みplanとして後続ステージへ引き渡す仕組みではありません。プレビュー後にstateやリソースが変更された場合、実際のdestroy内容も変わる可能性があります。承認から削除までの時間はできるだけ短くするのが安全です。

CIから実際にAzureリソースを削除する方法

確認なしでリソースを削除する場合は、--no-prompt--forceを併用します。

azd down \
  --environment "$AZURE_ENV_NAME" \
  --no-prompt \
  --force

この組み合わせには、次の意味があります。

--no-prompt
  CIでユーザー入力を求めない

--force
  削除を承認し、Terraformに-auto-approveを渡す

1.28.1では、非対話環境の場合、バックエンド初期化後にterraform destroyが実行され、--forceに応じて-auto-approveが付加されます。

--forceだけでも、Azure Developer CLIがCI環境を正しく検出できれば非対話処理になります。しかし、環境検出に依存しないよう、CIでは次の形式を標準にするのがおすすめです。

azd down -e "$AZURE_ENV_NAME" --no-prompt --force

特に削除処理では、既定の環境に依存せず、--environmentまたは-eで対象環境を明示してください。環境名の指定漏れは、意図しない環境を削除する原因になります。

–purgeは必要な場合だけ追加する

Key Vaultなど、一部のAzureリソースは削除後も論理削除状態で保持されます。論理削除されたリソースまで完全に削除する場合は、--purgeを追加します。

azd down \
  --environment "$AZURE_ENV_NAME" \
  --no-prompt \
  --force \
  --purge

Microsoft Learnでは、--purgeは、既定で論理削除されるリソースを完全削除するためのオプションとして説明されています。(Microsoft Learn)

ただし、--purgeには次のリスクがあります。

  • 削除後の復旧ができなくなる
  • 同名リソースの再作成条件に影響することがある
  • Key Vault内のシークレットや証明書も復元できなくなる可能性がある
  • 誤った環境を指定した場合の被害が大きくなる

一時的な検証環境を完全に消す必要がある場合など、目的が明確なときだけ使用してください。本番環境や共有環境の削除処理には、通常の--forceとは別の承認を設ける方が安全です。

GitHub Actionsでazd downを実行する例

次は、Azure Developer CLIのインストール、Azure認証、対象環境の準備が完了していることを前提にした削除ステップの例です。

- name: Destroy Azure environment
  timeout-minutes: 30
  shell: bash
  env:
    AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
  run: |
    set -euo pipefail

    azd version
    azd down \
      --environment "$AZURE_ENV_NAME" \
      --no-prompt \
      --force

削除ジョブには、GitHub Environmentsなどの承認機能を設定し、プルリクエストの作成だけで自動削除されないようにします。

実務では、次のようにステージを分けると安全です。

destroy-preview
  azd down --no-prompt
        ↓
削除対象をログで確認
        ↓
環境保護ルールによる承認
        ↓
destroy
  azd down --no-prompt --force

プレビュー用ジョブと削除用ジョブが別のfresh agentで動いても、1.28.1では削除側でバックエンド初期化が行われます。ただし、Azure認証情報、azdの環境情報、Terraformバックエンドへアクセスする権限は、削除側のジョブにも必要です。

Azure Pipelinesでazd downを実行する例

Azure Pipelinesでは、削除ステップを次のように記述できます。

- bash: |
    set -euo pipefail

    azd version
    azd down \
      --environment "$(AZURE_ENV_NAME)" \
      --no-prompt \
      --force
  displayName: Destroy Azure environment
  timeoutInMinutes: 30

timeoutInMinutesは、不具合の根本解決ではありませんが、認証やネットワーク、Terraform state lockなど別の原因で処理が止まった場合に、エージェントを長時間占有することを防げます。

本番環境や共有検証環境では、Azure PipelinesのEnvironment承認や手動検証ステップを削除処理の直前に配置します。

Azure Developer CLIを1.28.1以上へ更新する

まず、パイプライン内で実際に使われているバージョンを確認します。

azd version

ローカル環境では、次のコマンドでstableチャネルの最新版へ更新できます。

azd update --channel stable
azd version

Azure Developer CLIには、最新版へ更新するazd updateコマンドと、現在のバージョンを表示するazd versionコマンドが用意されています。(Microsoft Learn)

CIでは、ジョブの途中で毎回azd updateを実行するより、次のいずれかでバージョンを管理する方が安定します。

  • azdをセットアップするステップで1.28.1以上を指定する
  • CI用コンテナイメージに1.28.1以上を組み込む
  • セルフホステッドエージェントのazdを更新する
  • パイプライン冒頭でazd versionをログへ出力する
  • 古いバージョンを検出したらジョブを失敗させる

セルフホステッドエージェントでは、複数のazdがPATH上に存在することがあります。更新したはずなのに古いバージョンが表示される場合は、実行ファイルの場所も確認します。

Linuxの場合は次を実行します。

which azd
azd version

PowerShellの場合は次を実行します。

Get-Command azd
azd version

1.28.1へ更新しても直らない場合の確認ポイント

azd downがまだハングする

まず、エラーが発生している同じジョブ、同じコンテナ内でazd versionを実行してください。

ローカルPCのazdを更新しても、CIエージェントのazdは更新されません。また、セットアップステップの後に別のコンテナへ切り替えている場合、そのコンテナ内では古いazdが使われることがあります。

詳細ログを確認する場合は、--debugを追加します。

azd down \
  --environment "$AZURE_ENV_NAME" \
  --no-prompt \
  --force \
  --debug

正常終了したのにリソースが残っている

--forceが付いているか確認してください。

azd down --no-prompt

1.28.1以降、このコマンドは削除プレビューとして動作します。終了コード0でも、削除完了を意味しません。

実際に削除する場合は次のようにします。

azd down --no-prompt --force

backend initialization requiredが続く

1.28.1以上なのにバックエンド初期化エラーが続く場合は、次を確認します。

確認項目内容
実際のazdバージョン同じジョブ内で1.28.1以上になっているか
実行ディレクトリazure.yamlがある正しいプロジェクトから実行しているか
環境名--environmentの値が正しいか
Azure認証TerraformバックエンドへアクセスできるIDで認証しているか
ネットワークStorage Accountやプライベートエンドポイントへ接続できるか
カスタムフックazdではなく独自スクリプトが直接Terraformを実行していないか
backend設定必要な環境変数や生成元ファイルが存在するか

1.28.1の修正は、適切なタイミングでterraform init -input=falseを実行するものです。バックエンドへのアクセス権限不足、ネットワーク遮断、誤ったbackend設定まで自動修復するわけではありません。

state lockエラーが発生する

「backend initialization required」ではなく、state lockの取得エラーが出ている場合は別の問題です。

同じ環境に対してazd provisionterraform apply、別のdestroyが同時実行されていないか確認してください。CIでは環境名単位で同時実行を制限し、同じTerraform stateを複数ジョブから変更しないようにします。

ロックの強制解除は、実行中のTerraform処理が存在しないことを確認してから行ってください。

1.28.1へ更新できない場合の暫定対応

Azure Developer CLI 1.28.1未満を使い続けなければならない場合は、destroy前にTerraformバックエンドの初期化を完了させる必要があります。

元の不具合報告では、次のようにazd provision --previewを先に実行して初期化する回避方法が使われていました。(GitHub)

azd provision \
  --preview \
  --environment "$AZURE_ENV_NAME" \
  --no-prompt

azd down \
  --environment "$AZURE_ENV_NAME" \
  --no-prompt \
  --force

ただし、これはあくまで暫定対応です。

azdのTerraform実行では、環境ごとのパラメーターファイルやバックエンド設定、Terraformデータディレクトリが使われます。独自にterraform initを追加する場合、azdと異なる作業ディレクトリやbackend設定で初期化しても解決しないことがあります。

恒久的には、CIで使用するAzure Developer CLIを1.28.1以上へ更新してください。

安全なCI削除処理にするためのチェックリスト

Terraform環境の削除をCIへ組み込む場合は、次の状態を目標にします。

  • azd versionで1.28.1以上を確認している
  • --environmentで削除対象を明示している
  • 非対話実行では--no-promptを明示している
  • 実削除ステージだけに--forceを付けている
  • --purgeは必要な環境に限定している
  • プレビューと実削除の間に承認を設けている
  • 本番環境の削除権限を通常のデプロイジョブから分離している
  • 同じTerraform stateへの並列実行を防いでいる
  • CIジョブにタイムアウトを設定している
  • fresh agentでも動くことを前提にしている
  • .terraformキャッシュを正常動作の前提にしていない

最初に行うべきことは、CIログへazd versionを出し、1.28.1以上であることを確認することです。そのうえで、確認だけならazd down --no-prompt、実際の削除ならazd down --no-prompt --forceを使い分けてください。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次