
azd-deployment
by pascalvanderheiden
A list of re-useable agent skills I created for my own purpose.
SKILL.md
name: azd-deployment description: Expert guidance for deploying solutions to Azure using Azure Developer CLI (azd). Use this skill when implementing Infrastructure as Code with Bicep, configuring azure.yaml, deploying to Azure Static Web Apps, Azure Container Apps, Azure Functions, or any azd-compatible hosting. Covers managed identity configuration, RBAC role assignments, firewall rules, backend API linking, and integration with Microsoft Foundry for LLM models, Azure Database for PostgreSQL, Azure Storage, and Azure AI Search.
Azure Developer CLI (azd) Deployment
Comprehensive guidance for deploying applications to Azure using the Azure Developer CLI.
Quick Reference
# Initialize project
azd init
# Authenticate
azd auth login
# Provision and deploy
azd up
# Individual steps
azd provision # Create Azure resources
azd deploy # Deploy application code
# Environment management
azd env new <name>
azd env select <name>
azd env set <key> <value>
azd env get-values
Project Structure
Every azd project requires this structure:
project-root/
├── azure.yaml # Service definitions (required)
├── infra/ # Infrastructure as Code (required)
│ ├── main.bicep # Main entry point
│ ├── main.parameters.json
│ └── modules/ # Reusable Bicep modules
├── src/ # Application source code
│ ├── web/ # Frontend (Static Web App)
│ └── api/ # Backend (Container Apps)
├── .azure/ # Environment configs (auto-generated)
└── scripts/ # Deployment scripts (optional)
azure.yaml Configuration
Basic Structure
name: my-app
metadata:
template: my-app@1.0.0
services:
web:
project: ./src/web
language: js
host: staticwebapp
api:
project: ./src/api
language: python
host: containerapp
docker:
path: ./Dockerfile
context: ../
hooks:
postprovision:
posix:
shell: sh
run: ./scripts/post-provision.sh
Host Types
| Host | Description | Use Case |
|---|---|---|
staticwebapp | Azure Static Web Apps | Frontend SPAs, static sites |
containerapp | Azure Container Apps | APIs, microservices, background jobs |
appservice | Azure App Service | Traditional web apps |
function | Azure Functions | Event-driven, serverless |
aks | Azure Kubernetes Service | Complex container orchestration |
Infrastructure as Code (Bicep)
Main Entry Point
Create infra/main.bicep as the deployment entry point:
targetScope = 'subscription'
@minLength(1)
@maxLength(64)
@description('Environment name used for resource naming')
param environmentName string
@minLength(1)
@description('Primary location for all resources')
param location string
@description('Principal ID of the deploying user')
param principalId string = ''
var abbrs = loadJsonContent('./abbreviations.json')
var resourceToken = toLower(uniqueString(subscription().id, environmentName, location))
var tags = { 'azd-env-name': environmentName }
resource rg 'Microsoft.Resources/resourceGroups@2022-09-01' = {
name: 'rg-${environmentName}'
location: location
tags: tags
}
module resources './resources.bicep' = {
name: 'resources'
scope: rg
params: {
location: location
environmentName: environmentName
resourceToken: resourceToken
tags: tags
principalId: principalId
}
}
output AZURE_RESOURCE_GROUP string = rg.name
output AZURE_LOCATION string = location
output API_URI string = resources.outputs.apiUri
output WEB_URI string = resources.outputs.webUri
System-Assigned Managed Identity Pattern
Always use System-Assigned Managed Identity with RBAC:
// Container App with System-Assigned Identity
resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
name: 'ca-${resourceToken}'
location: location
tags: union(tags, { 'azd-service-name': 'api' })
identity: {
type: 'SystemAssigned'
}
properties: {
managedEnvironmentId: containerAppEnv.id
configuration: {
ingress: {
external: true
targetPort: 8000
transport: 'http'
}
}
template: {
containers: [
{
name: 'api'
image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
resources: {
cpu: json('0.5')
memory: '1Gi'
}
env: [
{ name: 'AZURE_CLIENT_ID', value: '' } // Uses system identity
]
}
]
}
}
}
RBAC Role Assignments
Assign roles to managed identities (never use connection strings):
// Role definitions
var roles = {
storageBlobDataContributor: 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'
cognitiveServicesOpenAIUser: '5e0bd9bd-7b93-4f28-af87-19fc36ad61bd'
searchIndexDataContributor: '8ebe5a00-799e-43f5-93ac-243d3dce84a7'
keyVaultSecretsUser: '4633458b-17de-408a-b874-0445c86b69e6'
}
// Storage Blob Data Contributor for Container App
resource storageBlobRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storageAccount.id, containerApp.id, roles.storageBlobDataContributor)
scope: storageAccount
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roles.storageBlobDataContributor)
principalId: containerApp.identity.principalId
principalType: 'ServicePrincipal'
}
}
// Azure OpenAI User for Container App
resource openAIRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(openAIAccount.id, containerApp.id, roles.cognitiveServicesOpenAIUser)
scope: openAIAccount
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roles.cognitiveServicesOpenAIUser)
principalId: containerApp.identity.principalId
principalType: 'ServicePrincipal'
}
}
// AI Search Index Data Contributor
resource searchRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(searchService.id, containerApp.id, roles.searchIndexDataContributor)
scope: searchService
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roles.searchIndexDataContributor)
principalId: containerApp.identity.principalId
principalType: 'ServicePrincipal'
}
}
Firewall Configuration
Configure network security for PostgreSQL and Storage:
// PostgreSQL Flexible Server with firewall rules
resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2023-12-01-preview' = {
name: 'psql-${resourceToken}'
location: location
tags: tags
sku: {
name: 'Standard_B1ms'
tier: 'Burstable'
}
properties: {
version: '16'
administratorLogin: 'pgadmin'
administratorLoginPassword: postgresPassword
storage: { storageSizeGB: 32 }
backup: { backupRetentionDays: 7, geoRedundantBackup: 'Disabled' }
highAvailability: { mode: 'Disabled' }
}
}
// Allow Azure services to access PostgreSQL
resource postgresFirewallAzure 'Microsoft.DBforPostgreSQL/flexibleServers/firewallRules@2023-12-01-preview' = {
parent: postgresServer
name: 'AllowAzureServices'
properties: {
startIpAddress: '0.0.0.0'
endIpAddress: '0.0.0.0'
}
}
// Storage Account with network rules
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: 'st${resourceToken}'
location: location
tags: tags
kind: 'StorageV2'
sku: { name: 'Standard_LRS' }
properties: {
allowBlobPublicAccess: false
minimumTlsVersion: 'TLS1_2'
networkAcls: {
defaultAction: 'Deny'
bypass: 'AzureServices'
virtualNetworkRules: []
ipRules: []
}
}
}
Static Web App with Backend Linking
Link Container Apps as backend API in Static Web Apps:
// Static Web App
resource staticWebApp 'Microsoft.Web/staticSites@2023-12-01' = {
name: 'stapp-${resourceToken}'
location: staticWebAppLocation
tags: union(tags, { 'azd-service-name': 'web' })
sku: { name: 'Standard', tier: 'Standard' }
properties: {
stagingEnvironmentPolicy: 'Enabled'
allowConfigFileUpdates: true
enterpriseGradeCdnStatus: 'Disabled'
}
}
// Link Container App as backend
resource staticWebAppBackend 'Microsoft.Web/staticSites/linkedBackends@2023-12-01' = {
parent: staticWebApp
name: 'api-backend'
properties: {
backendResourceId: containerApp.id
region: location
}
}
Microsoft Foundry Integration
Configure Azure AI Services for LLM access:
// Azure AI Services (Cognitive Services) for Foundry
resource aiServices 'Microsoft.CognitiveServices/accounts@2024-10-01' = {
name: 'ai-${resourceToken}'
location: location
tags: tags
kind: 'AIServices'
sku: { name: 'S0' }
properties: {
customSubDomainName: 'ai-${resourceToken}'
publicNetworkAccess: 'Enabled'
}
}
// Deploy GPT-4o model
resource gpt4oDeployment 'Microsoft.CognitiveServices/accounts/deployments@2024-10-01' = {
parent: aiServices
name: 'gpt-4o'
sku: {
name: 'GlobalStandard'
capacity: 10
}
properties: {
model: {
format: 'OpenAI'
name: 'gpt-4o'
version: '2024-11-20'
}
}
}
// Deploy text-embedding-3-large
resource embeddingDeployment 'Microsoft.CognitiveServices/accounts/deployments@2024-10-01' = {
parent: aiServices
name: 'text-embedding-3-large'
sku: {
name: 'Standard'
capacity: 50
}
properties: {
model: {
format: 'OpenAI'
name: 'text-embedding-3-large'
version: '1'
}
}
dependsOn: [gpt4oDeployment]
}
Azure AI Search Configuration
resource searchService 'Microsoft.Search/searchServices@2024-06-01-preview' = {
name: 'srch-${resourceToken}'
location: location
tags: tags
sku: { name: 'basic' }
properties: {
replicaCount: 1
partitionCount: 1
hostingMode: 'default'
publicNetworkAccess: 'enabled'
authOptions: {
aadOrApiKey: {
aadAuthFailureMode: 'http401WithBearerChallenge'
}
}
}
}
Environment Variables & Outputs
Pass resource information to applications via outputs:
// Outputs automatically become environment variables
output AZURE_AI_SERVICES_ENDPOINT string = aiServices.properties.endpoint
output AZURE_SEARCH_ENDPOINT string = 'https://${searchService.name}.search.windows.net'
output AZURE_STORAGE_ACCOUNT string = storageAccount.name
output POSTGRES_HOST string = postgresServer.properties.fullyQualifiedDomainName
output POSTGRES_DATABASE string = 'appdb'
output API_URI string = 'https://${containerApp.properties.configuration.ingress.fqdn}'
output WEB_URI string = 'https://${staticWebApp.properties.defaultHostname}'
Hooks for Post-Provisioning
Create scripts for tasks after provisioning:
# azure.yaml
hooks:
postprovision:
posix:
shell: sh
run: ./scripts/post-provision.sh
windows:
shell: pwsh
run: ./scripts/post-provision.ps1
Example post-provision script:
#!/bin/bash
set -e
echo "Running post-provision tasks..."
# Create PostgreSQL database
az postgres flexible-server db create \
--resource-group "$AZURE_RESOURCE_GROUP" \
--server-name "$POSTGRES_SERVER_NAME" \
--database-name "appdb"
# Create storage containers
az storage container create \
--account-name "$AZURE_STORAGE_ACCOUNT" \
--name "documents" \
--auth-mode login
echo "Post-provision complete!"
Deployment Workflow
Standard Workflow
# 1. Initialize (first time only)
azd init
# 2. Authenticate
azd auth login
# 3. Create environment
azd env new dev
# 4. Set any required parameters
azd env set POSTGRES_PASSWORD "$(openssl rand -base64 32)"
# 5. Provision and deploy
azd up
# 6. View outputs
azd env get-values
CI/CD Pipeline (GitHub Actions)
See references/github-actions.md for CI/CD configuration.
Troubleshooting
| Issue | Solution |
|---|---|
Resource not found | Run azd provision to create resources |
Permission denied | Check RBAC role assignments |
Connection refused | Verify firewall rules allow Azure services |
Identity not configured | Ensure managed identity is enabled |
Deployment failed | Check container logs: az containerapp logs show |
Resources
スコア
総合スコア
リポジトリの品質指標に基づく評価
SKILL.mdファイルが含まれている
ライセンスが設定されている
100文字以上の説明がある
GitHub Stars 100以上
3ヶ月以内に更新がある
10回以上フォークされている
オープンIssueが50未満
プログラミング言語が設定されている
1つ以上のタグが設定されている
レビュー
レビュー機能は近日公開予定です