此目录包含使用 Azure Developer CLI (AZD) 将容器化应用部署到 Azure Container Apps 的全面示例。这些示例展示了真实世界的模式、最佳实践以及生产级配置。
Azure Container Apps 是一个完全托管的无服务器容器平台,可让您运行微服务和容器化应用,而无需管理基础设施。结合 AZD,您可以获得以下优势:
开始之前,请确保您已具备以下条件:
# Check AZD installation azd version # Check Azure CLI az version # Check Docker (for building custom images) docker --version # Login to Azure azd auth login az login
所需的 Azure 资源:
使用 Azure Container Apps 部署一个基础 REST API。
示例:Python Flask API
# azure.yaml name: flask-api-demo metadata: template: flask-api-demo@0.0.1-beta services: api: project: ./src/api language: python host: containerapp
部署步骤:
# Initialize from template azd init --template todo-python-mongo # Provision infrastructure and deploy azd up # Test the deployment azd show curl $(azd show --output json | jq -r '.services.api.endpoint')/health
主要功能:
部署一个带有 MongoDB 集成的 Node.js 后端。
# Initialize Node.js API template azd init --template todo-nodejs-mongo # Configure environment variables azd env set DATABASE_NAME todosdb azd env set COLLECTION_NAME todos # Deploy azd up # View logs azd logs api
基础设施亮点:
// Bicep snippet from infra/main.bicep resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { name: 'api-${resourceToken}' location: location properties: { managedEnvironmentId: containerEnv.id configuration: { ingress: { external: true targetPort: 3000 transport: 'auto' } secrets: [ { name: 'mongodb-connection' value: mongoConnection } ] } template: { containers: [ { name: 'api' image: containerImage env: [ { name: 'DATABASE_URL' secretRef: 'mongodb-connection' } ] } ] scale: { minReplicas: 0 maxReplicas: 10 } } } }
部署一个完整的全栈应用,包括 React 前端和 API 后端。
# Initialize full-stack template azd init --template todo-csharp-sql-swa-func # Review configuration cat azure.yaml # Deploy both services azd up # Open the application azd show --output json | jq -r '.services.web.endpoint' | xargs start
场景:具有多个微服务的电商应用
目录结构:
microservices-demo/ ├── azure.yaml ├── infra/ │ ├── main.bicep │ ├── app/ │ │ ├── container-env.bicep │ │ ├── product-service.bicep │ │ ├── order-service.bicep │ │ └── payment-service.bicep │ └── core/ │ ├── storage.bicep │ └── database.bicep └── src/ ├── product-service/ ├── order-service/ └── payment-service/
azure.yaml 配置:
name: microservices-ecommerce services: product-service: project: ./src/product-service language: python host: containerapp order-service: project: ./src/order-service language: csharp host: containerapp payment-service: project: ./src/payment-service language: nodejs host: containerapp
部署:
# Initialize project azd init # Set production environment azd env new production # Configure production settings azd env set ENVIRONMENT production azd env set MIN_REPLICAS 2 azd env set MAX_REPLICAS 50 # Deploy all services azd up # Monitor deployment azd monitor --overview
场景:集成 Azure OpenAI 的 AI 聊天应用
文件:src/ai-chat/app.py
from flask import Flask, request, jsonify from azure.identity import DefaultAzureCredential from azure.keyvault.secrets import SecretClient import openai app = Flask(__name__) # Use Managed Identity for secure access credential = DefaultAzureCredential() vault_url = "https://{vault-name}.vault.azure.net" client = SecretClient(vault_url=vault_url, credential=credential) @app.route('/api/chat', methods=['POST']) def chat(): user_message = request.json.get('message') # Get OpenAI key from Key Vault openai_key = client.get_secret("openai-api-key").value openai.api_key = openai_key response = openai.ChatCompletion.create( model="gpt-4", messages=[{"role": "user", "content": user_message}] ) return jsonify({"response": response.choices[0].message.content}) if __name__ == '__main__': app.run(host='0.0.0.0', port=8000)
文件:azure.yaml
name: ai-chat-app services: api: project: ./src/ai-chat language: python host: containerapp
文件:infra/main.bicep
param location string = resourceGroup().location param environmentName string var resourceToken = uniqueString(subscription().id, environmentName, location) // Container Apps Environment module containerEnv './app/container-env.bicep' = { name: 'container-env-${resourceToken}' params: { location: location environmentName: environmentName } } // Key Vault for secrets resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = { name: 'kv-${resourceToken}' location: location properties: { sku: { family: 'A' name: 'standard' } tenantId: subscription().tenantId enableRbacAuthorization: true } } // Container App with Managed Identity module aiChatApp './app/container-app.bicep' = { name: 'ai-chat-app-${resourceToken}' params: { location: location environmentId: containerEnv.outputs.environmentId containerImage: 'your-registry.azurecr.io/ai-chat:latest' keyVaultName: keyVault.name } }
部署命令:
# Set up environment azd init --template ai-chat-app azd env new dev # Configure OpenAI azd env set AZURE_OPENAI_ENDPOINT "https://your-openai.openai.azure.com/" azd env set AZURE_OPENAI_DEPLOYMENT "gpt-4" # Deploy azd up # Test the API curl -X POST $(azd show --output json | jq -r '.services.api.endpoint')/api/chat \ -H "Content-Type: application/json" \ -d '{"message": "Hello, how are you?"}'
场景:带消息队列的订单处理系统
目录结构:
queue-worker/ ├── azure.yaml ├── infra/ │ ├── main.bicep │ ├── app/ │ │ ├── api.bicep │ │ └── worker.bicep │ └── core/ │ ├── storage-queue.bicep │ └── servicebus.bicep └── src/ ├── api/ └── worker/
文件:src/worker/processor.py
import os from azure.storage.queue import QueueClient from azure.identity import DefaultAzureCredential def process_orders(): credential = DefaultAzureCredential() queue_url = os.getenv('AZURE_QUEUE_URL') queue_client = QueueClient.from_queue_url( queue_url=queue_url, credential=credential ) while True: messages = queue_client.receive_messages(max_messages=10) for message in messages: # Process order print(f"Processing order: {message.content}") # Complete message queue_client.delete_message(message) if __name__ == '__main__': process_orders()
文件:azure.yaml
name: order-processing services: api: project: ./src/api language: python host: containerapp worker: project: ./src/worker language: python host: containerapp
部署:
# Initialize azd init # Deploy with queue configuration azd up # Scale worker based on queue length az containerapp update \ --name worker \ --resource-group rg-order-processing \ --scale-rule-name queue-scaling \ --scale-rule-type azure-queue \ --scale-rule-metadata queueName=orders accountName=storageaccount
# Create new revision without traffic azd deploy api --revision-suffix blue --no-traffic # Test the new revision curl https://api--blue.nicegrass-12345.eastus.azurecontainerapps.io/health # Split traffic (20% to blue, 80% to current) az containerapp ingress traffic set \ --name api \ --resource-group rg-myapp \ --revision-weight latest=80 blue=20 # Full cutover to blue az containerapp ingress traffic set \ --name api \ --resource-group rg-myapp \ --revision-weight blue=100
文件:.azure/dev/config.json
{ "deploymentStrategy": "canary", "canary": { "initialTrafficPercentage": 10, "incrementPercentage": 10, "intervalMinutes": 5 } }
部署脚本:
#!/bin/bash # deploy-canary.sh # Deploy new revision with 10% traffic azd deploy api --revision-mode multiple # Monitor metrics azd monitor --service api --duration 5m # Increase traffic gradually for i in {20..100..10}; do echo "Increasing traffic to $i%" az containerapp revision set-traffic \ --name api \ --resource-group rg-myapp \ --revision-weight latest=$i sleep 300 # Wait 5 minutes done
文件:azure.yaml
name: global-app services: api: project: ./src/api language: python host: containerapp regions: - eastus - westeurope - southeastasia
文件:infra/multi-region.bicep
param regions array = ['eastus', 'westeurope', 'southeastasia'] module containerApps './app/container-app.bicep' = [for region in regions: { name: 'app-${region}' params: { location: region environmentName: environmentName } }] // Traffic Manager for global load balancing resource trafficManager 'Microsoft.Network/trafficManagerProfiles@2022-04-01' = { name: 'tm-global-app' location: 'global' properties: { trafficRoutingMethod: 'Performance' endpoints: [for i in range(0, length(regions)): { name: 'endpoint-${regions[i]}' type: 'Microsoft.Network/trafficManagerProfiles/externalEndpoints' properties: { target: containerApps[i].outputs.fqdn endpointStatus: 'Enabled' } }] } }
部署:
# Deploy to all regions azd up # Verify endpoints azd show --output json | jq '.services.api.endpoints'
文件:infra/app/dapr-enabled.bicep
resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { name: 'dapr-app' properties: { configuration: { dapr: { enabled: true appId: 'order-service' appPort: 8000 appProtocol: 'http' } } template: { containers: [ { name: 'app' image: containerImage } ] } } }
带 Dapr 的应用代码:
from flask import Flask from dapr.clients import DaprClient app = Flask(__name__) @app.route('/orders', methods=['POST']) def create_order(): with DaprClient() as client: # Save state client.save_state( store_name='statestore', key='order-123', value={'status': 'pending'} ) # Publish event client.publish_event( pubsub_name='pubsub', topic_name='orders', data={'orderId': '123'} ) return {'status': 'created'}
# Use consistent naming conventions azd env set AZURE_ENV_NAME "myapp-prod" azd env set AZURE_LOCATION "eastus" # Tag resources for cost tracking azd env set AZURE_TAGS "Environment=Production,CostCenter=Engineering"
// Always use managed identity resource containerApp 'Microsoft.App/containerApps@2023-05-01' = { identity: { type: 'SystemAssigned' } } // Store secrets in Key Vault resource keyVault 'Microsoft.KeyVault/vaults@2023-02-01' = { properties: { enableRbacAuthorization: true networkAcls: { defaultAction: 'Deny' bypass: 'AzureServices' } } } // Use private endpoints resource privateEndpoint 'Microsoft.Network/privateEndpoints@2023-04-01' = { properties: { subnet: { id: subnetId } privateLinkServiceConnections: [ { name: 'containerapp-connection' properties: { privateLinkServiceId: containerApp.id } } ] } }
# azure.yaml with performance settings services: api: project: ./src/api host: containerapp resources: cpu: 1.0 memory: 2Gi scale: minReplicas: 2 maxReplicas: 20 rules: - name: http-rule http: concurrent: 100
# Enable Application Insights azd env set APPLICATIONINSIGHTS_CONNECTION_STRING "InstrumentationKey=..." # View logs in real-time azd logs api --follow # Monitor metrics azd monitor --service api # Create alerts az monitor metrics alert create \ --name high-cpu-alert \ --resource-group rg-myapp \ --scopes $(azd show --output json | jq -r '.services.api.resourceId') \ --condition "avg CPU > 80" \ --description "Alert when CPU exceeds 80%"
# Scale to zero when not in use az containerapp update \ --name api \ --resource-group rg-myapp \ --min-replicas 0 # Use spot instances for dev environments azd env set CONTAINER_APP_REPLICA_TYPE "Spot" # Set up budget alerts az consumption budget create \ --budget-name myapp-budget \ --amount 100 \ --time-grain Monthly \ --threshold 80
GitHub Actions 示例:
name: Deploy to Azure Container Apps on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup AZD uses: Azure/setup-azd@v1 - name: Login to Azure run: | azd auth login --client-id ${{ secrets.AZURE_CLIENT_ID }} \ --client-secret ${{ secrets.AZURE_CLIENT_SECRET }} \ --tenant-id ${{ secrets.AZURE_TENANT_ID }} - name: Deploy run: azd up --no-prompt env: AZURE_ENV_NAME: ${{ secrets.AZURE_ENV_NAME }} AZURE_LOCATION: ${{ secrets.AZURE_LOCATION }}
# Initialize new container app project azd init --template <template-name> # Deploy infrastructure and application azd up # Deploy only application code (skip infrastructure) azd deploy # Provision only infrastructure azd provision # View deployed resources azd show # Stream logs azd logs <service-name> --follow # Monitor application azd monitor --overview # Clean up resources azd down --force --purge
# Check logs azd logs api --tail 100 # View container events az containerapp revision show \ --name api \ --resource-group rg-myapp \ --revision latest # Test locally docker build -t api:local ./src/api docker run -p 8000:8000 api:local
# Verify ingress configuration az containerapp show \ --name api \ --resource-group rg-myapp \ --query properties.configuration.ingress # Check if internal ingress is enabled az containerapp ingress update \ --name api \ --resource-group rg-myapp \ --external true
# Check resource utilization az monitor metrics list \ --resource $(azd show --output json | jq -r '.services.api.resourceId') \ --metric "CPUPercentage,MemoryPercentage" # Scale up resources az containerapp update \ --name api \ --resource-group rg-myapp \ --cpu 2.0 \ --memory 4Gi
要贡献新的容器应用示例:
azure.yaml、infra/ 和 src/ 文件azd up 测试部署需要帮助? 加入 Microsoft Foundry Discord 社区获取支持和解答。
免责声明:
本文档使用AI翻译服务Co-op Translator进行翻译。尽管我们努力确保翻译的准确性,但请注意,自动翻译可能包含错误或不准确之处。原始语言的文档应被视为权威来源。对于关键信息,建议使用专业人工翻译。我们不对因使用此翻译而产生的任何误解或误读承担责任。