在Azure容器应用上部署容器:从环境配置到安全与扩展

本文详细介绍了如何在Azure容器应用中部署Docker容器,包括使用ARM模板创建托管环境、配置容器应用、安全最佳实践以及通过KEDA实现自动扩展,帮助开发者在无需直接管理Kubernetes的情况下运行微服务和事件驱动工作负载。

在Azure容器应用上部署容器

Azure容器应用是一项流行的服务,可帮助您部署Docker容器。它在轻松扩展容器和避免管理完整Kubernetes环境的操作复杂性之间提供了完美的平衡。其最佳用例包括部署API端点、构建事件驱动服务以及运行云工作流。此外,它还提供了云规模监控和警报所需的所有可观察性功能。在本教程中,我们将探讨如何将容器部署到Azure容器应用。

设置容器应用

创建应用的第一件事是容器环境。容器应用环境可以被视为托管相关服务的边界。例如,如果您正在为电子商务网站托管服务,将有一个环境,其中包含每个微服务的多个应用。每个环境应用都有一个工作负载配置文件,可以是容器应用或专用应用。容器配置文件和专用配置文件之间的主要区别在于,容器配置文件按环境中托管的每个应用收费,而专用配置文件无论应用数量如何都会产生固定成本。在限制方面,每个环境最多可以有200个容器应用,每个订阅每个区域最多可以有20个环境。

使用ARM模板部署容器应用

现在,让我们看看如何使用ARM模板部署容器应用。第一步是创建托管环境。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{
    "type": "Microsoft.App/managedEnvironments",
    "apiVersion": "2025-01-01",
    "name": "[parameters('containerAppEnvironmentName')]",
    "location": "[resourceGroup().location]",
    "identity": {
        "type": "UserAssigned",
        "userAssignedIdentities": {
            "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('userMsiName'))]":{}
        }
    },
    "properties": {
        "workloadProfiles": [
          {
            "workloadProfileType": "Consumption",
            "name": "Consumption"                  
          }
        ]
    }
}

上面的模板用于创建托管环境。强制参数包括:

  • name: 托管环境的名称。
  • location: 需要部署环境的Azure区域。
  • identity: 与环境关联的标识类型。用户分配或系统托管标识。两者都属于托管标识范畴,其中通信所需的所有机密都由Azure管理。
  • workloadProfiles: 在这种情况下,我们使用Consumption。如前所述,另一个选项是专用配置文件。

接下来,我们需要创建容器应用本身。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
    "type": "Microsoft.App/containerApps",
    "apiVersion": "2025-01-01",
    "name": "[parameters('containerAppName')]",
    "identity": {
        "type": "UserAssigned",
        "userAssignedIdentities": {
            "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('userMsiName'))]":{}
        }
    },
    "kind": "workflowapp",
    "location": "[resourceGroup().location]",
    "properties": {
        "configuration": {
            "ingress": {
                "transport": "auto"
            },
            "runtime": {
                "dotnet": {
                    "autoConfigureDataProtection": "true"
                }
            },
            "registries": [{
                "identity": "[concat('/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.ManagedIdentity/userAssignedIdentities/', parameters('userMsiName'))]",
                "server": "[variables('registry')]"
            }]
        },
        "environmentId": "[resourceId('Microsoft.App/managedEnvironments', parameters('containerAppEnvironmentName'))]",
        "template": {
            "scale": {
                "minReplicas": 2
            },
            "containers": [
                {
                  "image": "[concat(variables('registry'), '/official/', variables('repository'), '/api-service-host-image:', parameters('imageVersion'))]",
                  "name": "api-host-container",
                  "resources": {
                    "cpu": "1",
                    "memory": "2Gi"
                  }
                }
            ]
        }
    },
    "dependsOn": [
        "[resourceId('Microsoft.App/managedEnvironments', parameters('containerAppEnvironmentName'))]"
    ]
}

与托管环境类似,我们有参数如:

  • name: 容器应用的名称。
  • location: 需要创建容器应用的区域。
  • registries: 由于正在部署镜像,我们还需要指定必须从中拉取镜像的注册表。

在指定注册表属性时,还需要提及用于从注册表拉取镜像的标识。

  • template: 指定启动容器的属性。

  • containers:

    • image: 需要部署的Docker镜像。
    • resources: 运行容器所需的CPU和内存要求。
    • name: 容器应用内容器的名称。
  • ingress: 当托管HTTP API时,这很重要。如果API需要接收流量,它需要位于端点后面,指定入口会创建一个。

  • dependsOn: 确保有一个属性等待托管环境创建完成,然后才创建容器应用。

部署ARM模板的命令:

1
2
3
4
az deployment group create \
  --resource-group foo-bar-rg \
  --template-file <path-to-template.json> \
  --parameters <path-to-parameters.json>

保护您的容器应用

首先,将VNet附加到应用。VNet是Azure中提供私有网络的基本构建块。通过将网络安全组(NSG)附加到VNet,可以控制流经容器应用的入口和出口流量。这是阻止恶意流量的最佳策略。

其次,部署的镜像必须签名。这是为了确保供应链安全。有像Trivy这样的开源工具可以帮助签名Docker镜像。

如果可能,使用私有容器注册表。好处是除了您的组织/团队之外,没有人可以将镜像推送到注册表。

当有面向公众的API时,建议将它们放在应用程序网关或流量管理器后面,以防范拒绝服务攻击。

扩展基础设施

就像传统的VM基础设施一样,我们希望容器化工作负载能够根据需求无缝扩展。Azure容器应用通过KEDA(Kubernetes事件驱动自动扩展器)使这成为可能,支持事件驱动的自动扩展,向下扩展到零,向上扩展到满足峰值流量。

扩展规则可以依赖于HTTP流量、CPU、内存或任何其他资源利用率。例如,要创建具有HTTP扩展设置的容器应用,请使用以下命令。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
az containerapp create \
  --name foo-bar-container-app \
  --resource-group foo-bar-resource-group \
  --environment bar-environment \
  --image foo.acr.io/bar-image
  --min-replicas 0 \
  --max-replicas 5 \
  --scale-rule-name azure-http-rule \
  --scale-rule-type http \
  --scale-rule-http-concurrency 300

结论

总的来说,如果您需要在容器中运行微服务和事件驱动工作负载,而无需直接管理Kubernetes,Azure容器应用是理想选择。凭借对自动扩展和内置可观察性、安全网络的支持,它在简单性和灵活性之间取得了完美平衡。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计