关于 deployment-stacks-2025
deployment-stacks-2025 是介绍 Azure Deployment Stacks 的参考技能,涵盖资源生命周期管理、保护、清理策略和运维操作,面向在资源组、订阅或管理组范围管理部署的 Azure 基础设施团队。
主要功能
- 01统一管理堆栈资源
- 02通过拒绝设置保护资源
- 03资源脱离管理时的处理策略
- 04资源组、订阅和管理组范围
- 05Azure CLI 与 Bicep 示例
适用场景
- 01防止生产资源被修改或删除
- 02清理从模板中移除的资源
- 03在不同 Azure 范围管理基础设施
- 04规划从 Azure 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>
适用场景:
- 不可变基础设施
- 合规要求
- 关键生产工作负载
排除的主体
允许特定身份绕过拒绝设置:
# 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
适用场景:
- 临时环境(开发、测试)
- 全新部署
- 严格执行基础设施即代码
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 迁移
评估
- 清点 Blueprints:列出所有蓝图和分配
- 记录参数:导出参数和配置
- 规划转换:将蓝图映射到 Deployment Stacks
- 在开发环境中测试:验证转换后的模板
转换步骤
# 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 基础设施生命周期管理的未来!