Azure Developer CLI拡張の作り方|GA版azd Extension Frameworkの要件・機能・配布

Azure Developer CLI(azd)の Extension FrameworkはGAとなり、独自コマンド、ライフサイクル処理、デプロイ前の検証、MCPツールなどを、azd本体を改造せずに追加できる正式な拡張基盤になりました。

実務で重要なのは、単に拡張をインストールするだけではありません。拡張側のextension.yamlで機能と対応するazdバージョンを宣言し、利用するプロジェクト側のazure.yamlで必要な拡張とバージョン制約を管理します。さらに、用途に応じてOfficial、Private、Development、Nightlyの配布経路を使い分けます。

この仕組みを使えば、個人のローカルスクリプトとして管理していた処理を、複数プロジェクトで再利用できるチーム共通の開発ワークフローへ発展させられます。なお、GAになったのは拡張フレームワークであり、個々の拡張や機能にはPreviewのものが残る場合があります。(Microsoft for Developers)

目次

azd Extension FrameworkのGAで何が変わったのか

GA版では、拡張インターフェースの安定化に加え、プロジェクト単位の拡張要件、Semantic Versioningによるバージョン制約、複数の配布経路が整備されました。

変更点実務上の意味
拡張インターフェースの安定化プレビュー時代のAPI変更リスクを抑え、継続的に保守しやすくなった
プロジェクト単位の拡張要件リポジトリを取得した開発者やCI環境でも、必要な拡張を特定できる
バージョン制約拡張とazdの互換性をSemantic Versioningで管理できる
配布経路の拡大公式公開、社内限定、開発版、Nightly版を用途別に運用できる
統合ポイントの拡大Command、Lifecycle Hook、Validation Provider、MCP Toolなどを追加できる

GAは「将来、一切変更されない」という意味ではありません。破壊的変更はメジャーバージョン、後方互換のある機能追加はマイナーバージョンというように、バージョン管理を前提として運用することが重要です。MicrosoftはGAに向けて拡張インターフェースを安定化し、プロジェクトレベルの拡張要件や配布機能を追加しています。(Microsoft for Developers)

Azure Developer CLI拡張を使うべき場面

azdには、もともとazure.yamlへスクリプト形式のHookを記述する機能があります。そのため、すべての自動処理を拡張として実装する必要はありません。

判断項目azure.yamlのHookazd Extension
利用範囲原則として1つのリポジトリ複数プロジェクトや組織全体
実装形式PowerShell、Shell、Pythonなどのスクリプト独立した拡張プログラム
バージョン管理リポジトリのソース管理に依存拡張単位でSemVer管理
配布対象リポジトリへ同梱RegistryやBundleで配布
向いている処理単純なファイル生成、通知、初期化共通ポリシー、独自コマンド、Provider、MCP
更新方法リポジトリの更新azd extension updateなどで更新

たとえば、デプロイ後に1本のスクリプトを実行するだけなら、azure.yamlのHookで十分です。一方、すべてのプロジェクトでリソースタグを検査する、独自ホスティング先へデプロイする、AIエージェントから社内開発ツールを呼び出すといった用途は、拡張として切り出した方が管理しやすくなります。(Microsoft Learn)

azd拡張で追加できる主な機能

GA版のExtension Frameworkでは、次のようなCapabilityをextension.yamlへ宣言できます。

Capability追加できる機能活用例
custom-commands独自コマンドやコマンドグループazd guardrails check
lifecycle-eventsprovisionやdeploy前後の処理デプロイ前の設定確認
validation-providerazdの検証パイプラインへのルール追加命名規則、リージョン、タグの検査
mcp-serverAIエージェントから呼び出せるMCPツール構成確認、ログ調査、推奨設定の生成
service-target-provider新しいデプロイ先独自PaaSや社内基盤
framework-service-provider新しい言語やビルド方式未対応フレームワークのビルド
provisioning-provider独自のインフラプロビジョニングBicepやTerraform以外の仕組み
metadataヘルプやIntelliSense用メタデータコマンド説明や設定候補の表示

Capabilityは単なる分類ではありません。拡張が利用する権限や統合ポイントを明示する役割があり、必要なCapabilityを宣言していないと、対応するFramework Serviceの呼び出しが権限エラーになる場合があります。(Microsoft Learn)

Commandで独自のazdコマンドを追加する

custom-commandsを宣言すると、azd配下へ独自の名前空間とコマンドを追加できます。

たとえば、guardrailsという名前空間を作成した場合、次のような操作を提供できます。

azd guardrails check
azd guardrails report
azd guardrails fix

コマンドは単に外部プログラムを実行するだけではありません。azdのプロジェクト、環境、出力形式などのコンテキストを受け取り、既存の開発フローと統合できます。

公式SDKのazdext.NewExtensionRootCommandを使うと、--environmentや出力形式など、azd標準のフラグ処理を独自に作り直す必要がありません。(Microsoft Learn)

Lifecycle Hookでazdの処理に割り込む

lifecycle-eventsを宣言すると、azd provisionazd packageazd deployなどの処理前後に独自ロジックを実行できます。

代表的な利用例は次のとおりです。

  • preprovisionで必須設定やタグを確認する
  • postprovisionで作成されたリソース情報を外部システムへ登録する
  • prepackageでコード生成や依存関係の検査を行う
  • postdeployで疎通確認や通知を実行する

拡張側には、イベントを受け取るためのlistenコマンドが必要です。最新のテンプレートやSDKが提供するExtensionHostを利用し、イベントハンドラーを登録します。サービス単位のイベントでは、hostlanguageを条件にして対象を絞ることもできます。(Microsoft Learn)

Validation Providerでデプロイ前の検査を共通化する

validation-providerは、組織共通のガードレールを実装する場合に特に有効です。

たとえば、次のようなルールを拡張として配布できます。

  • 本番環境では許可されたAzureリージョンだけを利用する
  • 必須のリソースタグが設定されているか確認する
  • リソースグループ名が組織の命名規則に従っているか確認する
  • 公開エンドポイントや危険な構成を検出する
  • 本番環境へのデプロイ前に必要な環境変数を確認する

現行のFrameworkでは、Providerに依存せずプロビジョニング前に実行するprovisionチェックと、BicepのARMテンプレートやパラメーターを対象にするarm-provisionチェックを使い分けられます。

Terraformや拡張独自のProvisioning Providerにも適用したい検査はprovision、生成されたARMテンプレートの詳細まで調査したい検査はarm-provisionが適しています。(GitHub)

MCP ToolをAIエージェントへ公開する

mcp-serverを宣言すると、拡張の機能をModel Context Protocol経由でAIエージェントへ公開できます。

たとえば、次のようなMCP Toolを実装できます。

  • 現在のazdプロジェクト構成を説明する
  • Azureリソースに必要なタグを提案する
  • デプロイ前の問題点を一覧化する
  • ログや構成情報からトラブルの原因候補を返す
  • 組織標準に合うazure.yamlの設定を生成する

extension.yamlでは、Capabilityに加えて、MCPサーバーを起動する引数を指定できます。

capabilities:
  - custom-commands
  - mcp-server

mcp:
  serve:
    args:
      - mcp
      - start

拡張側ではmcp startコマンドを実装し、標準入出力でMCPクライアントと通信します。動作確認は、たとえば次のコマンドで行えます。

azd guardrails mcp start

MCP ToolからAzureを変更できるようにする場合は、参照専用と更新系のToolを分離し、対象サブスクリプション、環境、リソースグループを必ず検証してください。秘密情報をToolの戻り値やログへ含めないことも重要です。(Microsoft Learn)

Extension要件を管理する4つのバージョン指定

azd Extension Frameworkでは、似た名前のバージョン指定が複数あります。混同すると、インストールできない、意図しない最新版へ更新される、別の開発者環境で動かないといった問題が発生します。

設定場所プロパティ管理する対象
extension.yamlversion拡張そのもののバージョン
extension.yamlrequiredAzdVersionその拡張を実行できるazdのバージョン
azure.yamlrequiredVersions.azdプロジェクトが必要とするazdのバージョン
azure.yamlrequiredVersions.extensionsプロジェクトが必要とする拡張とバージョン

extension.yamlのrequiredAzdVersion

拡張が新しいSDKやFramework APIを利用している場合は、そのAPIを搭載したazdより古いバージョンで実行されないようにします。

version: 1.2.0
requiredAzdVersion: ">=1.30.0"

上記の数値は例です。実際には、拡張が使用するAPIを最初に搭載したazdバージョンに合わせます。

azdは拡張のインストールや更新時にrequiredAzdVersionを確認し、実行中のazdと互換性のない拡張バージョンを候補から除外します。互換性のあるバージョンが1つもない場合は、インストールに失敗します。(GitHub)

azure.yamlのrequiredVersions.extensions

利用するプロジェクトでは、必要な拡張をazure.yamlへ記述します。

name: contoso-webapp

requiredVersions:
  azd: ">=1.30.0"
  extensions:
    contoso.azd.guardrails: "^1.2.0"

この指定により、プロジェクトを利用する開発者は「別途この拡張を入れてください」と書かれたREADMEを探さなくても、必要なExtensionを把握できます。

requiredVersions.extensionsでは、次のようなSemVer制約を利用できます。

指定意味
1.2.31.2.3だけを利用
^1.2.31.2.3以上、2.0.0未満
~1.2.31.2.3以上、1.3.0未満
>=1.0.0,<2.0.0明示した範囲内
latest利用可能な最上位バージョン

複数のバージョンが条件を満たす場合、azdは条件内で最も高いバージョンを選択します。CLIのazd extension install --versionは、基本的に完全一致のバージョンかlatestを指定する点にも注意が必要です。プロジェクトファイルでは範囲指定、CIで明示的にインストールする場合は完全一致という使い分けが分かりやすいでしょう。(GitHub)

本番プロジェクトではlatestを避ける

latestは検証環境では便利ですが、本番運用では、同じコミットから異なる拡張バージョンが選ばれる可能性があります。

一般的には、次のように使い分けます。

  • ローカル試験ではlatest
  • 通常の開発では^1.2.0~1.2.0
  • 厳密な再現性が必要なCIでは1.2.3
  • メジャーバージョンをまたがせたくない場合は>=1.2.0,<2.0.0

Preview版を対象にする場合は、制約にもプレリリース識別子を含める必要があります。通常の>=0.1.0では、0.1.0-previewなどが対象にならない場合があります。(GitHub)

Azure Developer CLI拡張を作成する手順

ここでは、公式クイックスタートと同じくGoで拡張を作成します。

開発用Extensionをインストールする

拡張開発には、azd xコマンドを提供するmicrosoft.azd.extensionsを利用します。

azd version

azd extension install microsoft.azd.extensions

azd extension list --installed

azd x

azd xが実行できれば、拡張の初期化、ビルド、監視、パッケージ化、公開を行えます。(Microsoft Learn)

Gitリポジトリを作成する

azd x initは、拡張用フォルダーがGitで追跡されていることを前提とします。

mkdir azd-guardrails
cd azd-guardrails

git init
git commit --allow-empty -m "Initial commit"

azd x init

対話形式では、次のような情報を入力します。

項目入力例
Extension IDcontoso.azd.guardrails
Display nameContoso azd Guardrails
DescriptionValidate Azure project policies before deployment.
Namespaceguardrails
CapabilityCustom commands
LanguageGo

azd x initは、ソースコードの生成だけでなく、初期ビルド、パッケージ化、ローカルRegistryへの公開、ローカル環境へのインストールまで実行します。(Microsoft Learn)

生成されるファイルを確認する

代表的な構成は次のとおりです。

contoso.azd.guardrails/
├── bin/
├── build.ps1
├── build.sh
├── CHANGELOG.md
├── extension.yaml
├── main.go
├── go.mod
└── internal/

特に重要なのは次の3つです。

  • extension.yaml:ID、バージョン、Capability、利用例を定義する
  • main.go:拡張のエントリーポイント
  • CHANGELOG.md:リリース時の変更内容を管理する

Windows、Linux、macOS向けのビルド処理は、生成されたビルドスクリプトを基準に整備します。(Microsoft Learn)

extension.yamlを設定する

Command、Lifecycle Event、Validation Provider、MCP Serverを持つ拡張の例は次のとおりです。

# yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/refs/heads/main/cli/azd/extensions/extension.schema.json

id: contoso.azd.guardrails
namespace: guardrails
displayName: Contoso azd Guardrails
description: Validates project policies before provisioning and deployment.
usage: azd guardrails <command> [options]

version: 1.0.0
language: go
requiredAzdVersion: ">=1.30.0"

capabilities:
  - custom-commands
  - lifecycle-events
  - validation-provider
  - mcp-server

examples:
  - name: check
    description: Validates the current azd project.
    usage: azd guardrails check

tags:
  - governance
  - validation
  - mcp

mcp:
  serve:
    args:
      - mcp
      - start

最低限必要なのは、idversiondisplayNamedescriptionです。通常の拡張はcapabilitiesを宣言し、複数の拡張をまとめるExtension Packは代わりにdependenciesを宣言できます。(Microsoft Learn)

独自コマンドを実装する

internal/cmd/check.goなどにCobraコマンドを追加します。

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

func newCheckCommand() *cobra.Command {
    return &cobra.Command{
        Use:   "check",
        Short: "Validates the current azd project.",
        RunE: func(cmd *cobra.Command, args []string) error {
            fmt.Println("Project policy check passed.")
            return nil
        },
    }
}

ルートコマンド側で登録します。

rootCmd.AddCommand(newCheckCommand())

再ビルド後、次のように実行できます。

azd guardrails check

最初は文字列を表示するだけのコマンドで動作確認し、その後、azd SDKを使ったプロジェクト情報の取得やAzure APIの呼び出しを追加すると、問題の切り分けがしやすくなります。(Microsoft Learn)

Lifecycle Eventを登録する

Lifecycle Eventでは、ExtensionHostへハンドラーを登録します。

host := azdext.NewExtensionHost(azdClient).
    WithProjectEventHandler(
        "preprovision",
        func(ctx context.Context, args *azdext.ProjectEventArgs) error {
            fmt.Printf("Validating project: %s\n", args.Project.Name)

            // 必須タグや環境設定の検査を実装する
            return nil
        },
    )

Lifecycle Eventを受け取る拡張では、最新のSDKが提供するNewListenCommandNewExtensionHostを利用してください。古いプレビュー版サンプルで使われていたazdext.NewContext()は非推奨となっており、新規実装ではazdext.Runなどの新しいヘルパーが推奨されています。(GitHub)

Validation Providerを登録する

Providerに依存しないプロビジョニング前検査は、次のような形で登録します。

host := azdext.NewExtensionHost(azdClient).
    WithValidationCheck(azdext.ValidationCheckRegistration{
        CheckType: azdext.ValidationCheckTypeProvision,
        RuleID:    "required_tags",
        Factory: func() azdext.ValidationCheckProvider {
            return &RequiredTagsCheck{}
        },
    })

Rule IDは、ログやエラー内容から原因を追跡できる安定した名前にします。表示メッセージだけでなく、「どの項目が不足しているか」「どのファイルや設定を修正すべきか」まで返すと、CIでも利用しやすくなります。(GitHub)

ビルドとローカルテストを行う

開発中はazd x watchを使用すると、ソース変更後のビルドとローカルインストールを自動化できます。

azd x watch

別のターミナルでコマンドを実行します。

azd guardrails check

手動で実行する場合は、次のコマンドを利用します。

azd x build
azd x pack
azd x publish

すべての対象プラットフォーム向けにビルドするときは、次のようにします。

azd x build --all
azd x pack --rebuild

azd x watchは開発用、build --allpack --rebuildはリリース前の確認用と分けると、日常的な開発速度を落とさずに済みます。(Microsoft Learn)

azd Extensionの配布方法を選ぶ

GA版では、用途に応じた複数の配布方法を選択できます。

配布方法適した用途主な注意点
Official Registry安定した一般公開Extension審査、品質基準、リリース管理が必要
Private Registry社内ツールや限定配布Registryとアクセス制御を自分で管理する
Development RegistryPreview版や公開前検証未署名、サポート対象外、削除や破壊的変更の可能性
Nightly Registry最新ビルドの継続検証本番利用には向かない
Bundle一時的な評価、閉域、単発配布自動更新されず、配布元の信頼確認が必要

Official Registryはazdにあらかじめ登録されています。Private配布ではURLまたはファイルベースのRegistryを追加できます。DevelopmentとNightlyは明示的なオプトイン方式です。また、Registryを用意せずに単一のZIPファイルとして渡すBundleも利用できます。(Microsoft for Developers)

Private Registryで社内配布する

社内向けExtensionでは、独自のregistry.jsonをWebサーバーや社内の配布基盤へ配置します。

利用者側では、RegistryをSourceとして追加します。

azd extension source add \
  -n contoso \
  -t url \
  -l "https://example.com/azd/registry.json"

登録後、Sourceを明示してインストールします。

azd extension install contoso.azd.guardrails --source contoso

登録内容を確認するには、次のコマンドを使用します。

azd extension source list
azd extension show contoso.azd.guardrails --source contoso

Private Registryは、機密性の高い社内ロジックや、正式公開する予定のない組織固有のExtensionに適しています。Registryへアクセスする仕組み、配布物の署名、承認済みバージョンの管理は、組織側で設計する必要があります。(Microsoft Learn)

Development Registryを利用する

Development Registryは、Preview版、実験的なExtension、Official Registryへ昇格する前の検証に使います。

azd extension source add \
  -n dev \
  -t url \
  -l "https://aka.ms/azd/extensions/registry/dev"

インストール時はSourceを明示します。

azd extension install my.experimental.extension --source dev

Development RegistryのExtensionは未署名で、Azureサポートの対象外です。予告なく変更や削除が行われる可能性もあるため、本番環境の必須ワークフローへ直接組み込むのは避けます。(GitHub)

Nightly Registryを利用する

Nightly Registryは、最新コードから自動生成されたビルドを継続的に確認する用途に向いています。

azd extension source add \
  -n nightly \
  -t url \
  -l "https://raw.githubusercontent.com/Azure/azure-dev/nightly/cli/azd/extensions/registry.nightly.json"

Nightly版は、次期リリースによる互換性問題の早期発見や、自動テストでのスモークテストに使用します。開発者の通常環境へ常用させるより、専用の検証環境を分けた方が安全です。(GitHub)

Bundleで単発配布する

一時的な評価や、Registryを構築できない環境では、自己完結型Bundleを作成できます。

azd x pack --bundle

生成されたZIPファイルを受け取った利用者は、ファイルを直接インストールできます。

azd extension install ./contoso.azd.guardrails_1.0.0.zip

Bundleにはregistry.jsonと対象プラットフォーム向けArtifactが含まれます。ただし、インストール後に永続的なRegistry Sourceは残らず、azd extension updateによる自動更新も行われません。更新時は新しいBundleを再インストールします。

Bundle内のチェックサムは破損検出には役立ちますが、発行者本人であることまでは保証しません。信頼できる経路で受け取ったBundleだけをインストールしてください。(GitHub)

ExtensionをリリースしてRegistryへ公開する

GitHub ReleaseとRegistryを利用する場合、基本的な流れは次のとおりです。

azd x pack --rebuild

azd x release --repo contoso/azd-guardrails

azd x publish \
  --repo contoso/azd-guardrails \
  --registry ./registry.json

各コマンドの役割は次のように分かれています。

コマンド処理内容
azd x buildExtensionの実行ファイルをビルドする
azd x pack配布用Artifactを作成する
azd x releaseGitHub ReleaseへArtifactを登録する
azd x publishRegistryへバージョンとArtifact情報を追加する

リリース前には、extension.yamlversionCHANGELOG.mdを更新します。GitHubへReleaseを作成する場合は、GitHub CLIまたは適切な権限を持つTokenによる認証も必要です。

Official Registryへの掲載は、単にRegistryファイルをアップロードする操作ではありません。スキーマ、メタデータ、対象プラットフォーム、チェックサム、品質基準を満たしたうえで、所定の提出・レビュー手続きを通す必要があります。(GitHub)

CI/CDではExtensionを明示的にセットアップする

azure.yamlrequiredVersions.extensionsを書けば、ローカルの対話環境では不足しているExtensionのインストールを案内できます。

一方、CI/CDとして検出された環境では、自動インストールが無効になる場合があります。そのため、パイプラインのセットアップ処理でSource追加とExtensionインストールを明示する方が確実です。

azd extension source add \
  -n contoso \
  -t url \
  -l "https://example.com/azd/registry.json"

azd extension install \
  contoso.azd.guardrails \
  --version 1.2.3 \
  --source contoso

azd up --no-prompt

CIでは次の方針がおすすめです。

  • --versionで完全一致のバージョンを指定する
  • --sourceを常に明示する
  • Source追加をデプロイ前のBootstrap処理へ含める
  • Extensionのバージョンとチェックサムをログへ出力する
  • 更新は通常のデプロイと分離し、Pull Requestで確認する

複数のSourceに同じExtension IDが存在すると、対話環境では選択を求められ、非対話環境ではエラーになります。CIではSource名の明示が特に重要です。(GitHub)

失敗しやすいポイントと対処方法

症状主な原因対処
Extensionが見つからないSource未登録、IDの間違いazd extension source listazd extension showを確認
複数Sourceで見つかった同じIDが複数Registryに存在--sourceを指定
条件を満たすバージョンがないazure.yamlの制約が厳しすぎる公開済みバージョンを確認して制約を見直す
azdと互換性がないrequiredAzdVersionを満たしていないazdを更新するか対応Extensionを使用
更新した版が表示されないRegistryキャッシュが残っているキャッシュTTLを一時的に0にする
CIで自動インストールされないCIでは自動導入が抑止されるパイプライン内で明示的にインストール
Development版で警告が出る未署名の実験版を使用している検証環境だけで利用する

基本的な診断は、次の順番で行います。

azd extension source list

azd extension show contoso.azd.guardrails

azd extension list --installed

azd extension install \
  contoso.azd.guardrails \
  --source contoso

Registryの更新が反映されない場合、PowerShellでは次のようにキャッシュを無効化して確認できます。

$env:AZD_EXTENSION_CACHE_TTL = "0s"
azd extension show contoso.azd.guardrails

Bash系の環境では次のように実行します。

AZD_EXTENSION_CACHE_TTL=0s \
azd extension show contoso.azd.guardrails

バージョン制約を外して無理にインストールするより、azd extension showで公開バージョンとrequiredAzdVersionを確認し、互換性のある組み合わせへ修正する方が安全です。(GitHub)

実務ではPrivate Registryから段階的に公開する

新しいExtensionを最初からOfficial Registryへ出す必要はありません。次の順序で利用範囲を広げると、問題を早い段階で発見できます。

  1. azd x watchで開発者本人がローカル検証する
  2. Bundleで少人数へ渡して操作性を確認する
  3. Private Registryでチーム内の複数プロジェクトへ展開する
  4. azure.yamlへExtension要件とバージョン制約を追加する
  5. 公開前の機能はDevelopment Registryで検証する
  6. 安定後にOfficial Registryへの提出を検討する
  7. Nightly版は専用環境の継続テストだけに使用する

最初のExtensionでは、大規模な独自Provisioning Providerを作るより、「1つのCommand」または「1つのValidation Rule」から始めるのが現実的です。

たとえば、azd guardrails checkで必須タグと利用リージョンだけを検査し、安定した段階でpreprovisionへの自動統合やMCP Toolを追加します。機能追加はマイナーバージョン、互換性を壊す変更はメジャーバージョンとして管理すれば、利用プロジェクト側も安全に更新できます。

Azure Developer CLI拡張を実務へ導入する際は、まずGoテンプレートで最小構成を作成し、extension.yamlへCapabilityとrequiredAzdVersionを定義します。次に、利用プロジェクトのazure.yamlrequiredVersions.extensionsを追加し、Private RegistryまたはBundleでチーム内検証を始めてください。拡張の実装だけでなく、バージョン制約、配布元、更新方法までセットで設計することが、GA版Extension Frameworkを安定運用するためのポイントです。

この記事を書いた人

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

コメント

コメントする

目次