name: azure-app-service description: 通过自动扩展、部署槽、SSL/TLS和监控部署和管理Azure App Service中的Web应用程序。用于在Azure上托管Web应用程序。
Azure App Service
概览
Azure App Service提供了一个完全托管的平台,用于构建和托管Web应用程序、REST API和移动后端。支持多种编程语言,集成了DevOps、安全性和高可用性。
使用场景
- Web应用程序(ASP.NET、Node.js、Python、Java)
- REST API和微服务
- 移动应用后端
- 静态网站托管
- 需要扩展的生产应用程序
- 需要自动扩展的应用程序
- 多区域部署
- 容器化应用程序
实施示例
1. 使用Azure CLI创建App Service
# 登录Azure
az login
# 创建资源组
az group create --name myapp-rg --location eastus
# 创建App Service计划
az appservice plan create \
--name myapp-plan \
--resource-group myapp-rg \
--sku P1V2 \
--is-linux
# 创建Web应用程序
az webapp create \
--resource-group myapp-rg \
--plan myapp-plan \
--name myapp-web \
--deployment-container-image-name nodejs:18
# 配置应用程序设置
az webapp config appsettings set \
--resource-group myapp-rg \
--name myapp-web \
--settings \
NODE_ENV=production \
PORT=8080 \
DATABASE_URL=postgresql://... \
REDIS_URL=redis://...
# 启用仅HTTPS
az webapp update \
--resource-group myapp-rg \
--name myapp-web \
--https-only true
# 配置自定义域名
az webapp config hostname add \
--resource-group myapp-rg \
--webapp-name myapp-web \
--hostname www.example.com
# 创建部署槽
az webapp deployment slot create \
--resource-group myapp-rg \
--name myapp-web \
--slot staging
# 交换槽
az webapp deployment slot swap \
--resource-group myapp-rg \
--name myapp-web \
--slot staging
# 获取发布配置文件
az webapp deployment list-publish-profiles \
--resource-group myapp-rg \
--name myapp-web \
--query "[0].publishUrl"
2. Terraform App Service配置
# app-service.tf
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
variable "environment" {
default = "prod"
}
variable "location" {
default = "eastus"
}
# 资源组
resource "azurerm_resource_group" "main" {
name = "myapp-rg-${var.environment}"
location = var.location
}
# App Service计划
resource "azurerm_service_plan" "main" {
name = "myapp-plan-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
os_type = "Linux"
sku_name = "P1V2"
tags = {
environment = var.environment
}
}
# 日志分析工作区
resource "azurerm_log_analytics_workspace" "main" {
name = "myapp-logs-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
sku = "PerGB2018"
retention_in_days = 30
}
# 应用程序见解
resource "azurerm_application_insights" "main" {
name = "myapp-insights-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
application_type = "web"
retention_in_days = 30
workspace_id = azurerm_log_analytics_workspace.main.id
}
# Web应用程序
resource "azurerm_linux_web_app" "main" {
name = "myapp-web-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
service_plan_id = azurerm_service_plan.main.id
https_only = true
app_settings = {
WEBSITES_ENABLE_APP_SERVICE_STORAGE = false
DOCKER_ENABLE_CI = true
APPINSIGHTS_INSTRUMENTATIONKEY = azurerm_application_insights.main.instrumentation_key
APPLICATIONINSIGHTS_CONNECTION_STRING = azurerm_application_insights.main.connection_string
NODE_ENV = "production"
PORT = "8080"
}
site_config {
always_on = true
http2_enabled = true
minimum_tls_version = "1.2"
websockets_enabled = false
application_stack {
node_version = "18-lts"
}
cors {
allowed_origins = ["https://example.com"]
}
}
identity {
type = "SystemAssigned"
}
tags = {
environment = var.environment
}
}
# 部署槽(暂存)
resource "azurerm_linux_web_app_slot" "staging" {
name = "staging"
app_service_id = azurerm_linux_web_app.main.id
service_plan_id = azurerm_service_plan.main.id
https_only = true
app_settings = {
WEBSITES_ENABLE_APP_SERVICE_STORAGE = false
NODE_ENV = "staging"
PORT = "8080"
}
site_config {
always_on = true
http2_enabled = true
minimum_tls_version = "1.2"
application_stack {
node_version = "18-lts"
}
}
identity {
type = "SystemAssigned"
}
}
# 自动扩展设置
resource "azurerm_monitor_autoscale_setting" "app_service" {
name = "app-service-autoscale"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
target_resource_id = azurerm_service_plan.main.id
profile {
name = "default"
capacity {
default = 2
minimum = 1
maximum = 5
}
rule {
metric_trigger {
metric_name = "CpuPercentage"
metric_resource_id = azurerm_service_plan.main.id
time_grain = "PT1M"
statistic = "Average"
time_window = "PT5M"
operator = "GreaterThan"
threshold = 75
}
scale_action {
direction = "Increase"
type = "ChangeCount"
value = 1
cooldown = "PT5M"
}
}
rule {
metric_trigger {
metric_name = "CpuPercentage"
metric_resource_id = azurerm_service_plan.main.id
time_grain = "PT1M"
statistic = "Average"
time_window = "PT5M"
operator = "LessThan"
threshold = 25
}
scale_action {
direction = "Decrease"
type = "ChangeCount"
value = 1
cooldown = "PT5M"
}
}
}
}
# 诊断设置
resource "azurerm_monitor_diagnostic_setting" "app_service" {
name = "app-service-logs"
target_resource_id = azurerm_linux_web_app.main.id
log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id
enabled_log {
category = "AppServiceHTTPLogs"
}
enabled_log {
category = "AppServiceAntivirusScanAuditLogs"
}
metric {
category = "AllMetrics"
}
}
# 密钥库用于密钥
resource "azurerm_key_vault" "main" {
name = "myappkv${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
tenant_id = data.azurerm_client_config.current.tenant_id
sku_name = "standard"
access_policy {
tenant_id = data.azurerm_client_config.current.tenant_id
object_id = azurerm_linux_web_app.main.identity[0].principal_id
secret_permissions = [
"Get",
"List"
]
}
tags = {
environment = var.environment
}
}
# 密钥库密钥
resource "azurerm_key_vault_secret" "database_url" {
name = "database-url"
value = "postgresql://user:pass@host/db"
key_vault_id = azurerm_key_vault.main.id
}
resource "azurerm_key_vault_secret" "api_key" {
name = "api-key"
value = "your-api-key-here"
key_vault_id = azurerm_key_vault.main.id
}
data "azurerm_client_config" "current" {}
output "app_url" {
value = "https://${azurerm_linux_web_app.main.default_hostname}"
}
output "app_insights_key" {
value = azurerm_application_insights.main.instrumentation_key
sensitive = true
}
3. 部署配置
# .github/workflows/deploy.yml
name: 部署到App Service
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 设置Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: 安装依赖
run: npm install
- name: 运行测试
run: npm test
- name: 构建
run: npm run build
- name: 部署到Azure
uses: azure/webapps-deploy@v2
with:
app-name: myapp-web-prod
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}
package: .
- name: 交换槽
uses: azure/CLI@v1
with:
azcliversion: 2.0.76
inlineScript: |
az webapp deployment slot swap \
--resource-group myapp-rg-prod \
--name myapp-web-prod \
--slot staging
4. 健康检查配置
# 启用健康检查
az webapp config set \
--resource-group myapp-rg \
--name myapp-web \
--generic-configurations HEALTHCHECK_PATH=/health
# 监控健康
az monitor metrics list-definitions \
--resource /subscriptions/{subscription}/resourceGroups/myapp-rg/providers/Microsoft.Web/sites/myapp-web
最佳实践
✅ DO
- 使用部署槽进行零停机部署
- 启用应用程序见解
- 根据指标配置自动扩展
- 使用托管身份访问Azure服务
- 启用仅HTTPS
- 在密钥库中存储密钥
- 监控性能指标
- 实施健康检查
❌ DON’T
- 在配置中存储密钥
- 禁用HTTPS
- 忽略应用程序见解
- 为生产使用单一实例
- 直接部署到生产环境
- 忽略自动扩展配置
监控
- 应用程序见解用于应用程序指标
- Azure Monitor用于资源健康
- Log Analytics用于日志分析
- 自定义指标和事件
- 性能计数器和诊断