mcpField
D
deployment-stacks-2025

deployment-stacks-2025

github.com/josiahsiegelクラウド・DevOps59153 回インストール19 週間前に更新
リポジトリ

deployment-stacks-2025 について

deployment-stacks-2025は、Azure Deployment Stacksのリファレンススキルです。リソースのライフサイクル管理、保護、クリーンアップ方針、運用を扱い、リソースグループ、サブスクリプション、管理グループの各スコープでデプロイを管理するAzureインフラチーム向けです。

主な機能

  1. 01スタック内リソースの一元管理
  2. 02拒否設定によるリソース保護
  3. 03管理対象から外す際のポリシー
  4. 04リソースグループ、サブスクリプション、管理グループのスコープ
  5. 05Azure CLIとBicepの例

活用シーン

  1. 01本番リソースの変更や削除を防ぐ
  2. 02テンプレートから除外したリソースを整理する
  3. 03異なるAzureスコープでインフラを管理する
  4. 04Azure Blueprintsからの移行を計画する

インストール

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

$npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill deployment-stacks-2025

インストール後、Claude Code で/deployment-stacks-2025を入力して読み込まれたか確認します。

同梱ファイルreferences/cicd-monitoring.md

詳細

Azure Deployment Stacks - 2025 GA の機能

Azure Deployment Stacks に関する完全なナレッジベースです。Azure Blueprints の後継機能であり、2024 年に GA となり、2025 年のベストプラクティスに対応しています。

概要

Azure Deployment Stacks は、Azure リソースのコレクションを単一のアトミックな単位として管理するリソースの種類です。統合されたライフサイクル管理、リソース保護、自動クリーンアップ機能を提供します。

主な機能

1. 統合されたリソース管理
  • 複数のリソースを単一のエンティティとして管理
  • スタック全体に対する更新、エクスポート、削除操作
  • 管理対象のすべてのリソースを一元的に追跡
  • 環境間で一貫したデプロイ
2. 拒否設定(リソース保護)

管理対象のリソースへの不正な変更を防止します。

  • None:制限なし(デフォルト)
  • DenyDelete:リソースの削除を防止
  • DenyWriteAndDelete:更新と削除を防止
3. ActionOnUnmanage(クリーンアップポリシー)

テンプレートに含まれなくなったリソースの処理を制御します。

  • detachAll:リソースをスタック管理から解除し、リソースは保持
  • deleteAll:テンプレートに含まれないリソースを削除
  • deleteResources:管理対象外のリソースを削除し、リソースグループは保持
4. 柔軟なスコープ

スタックを次のスコープにデプロイできます。

  • リソースグループのスコープ
  • サブスクリプションのスコープ
  • 管理グループのスコープ
5. Azure Blueprints の後継

Azure Blueprints は2026 年 7 月に非推奨となる予定です。推奨される後継機能は Deployment Stacks です。

前提条件

Azure CLI のバージョン
# Requires Azure CLI 2.61.0 or later
az version

# Upgrade if needed
az upgrade
Azure PowerShell のバージョン
# Requires Azure PowerShell 12.0.0 or later
Get-InstalledModule -Name Az
Update-Module -Name Az

Deployment Stacks の作成

サブスクリプションスコープのスタック
# Create deployment stack at subscription level
az stack sub create \
  --name MyProductionStack \
  --location eastus \
  --template-file main.bicep \
  --parameters @parameters.json \
  --deny-settings-mode DenyWriteAndDelete \
  --deny-settings-excluded-principals <devops-service-principal-id> <admin-group-id> \
  --action-on-unmanage deleteAll \
  --description "Production infrastructure managed by deployment stack" \
  --tags Environment=Production ManagedBy=DeploymentStack CostCenter=Engineering

# What-if analysis before deployment
az stack sub what-if \
  --name MyProductionStack \
  --location eastus \
  --template-file main.bicep \
  --parameters @parameters.json

# Create with confirmation prompt disabled
az stack sub create \
  --name MyDevStack \
  --location eastus \
  --template-file main.bicep \
  --deny-settings-mode None \
  --action-on-unmanage detachAll \
  --yes
リソースグループスコープのスタック
# Create resource group
az group create \
  --name MyRG \
  --location eastus \
  --tags Environment=Production

# Create deployment stack
az stack group create \
  --name MyAppStack \
  --resource-group MyRG \
  --template-file main.bicep \
  --parameters environment=production \
  --deny-settings-mode DenyDelete \
  --action-on-unmanage deleteAll \
  --description "Application infrastructure stack"
管理グループスコープのスタック
# Create stack at management group level
az stack mg create \
  --name MyEnterpriseStack \
  --management-group-id MyMgmtGroup \
  --location eastus \
  --template-file main.bicep \
  --deny-settings-mode DenyWriteAndDelete \
  --action-on-unmanage detachAll

Deployment Stack 用の Bicep テンプレート

本番環境用スタックテンプレート
// main.bicep
targetScope = 'subscription'

@description('Environment name')
@allowed([
  'dev'
  'staging'
  'production'
])
param environment string = 'production'

@description('Primary location')
param location string = 'eastus'

@description('Secondary location for geo-replication')
param secondaryLocation string = 'westus'

// Resource naming
var namingPrefix = 'myapp-${environment}'

// Resource Group for core infrastructure
resource coreRG 'Microsoft.Resources/resourceGroups@2024-03-01' = {
  name: '${namingPrefix}-core-rg'
  location: location
  tags: {
    Environment: environment
    ManagedBy: 'DeploymentStack'
    Purpose: 'Core Infrastructure'
  }
}

// Resource Group for data services
resource dataRG 'Microsoft.Resources/resourceGroups@2024-03-01' = {
  name: '${namingPrefix}-data-rg'
  location: location
  tags: {
    Environment: environment
    ManagedBy: 'DeploymentStack'
    Purpose: 'Data Services'
  }
}

// Log Analytics Workspace
module logAnalytics 'modules/log-analytics.bicep' = {
  name: 'logAnalyticsDeploy'
  scope: coreRG
  params: {
    name: '${namingPrefix}-logs'
    location: location
    retentionInDays: environment == 'production' ? 90 : 30
  }
}

// AKS Automatic Cluster
module aksCluster 'modules/aks-automatic.bicep' = {
  name: 'aksClusterDeploy'
  scope: coreRG
  params: {
    name: '${namingPrefix}-aks'
    location: location
    kubernetesVersion: '1.34'
    workspaceId: logAnalytics.outputs.workspaceId
    enableZoneRedundancy: environment == 'production'
  }
}

// Container Apps Environment
module containerEnv 'modules/container-env.bicep' = {
  name: 'containerEnvDeploy'
  scope: coreRG
  params: {
    name: '${namingPrefix}-containerenv'
    location: location
    workspaceId: logAnalytics.outputs.workspaceId
    zoneRedundant: environment == 'production'
  }
}

// Azure OpenAI
module openAI 'modules/openai.bicep' = {
  name: 'openAIDeploy'
  scope: dataRG
  params: {
    name: '${namingPrefix}-openai'
    location: location
    deployGPT5: environment == 'production'
  }
}

// Cosmos DB with geo-replication
module cosmosDB 'modules/cosmos-db.bicep' = {
  name: 'cosmosDBDeploy'
  scope: dataRG
  params: {
    name: '${namingPrefix}-cosmos'
    primaryLocation: location
    secondaryLocation: secondaryLocation
    enableAutomaticFailover: environment == 'production'
  }
}

// Key Vault
module keyVault 'modules/key-vault.bicep' = {
  name: 'keyVaultDeploy'
  scope: coreRG
  params: {
    name: '${namingPrefix}-kv'
    location: location
    enablePurgeProtection: environment == 'production'
  }
}

// Outputs
output aksClusterName string = aksCluster.outputs.clusterName
output containerEnvId string = containerEnv.outputs.environmentId
output openAIEndpoint string = openAI.outputs.endpoint
output cosmosDBEndpoint string = cosmosDB.outputs.endpoint
output keyVaultUri string = keyVault.outputs.vaultUri
AKS Automatic モジュール
// modules/aks-automatic.bicep
@description('Cluster name')
param name string

@description('Location')
param location string

@description('Kubernetes version')
param kubernetesVersion string = '1.34'

@description('Log Analytics workspace ID')
param workspaceId string

@description('Enable zone redundancy')
param enableZoneRedundancy bool = true

resource aksCluster 'Microsoft.ContainerService/managedClusters@2025-01-01' = {
  name: name
  location: location
  sku: {
    name: 'Automatic'
    tier: 'Standard'
  }
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    kubernetesVersion: kubernetesVersion
    dnsPrefix: '${name}-dns'
    enableRBAC: true
    aadProfile: {
      managed: true
      enableAzureRBAC: true
    }
    networkProfile: {
      networkPlugin: 'azure'
      networkPluginMode: 'overlay'
      networkDataplane: 'cilium'
      serviceCidr: '10.0.0.0/16'
      dnsServiceIP: '10.0.0.10'
    }
    autoScalerProfile: {
      'balance-similar-node-groups': 'true'
      expander: 'least-waste'
    }
    autoUpgradeProfile: {
      upgradeChannel: 'stable'
      nodeOSUpgradeChannel: 'NodeImage'
    }
    securityProfile: {
      defender: {
        securityMonitoring: {
          enabled: true
        }
      }
      workloadIdentity: {
        enabled: true
      }
    }
    oidcIssuerProfile: {
      enabled: true
    }
    addonProfiles: {
      omsagent: {
        enabled: true
        config: {
          logAnalyticsWorkspaceResourceID: workspaceId
        }
      }
      azurePolicy: {
        enabled: true
      }
    }
  }
  zones: enableZoneRedundancy ? ['1', '2', '3'] : null
}

output clusterName string = aksCluster.name
output clusterId string = aksCluster.id
output oidcIssuerUrl string = aksCluster.properties.oidcIssuerProfile.issuerUrl
output kubeletIdentity string = aksCluster.properties.identityProfile.kubeletidentity.objectId

Deployment Stacks の管理

スタックの更新
# Update with new template version
az stack sub update \
  --name MyProductionStack \
  --template-file main.bicep \
  --parameters @parameters.json \
  --action-on-unmanage deleteAll

# Update deny settings
az stack sub update \
  --name MyProductionStack \
  --deny-settings-mode DenyWriteAndDelete \
  --deny-settings-excluded-principals <new-principal-id>
スタックの詳細の表示
# Show stack information
az stack sub show \
  --name MyProductionStack \
  --output json

# List all stacks in subscription
az stack sub list --output table

# List stacks in resource group
az stack group list \
  --resource-group MyRG \
  --output table
スタックテンプレートのエクスポート
# Export template from deployed stack
az stack sub export \
  --name MyProductionStack \
  --output-file exported-stack.json

# Export and save parameters
az stack sub show \
  --name MyProductionStack \
  --query "parameters" \
  --output json > parameters-backup.json
スタックの削除
# Delete stack and all managed resources
az stack sub delete \
  --name MyProductionStack \
  --action-on-unmanage deleteAll \
  --yes

# Delete stack but keep resources
az stack sub delete \
  --name MyProductionStack \
  --action-on-unmanage detachAll \
  --yes

# Delete with confirmation prompt
az stack sub delete --name MyProductionStack

拒否設定の詳細

DenyDelete モード

削除を防止しますが、更新は許可します。

az stack sub create \
  --name MyStack \
  --location eastus \
  --template-file main.bicep \
  --deny-settings-mode DenyDelete \
  --deny-settings-excluded-principals \
    <emergency-access-principal-id> \
    <devops-service-principal-id>

使用例:

  • 本番データベースの保護
  • リソースの誤削除の防止
  • 構成の更新の許可
DenyWriteAndDelete モード

更新と削除の両方を防止します。

az stack sub create \
  --name MyStack \
  --location eastus \
  --template-file main.bicep \
  --deny-settings-mode DenyWriteAndDelete \
  --deny-settings-excluded-principals <break-glass-principal-id>

使用例:

  • 不変のインフラストラクチャ
  • コンプライアンス要件
  • 重要な本番ワークロード
除外するプリンシパル

特定の ID に対して拒否設定を回避します。

# Get principal IDs
SERVICE_PRINCIPAL_ID=$(az ad sp show --id <app-id> --query id -o tsv)
ADMIN_GROUP_ID=$(az ad group show --group "Cloud Admins" --query id -o tsv)

# Apply with exclusions
az stack sub create \
  --name MyStack \
  --location eastus \
  --template-file main.bicep \
  --deny-settings-mode DenyWriteAndDelete \
  --deny-settings-excluded-principals $SERVICE_PRINCIPAL_ID $ADMIN_GROUP_ID

ActionOnUnmanage ポリシー

detachAll

リソースはスタック管理から解除されますが、削除されません。

az stack sub create \
  --name MyStack \
  --location eastus \
  --template-file main.bicep \
  --action-on-unmanage detachAll

次の場合に使用します:

  • デプロイの変更をテストする
  • リソースを別のスタックに移行する
  • 一時的なスタック管理
deleteAll

管理対象外のリソースをすべて削除します。

az stack sub create \
  --name MyStack \
  --location eastus \
  --template-file main.bicep \
  --action-on-unmanage deleteAll

次の場合に使用します:

  • 一時的な環境(開発、テスト)
  • クリーンな状態からのデプロイ
  • 厳格な Infrastructure as Code の適用
deleteResources

リソースグループは保持し、リソースを削除します。

az stack sub create \
  --name MyStack \
  --location eastus \
  --template-file main.bicep \
  --action-on-unmanage deleteResources

Deployment Stacks の RBAC

組み込みロール

Azure Deployment Stack Contributor

  • Deployment Stacks を管理
  • 拒否割り当ての作成や削除は不可

Azure Deployment Stack Owner

  • スタックを完全に管理
  • 拒否割り当てを作成および削除可能
ロールの割り当て
# Assign Stack Contributor role
az role assignment create \
  --assignee <user-or-service-principal-id> \
  --role "Azure Deployment Stack Contributor" \
  --scope /subscriptions/<subscription-id>

# Assign Stack Owner role
az role assignment create \
  --assignee <admin-principal-id> \
  --role "Azure Deployment Stack Owner" \
  --scope /subscriptions/<subscription-id>

CI/CD、監視、監査

Deployment Stacks 用の GitHub Actions と Azure DevOps の詳細な CI/CD の例に加え、監視、監査クエリ、デプロイ履歴の確認、運用上の可観測性については、references/cicd-monitoring.md を参照してください。スタックのデプロイを本番環境向けに整備するときや、変更を監査するときに、この参照資料を読み込んでください。

Azure Blueprints からの移行

評価
  1. Blueprint の一覧作成:すべての Blueprint と割り当てを一覧にします
  2. パラメーターの文書化:パラメーターと構成をエクスポートします
  3. 変換の計画:Blueprint を Deployment Stacks に対応付けます
  4. 開発環境でのテスト:変換したテンプレートを検証します
変換手順
# 1. Export Blueprint as ARM template
# (Use Azure Portal or PowerShell)

# 2. Convert ARM to Bicep
az bicep decompile --file blueprint-template.json

# 3. Create Deployment Stack
az stack sub create \
  --name ConvertedFromBlueprint \
  --location eastus \
  --template-file converted.bicep \
  --parameters @blueprint-parameters.json \
  --deny-settings-mode DenyWriteAndDelete \
  --action-on-unmanage detachAll

# 4. Validate resources
az stack sub show --name ConvertedFromBlueprint

# 5. Delete Blueprint assignment (after validation)
# Remove-AzBlueprintAssignment -Name MyBlueprintAssignment

ベストプラクティス

✓ 新しいインフラストラクチャにはすべて Deployment Stacks を使用する ✓ デプロイ前に必ず what-if 分析を実行する ✓ 本番環境のスタックには DenyWriteAndDelete を使用する ✓ 拒否設定から緊急用プリンシパルを除外する ✓ スタックに Environment、CostCenter、Owner のタグを付ける ✓ 一時的な環境には deleteAll を使用する ✓ 移行シナリオには detachAll を使用する ✓ スタックのデプロイには CI/CD パイプラインを実装する ✓ アクティビティログでスタック操作を監視する ✓ スタックのアーキテクチャと依存関係を文書化する

トラブルシューティング

スタックの作成に失敗する
# Check deployment errors
az stack sub show \
  --name MyStack \
  --query "error" \
  --output json

# Validate template
az deployment sub validate \
  --location eastus \
  --template-file main.bicep \
  --parameters @parameters.json
拒否設定によって操作がブロックされる
# Check deny assignments
az role assignment list \
  --scope /subscriptions/<subscription-id> \
  --include-inherited \
  --query "[?type=='Microsoft.Authorization/denyAssignments']"

# Add principal to exclusions
az stack sub update \
  --name MyStack \
  --deny-settings-excluded-principals <new-principal-id>
リソースが削除されない
# Check action-on-unmanage setting
az stack sub show \
  --name MyStack \
  --query "actionOnUnmanage" \
  --output tsv

# Update to deleteAll
az stack sub update \
  --name MyStack \
  --action-on-unmanage deleteAll

参考資料

Deployment Stacks は、Azure インフラストラクチャのライフサイクル管理の未来です!

コメント