AzureFunctions azure-functions

Azure Functions 是一种无服务器计算服务,允许开发者构建和运行事件驱动的代码,而无需管理基础设施。

Serverless 0 次安装 0 次浏览 更新于 3/3/2026

Azure Functions

概览

Azure Functions 允许在 Microsoft Azure 上进行无服务器计算。构建事件驱动的应用程序,自动缩放,灵活绑定到各种 Azure 服务,并集成通过 Application Insights 进行监控。

何时使用

  • HTTP APIs 和 webhooks
  • 消息驱动处理(Service Bus,Event Hub)
  • 计划作业和 CRON 表达式
  • 文件和 blob 处理
  • 基于队列的工作流
  • 实时数据处理
  • 微服务和后端逻辑
  • 与 Azure 生态系统服务集成

实施示例

1. 使用 Azure CLI 创建 Azure 函数

# 安装 Azure Functions Core Tools
curl https://aka.ms/install-artifacts-ubuntu.sh | bash

# 登录到 Azure
az login

# 创建资源组
az group create --name myapp-rg --location eastus

# 创建存储账户(函数必需)
az storage account create \
  --name myappstore \
  --location eastus \
  --resource-group myapp-rg \
  --sku Standard_LRS

# 创建函数应用
az functionapp create \
  --resource-group myapp-rg \
  --consumption-plan-location eastus \
  --runtime node \
  --runtime-version 18 \
  --functions-version 4 \
  --name myapp-function \
  --storage-account myappstore

# 在应用中创建函数
func new --name HttpTrigger --template "HTTP trigger"

# 配置认证
az functionapp auth update \
  --resource-group myapp-rg \
  --name myapp-function \
  --enabled true \
  --action RedirectToLoginPage \
  --default-provider AzureActiveDirectory

# 部署函数
func azure functionapp publish myapp-function

# 检查部署
az functionapp list --output table

# 获取函数详情
az functionapp function show \
  --resource-group myapp-rg \
  --name myapp-function \
  --function-name HttpTrigger

2. Azure 函数实现(Node.js)

// HttpTrigger/index.js
module.exports = async function (context, req) {
  context.log('HTTP trigger function processed request.');

  // 提取请求数据
  const name = req.query.name || (req.body && req.body.name);
  const requestId = context.traceContext.traceparent;

  try {
    // 验证输入
    if (!name) {
      return {
        status: 400,
        body: { error: 'Name parameter is required' }
      };
    }

    // 业务逻辑
    const response = {
      message: `Hello ${name}!`,
      timestamp: new Date().toISOString(),
      requestId: requestId
    };

    // 记录到 Application Insights
    context.log({
      level: 'info',
      message: 'Request processed successfully',
      name: name,
      requestId: requestId
    });

    return {
      status: 200,
      headers: {
        'Content-Type': 'application/json',
        'X-Request-ID': requestId
      },
      body: response
    };
  } catch (error) {
    context.log.error('Error processing request:', error);

    return {
      status: 500,
      body: { error: 'Internal server error' }
    };
  }
};

// TimerTrigger/index.js
module.exports = async function (context, myTimer) {
  const timeStamp = new Date().toISOString();

  if (myTimer.isPastDue) {
    context.log('Timer function is running late!');
  }

  // 处理计划作业
  context.log(`Timer trigger function ran at ${timeStamp}`);
  context.log('Processing batch job...');

  // 模拟工作
  await new Promise(resolve => setTimeout(resolve, 1000));

  context.log('Batch job completed');
};

// ServiceBusQueueTrigger/index.js
module.exports = async function (context, mySbMsg) {
  context.log('ServiceBus queue trigger function processed message:', mySbMsg);

  try {
    const messageBody = typeof mySbMsg === 'string' ? JSON.parse(mySbMsg) : mySbMsg;

    // 处理消息
    await processMessage(messageBody);

    context.log('Message processed successfully');
  } catch (error) {
    context.log.error('Error processing message:', error);
    throw error; // 重新排队消息
  }
};

async function processMessage(messageBody) {
  // 业务逻辑在这里
  return true;
}

3. 使用 Terraform 的 Azure Functions

# functions.tf
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.0"
    }
  }
}

provider "azurerm" {
  features {
    virtual_machine {
      delete_os_disk_on_delete            = true
      graceful_shutdown                   = false
      skip_shutdown_and_force_delete       = false
    }
  }
}

variable "environment" {
  default = "dev"
}

variable "location" {
  default = "eastus"
}

# 资源组
resource "azurerm_resource_group" "main" {
  name     = "myapp-rg-${var.environment}"
  location = var.location
}

# 函数应用的存储账户
resource "azurerm_storage_account" "function_storage" {
  name                     = "myappstore${var.environment}"
  resource_group_name      = azurerm_resource_group.main.name
  location                 = azurerm_resource_group.main.location
  account_tier             = "Standard"
  account_replication_type = "LRS"

  identity {
    type = "SystemAssigned"
  }

  tags = {
    environment = var.environment
  }
}

# 应用程序洞察
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
}

# 应用服务计划
resource "azurerm_service_plan" "function_plan" {
  name                = "myapp-plan-${var.environment}"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  os_type             = "Linux"
  sku_name            = "Y1" # 消费计划

  tags = {
    environment = var.environment
  }
}

# 函数应用
resource "azurerm_linux_function_app" "main" {
  name                = "myapp-function-${var.environment}"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  service_plan_id     = azurerm_service_plan.function_plan.id

  storage_account_name       = azurerm_storage_account.function_storage.name
  storage_account_access_key = azurerm_storage_account.function_storage.primary_access_key

  app_settings = {
    APPINSIGHTS_INSTRUMENTATIONKEY             = azurerm_application_insights.main.instrumentation_key
    APPLICATIONINSIGHTS_CONNECTION_STRING      = azurerm_application_insights.main.connection_string
    AzureWebJobsStorage                        = azurerm_storage_account.function_storage.primary_blob_connection_string
    WEBSITE_NODE_DEFAULT_VERSION               = "~18"
    FUNCTIONS_EXTENSION_VERSION                = "~4"
    FUNCTIONS_WORKER_RUNTIME                   = "node"
    ENABLE_INIT_LOGGING                        = true
    WEBSITE_RUN_FROM_PACKAGE                   = 1
  }

  site_config {
    application_insights_key             = azurerm_application_insights.main.instrumentation_key
    application_insights_connection_string = azurerm_application_insights.main.connection_string

    cors {
      allowed_origins = ["https://example.com"]
    }

    http2_enabled = true
  }

  https_only = true
  identity {
    type = "SystemAssigned"
  }

  tags = {
    environment = var.environment
  }
}

# 密钥库用于密钥
resource "azurerm_key_vault" "function_secrets" {
  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_function_app.main.identity[0].principal_id

    secret_permissions = [
      "Get",
      "List"
    ]
  }

  tags = {
    environment = var.environment
  }
}

# 将数据库密码存储在密钥库中
resource "azurerm_key_vault_secret" "db_password" {
  name         = "db-password"
  value        = "MySecurePassword123!"
  key_vault_id = azurerm_key_vault.function_secrets.id
}

# 诊断设置
resource "azurerm_monitor_diagnostic_setting" "function_logs" {
  name               = "function-logs"
  target_resource_id = azurerm_linux_function_app.main.id

  log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id

  enabled_log {
    category = "FunctionAppLogs"
  }

  metric {
    category = "AllMetrics"
  }
}

# 日志分析工作区
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
}

data "azurerm_client_config" "current" {}

output "function_app_url" {
  value = "https://${azurerm_linux_function_app.main.default_hostname}"
}

output "app_insights_key" {
  value     = azurerm_application_insights.main.instrumentation_key
  sensitive = true
}

4. 函数绑定配置

{
  "scriptFile": "index.js",
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": ["get", "post"],
      "route": "api/{*route}"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    },
    {
      "type": "queue",
      "direction": "out",
      "name": "myQueueItem",
      "queueName": "myqueue",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "serviceBus",
      "direction": "in",
      "name": "mySbMsg",
      "queueName": "myqueue",
      "connection": "ServiceBusConnection",
      "cardinality": "one"
    },
    {
      "type": "blob",
      "direction": "in",
      "name": "inputBlob",
      "path": "input/{name}",
      "connection": "AzureWebJobsStorage"
    },
    {
      "type": "blob",
      "direction": "out",
      "name": "outputBlob",
      "path": "output/{name}",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

最佳实践

✅ DO

  • 使用 Azure 服务的托管身份
  • 在 Key Vault 中存储密钥
  • 启用 Application Insights
  • 实现幂等函数
  • 使用持久函数进行长时间运行的操作
  • 处理异常和失败
  • 监控函数执行
  • 使用绑定而不是 SDK 调用

❌ DON’T

  • 在代码或配置中存储密钥
  • 忽略 Application Insights
  • 创建没有错误处理的函数
  • 使用阻塞操作
  • 创建没有持久函数的长时间运行函数
  • 忽略监控和日志记录

监控

  • Application Insights 用于跟踪和指标
  • Azure Monitor 用于整体健康
  • Log Analytics 用于日志分析
  • 函数指标(执行次数,持续时间)
  • 自定义遥测和事件

资源