Azure Container Apps — Chạy Container Production mà không cần Kubernetes

Posted on: 4/17/2026 5:05:43 PM

1. Azure Container Apps là gì?

Azure Container Apps (ACA) là nền tảng serverless container của Microsoft Azure, cho phép bạn chạy ứng dụng container hóa mà không cần quản lý cluster Kubernetes, node pool, hay bất kỳ hạ tầng nào phía dưới. ACA tự động xử lý scaling, load balancing, TLS certificates, và revision management — bạn chỉ cần tập trung vào code.

Nếu bạn từng cảm thấy Kubernetes quá phức tạp cho một API backend hoặc vài microservices, thì ACA chính xác là thứ bạn cần. Nó mang lại sức mạnh của container orchestration mà không đòi hỏi bạn phải hiểu về etcd, kube-proxy, hay CNI plugins.

180,000 vCPU-seconds miễn phí/tháng
360,000 GiB-seconds miễn phí/tháng
2 triệu Requests miễn phí/tháng
0 → N Scale-to-zero tự động

Tại sao không dùng Kubernetes trực tiếp?

AKS (Azure Kubernetes Service) là lựa chọn mạnh mẽ khi bạn cần toàn quyền kiểm soát cluster. Nhưng với đa số ứng dụng web, API, và microservices, ACA cung cấp 90% tính năng cần thiết mà chỉ mất 10% effort quản lý. Bạn không cần lo về node upgrades, cluster networking, hay RBAC policies — Azure lo hết.

2. Kiến trúc hệ thống

ACA được xây dựng trên nền tảng Kubernetes (AKS) nhưng abstract hoàn toàn layer đó khỏi developer. Kiến trúc gồm 3 tầng chính:

graph TB
    subgraph Internet
        U[Users / Clients]
    end
    subgraph ACA_ENV["Container Apps Environment"]
        direction TB
        INGRESS["Built-in Ingress
TLS + Load Balancer"] subgraph APPS["Container Apps"] A1["API Gateway
.NET 10"] A2["Order Service
.NET 10"] A3["Notification
Worker"] end subgraph INFRA["Platform Services"] DAPR["Dapr Sidecar"] KEDA["KEDA Autoscaler"] ENVOY["Envoy Proxy"] end subgraph STORAGE["Managed Storage"] LOG["Log Analytics"] SECRET["Secret Store"] end end U --> INGRESS INGRESS --> A1 A1 --> DAPR DAPR --> A2 DAPR --> A3 A2 --> KEDA A3 --> KEDA APPS --> LOG APPS --> SECRET style ACA_ENV fill:#f8f9fa,stroke:#e94560,color:#2c3e50 style INGRESS fill:#e94560,stroke:#fff,color:#fff style DAPR fill:#2c3e50,stroke:#fff,color:#fff style KEDA fill:#2c3e50,stroke:#fff,color:#fff style ENVOY fill:#2c3e50,stroke:#fff,color:#fff style A1 fill:#fff,stroke:#e94560,color:#2c3e50 style A2 fill:#fff,stroke:#e94560,color:#2c3e50 style A3 fill:#fff,stroke:#e94560,color:#2c3e50 style LOG fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style SECRET fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50

Kiến trúc tổng quan Azure Container Apps Environment

Container Apps Environment là boundary chung cho tất cả container apps, tương tự một namespace trong Kubernetes. Các apps trong cùng environment chia sẻ virtual network, logging configuration, và Dapr components.

Envoy Proxy xử lý ingress routing, TLS termination, traffic splitting giữa các revisions. KEDA (Kubernetes Event-Driven Autoscaling) điều khiển scaling dựa trên HTTP traffic, queue depth, cron schedule, hoặc bất kỳ metric nào KEDA hỗ trợ. Dapr (Distributed Application Runtime) cung cấp building blocks cho microservices: service invocation, state management, pub/sub, bindings, và secrets.

3. So sánh với AKS, App Service và Container Instances

Azure cung cấp nhiều dịch vụ chạy container. Bảng dưới giúp bạn chọn đúng dịch vụ cho từng use case:

Tiêu chíContainer AppsAKSApp ServiceContainer Instances
Quản lý hạ tầngServerless, không cần quản lýBạn quản lý clusterPaaS, managedServerless, đơn giản
Scaling0 → N, KEDA-basedHPA, VPA, Cluster Autoscaler1 → 30 instancesKhông auto-scale
Scale-to-zero✅ Có❌ Không (luôn có node)❌ Không (luôn có instance)N/A
Dapr integration✅ Built-inTự cài đặt❌ Không❌ Không
Revision management✅ Traffic splittingTự quản lý DeploymentDeployment slots❌ Không
GPU support✅ Serverless GPU (GA 2026)✅ GPU node pools❌ Không✅ GPU containers
Jobs/Cron✅ Native JobsCronJob resourceWebJobsTự schedule
Free tier✅ 180K vCPU-s/thángControl plane miễn phíF1 tier (giới hạn)Không có free tier
Best forMicroservices, APIs, event-drivenComplex workloads, full controlWeb apps đơn giảnBatch jobs ngắn

Khi nào chọn ACA thay vì AKS?

Nếu team của bạn dưới 5 người và không có dedicated DevOps/Platform engineer, ACA gần như luôn là lựa chọn tốt hơn. Bạn tiết kiệm hàng trăm giờ mỗi năm không phải quản lý cluster upgrades, node draining, và network policies. Khi nào cần full control (custom operators, service mesh phức tạp, multi-tenancy ở cluster level), lúc đó mới nên migrate sang AKS.

4. Các tính năng cốt lõi

4.1. Ingress & Traffic Management

ACA cung cấp built-in HTTP ingress với TLS termination tự động. Bạn không cần cài NGINX Ingress Controller hay cert-manager — chỉ cần bật ingress là có HTTPS endpoint.

# Tạo container app với ingress
az containerapp create \
  --name my-api \
  --resource-group my-rg \
  --environment my-env \
  --image myregistry.azurecr.io/my-api:v1 \
  --target-port 8080 \
  --ingress external \
  --min-replicas 0 \
  --max-replicas 10

Traffic splitting cho phép Blue/Green deployment và A/B testing:

# Split traffic: 80% revision hiện tại, 20% revision mới
az containerapp ingress traffic set \
  --name my-api \
  --resource-group my-rg \
  --revision-weight my-api--v1=80 my-api--v2=20

4.2. Revision Management

Mỗi lần bạn thay đổi container image hoặc configuration, ACA tạo một revision mới. Bạn có thể chạy nhiều revisions đồng thời và split traffic giữa chúng — lý tưởng cho canary deployments.

graph LR
    LB["Load Balancer"]
    LB -->|"80%"| R1["Revision v1
3 replicas"] LB -->|"20%"| R2["Revision v2
1 replica"] R1 --> DB[(Database)] R2 --> DB style LB fill:#e94560,stroke:#fff,color:#fff style R1 fill:#fff,stroke:#e94560,color:#2c3e50 style R2 fill:#f8f9fa,stroke:#4CAF50,color:#2c3e50 style DB fill:#2c3e50,stroke:#fff,color:#fff

Traffic splitting giữa 2 revisions cho canary deployment

4.3. Secret Management

ACA cho phép định nghĩa secrets trực tiếp hoặc reference từ Azure Key Vault. Secrets được inject vào container qua environment variables — không bao giờ lưu credentials trong container image.

# Thêm secret từ Key Vault
az containerapp secret set \
  --name my-api \
  --resource-group my-rg \
  --secrets "db-conn=keyvaultref:https://my-vault.vault.azure.net/secrets/db-connection,identityref:/subscriptions/.../my-identity"

5. Free Tier chi tiết — chạy production chi phí gần bằng 0

Đây là điểm hấp dẫn nhất của ACA: free tier đủ rộng để chạy production cho ứng dụng nhỏ và vừa.

Tài nguyênFree Tier (mỗi subscription/tháng)Sau khi hết free
vCPU180,000 vCPU-seconds$0.000024/vCPU-second
Memory360,000 GiB-seconds$0.000003/GiB-second
Requests2,000,000 requests$0.40/million requests
Scale-to-zero✅ Không tính phí khi 0 replicas
Idle chargeGiảm giá khi replicas idleTỷ lệ thấp hơn active

Free Tier đủ dùng cho những gì?

180,000 vCPU-seconds ≈ một container 0.25 vCPU chạy liên tục trong ~8.3 ngày, hoặc nhiều containers scale-to-zero chỉ chạy khi có request. Với ứng dụng API nhỏ nhận vài trăm requests/ngày, free tier đủ dùng cả tháng mà không mất đồng nào. Health probe requests cũng không bị tính phí.

Ước tính chi phí thực tế

Giả sử bạn có 1 API (.NET 10) với 0.5 vCPU / 1 GiB RAM, nhận trung bình 50,000 requests/ngày, thời gian xử lý trung bình 100ms/request:

Active time/ngày: 50,000 × 100ms = 5,000 giây
vCPU-seconds/ngày: 5,000 × 0.5 = 2,500
vCPU-seconds/tháng: 2,500 × 30 = 75,000  ← Trong free tier (180,000)

GiB-seconds/ngày: 5,000 × 1 = 5,000
GiB-seconds/tháng: 5,000 × 30 = 150,000  ← Trong free tier (360,000)

Requests/tháng: 50,000 × 30 = 1,500,000  ← Trong free tier (2,000,000)

→ Chi phí: $0/tháng

6. Triển khai ứng dụng .NET 10 lên ACA

6.1. Dockerfile tối ưu cho .NET 10

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app --no-restore

FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS runtime
WORKDIR /app
COPY --from=build /app .

ENV ASPNETCORE_URLS=http://+:8080
ENV DOTNET_EnableDiagnostics=0
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApi.dll"]

Tại sao dùng Alpine image?

Image aspnet:10.0-alpine chỉ ~110MB so với ~220MB của image Debian. Container nhẹ hơn → cold start nhanh hơn, pull image nhanh hơn, tiết kiệm băng thông. Với Native AOT, image có thể giảm xuống dưới 50MB.

6.2. Deploy bằng Azure CLI

# Tạo resource group và environment
az group create --name rg-myapp --location southeastasia
az containerapp env create \
  --name env-myapp \
  --resource-group rg-myapp \
  --location southeastasia

# Build và push image lên ACR
az acr create --name myappacr --resource-group rg-myapp --sku Basic
az acr build --registry myappacr --image my-api:v1 .

# Deploy container app
az containerapp create \
  --name api-myapp \
  --resource-group rg-myapp \
  --environment env-myapp \
  --image myappacr.azurecr.io/my-api:v1 \
  --registry-server myappacr.azurecr.io \
  --target-port 8080 \
  --ingress external \
  --cpu 0.25 --memory 0.5Gi \
  --min-replicas 0 \
  --max-replicas 5 \
  --env-vars "ASPNETCORE_ENVIRONMENT=Production"

6.3. Deploy bằng .NET Aspire

Nếu bạn sử dụng .NET Aspire, việc deploy lên ACA trở nên cực kỳ đơn giản với azd (Azure Developer CLI):

# Khởi tạo Aspire project
dotnet new aspire-starter -n MyApp
cd MyApp

# Deploy lên ACA
azd init
azd up

Aspire tự động tạo Container Apps Environment, đăng ký container images lên ACR, cấu hình service discovery giữa các projects, và thiết lập health checks — tất cả chỉ với 2 lệnh.

6.4. Cấu hình Health Probes

ACA hỗ trợ 3 loại health probes giống Kubernetes:

// Program.cs - Cấu hình health checks
builder.Services.AddHealthChecks()
    .AddSqlServer(builder.Configuration.GetConnectionString("Default")!)
    .AddRedis(builder.Configuration.GetConnectionString("Redis")!);

app.MapHealthChecks("/healthz/live", new HealthCheckOptions
{
    Predicate = _ => false // Liveness: chỉ check app sống
});

app.MapHealthChecks("/healthz/ready", new HealthCheckOptions
{
    Predicate = check => check.Tags.Contains("ready") // Readiness: check dependencies
});
# container app config
properties:
  template:
    containers:
      - name: my-api
        probes:
          - type: Liveness
            httpGet:
              path: /healthz/live
              port: 8080
            periodSeconds: 10
          - type: Readiness
            httpGet:
              path: /healthz/ready
              port: 8080
            periodSeconds: 5
          - type: Startup
            httpGet:
              path: /healthz/live
              port: 8080
            failureThreshold: 30
            periodSeconds: 2

7. Dapr Integration — Microservices không vendor lock-in

Dapr (Distributed Application Runtime) là building block runtime cho microservices, và ACA tích hợp Dapr ở mức platform — bạn chỉ cần bật flag, không cần tự cài hay quản lý Dapr sidecar.

graph LR
    subgraph ACA_ENV["Container Apps Environment"]
        subgraph APP1["Order Service"]
            C1["App Code"]
            D1["Dapr Sidecar"]
        end
        subgraph APP2["Payment Service"]
            C2["App Code"]
            D2["Dapr Sidecar"]
        end
        subgraph APP3["Email Service"]
            C3["App Code"]
            D3["Dapr Sidecar"]
        end
    end
    C1 -->|"HTTP/gRPC"| D1
    D1 -->|"Service Invocation"| D2
    D2 --> C2
    D1 -->|"Pub/Sub"| D3
    D3 --> C3
    style C1 fill:#fff,stroke:#e94560,color:#2c3e50
    style C2 fill:#fff,stroke:#e94560,color:#2c3e50
    style C3 fill:#fff,stroke:#e94560,color:#2c3e50
    style D1 fill:#e94560,stroke:#fff,color:#fff
    style D2 fill:#e94560,stroke:#fff,color:#fff
    style D3 fill:#e94560,stroke:#fff,color:#fff

Dapr sidecar pattern trong Azure Container Apps

Các Dapr building blocks hữu ích nhất

Building BlockMô tảBackend mặc định trên ACA
Service InvocationGọi service khác qua tên, không cần biết IP/portInternal DNS
State ManagementKey-value store cho session, cart, preferencesAzure Cosmos DB, Azure Table Storage
Pub/SubPublish/Subscribe messaging giữa servicesAzure Service Bus, Azure Event Hubs
BindingsInput/Output bindings tới external systemsAzure Blob Storage, Azure Queue, SMTP
SecretsTruy cập secrets từ secret storesAzure Key Vault
// Gọi Payment Service qua Dapr (không cần biết URL)
using var client = new DaprClientBuilder().Build();

var order = new Order { Id = "ORD-001", Amount = 99.99m };
var result = await client.InvokeMethodAsync<Order, PaymentResult>(
    "payment-service",  // App ID của target service
    "api/process",
    order
);

// Pub/Sub: publish event
await client.PublishEventAsync("pubsub", "order-completed", order);

// State Management: lưu trạng thái
await client.SaveStateAsync("statestore", $"order-{order.Id}", order);

8. Autoscaling với KEDA — từ zero đến hàng nghìn replicas

ACA sử dụng KEDA (Kubernetes Event-Driven Autoscaling) để scaling dựa trên nhiều nguồn sự kiện khác nhau. Đây là điểm vượt trội so với App Service (chỉ scale theo CPU/memory) và Container Instances (không auto-scale).

Các scaling rules phổ biến

# Scale theo HTTP traffic
scale:
  minReplicas: 0
  maxReplicas: 20
  rules:
    - name: http-rule
      http:
        metadata:
          concurrentRequests: "50"

---
# Scale theo Azure Service Bus queue
scale:
  minReplicas: 0
  maxReplicas: 30
  rules:
    - name: queue-rule
      custom:
        type: azure-servicebus
        metadata:
          queueName: orders
          messageCount: "5"
        auth:
          - secretRef: sb-connection
            triggerParameter: connection

---
# Scale theo cron schedule
scale:
  minReplicas: 1
  maxReplicas: 10
  rules:
    - name: business-hours
      custom:
        type: cron
        metadata:
          timezone: "Asia/Ho_Chi_Minh"
          start: "0 8 * * 1-5"
          end: "0 18 * * 1-5"
          desiredReplicas: "5"

Lưu ý về Scale-to-Zero

Khi scale xuống 0 replicas, request đầu tiên sẽ có cold start (thường 2-5 giây với .NET). Để giảm thiểu, bạn có thể đặt minReplicas: 1 (sẽ mất free tier cho idle time) hoặc sử dụng Native AOT để giảm startup time xuống dưới 100ms. App scale theo CPU/memory không thể scale-to-zero.

9. Jobs — Tác vụ nền và xử lý theo lịch

Ngoài apps (dịch vụ chạy liên tục), ACA còn hỗ trợ Jobs — container chạy đến khi hoàn thành rồi tắt. Có 3 loại trigger:

Trigger TypeMô tảUse Case
ManualChạy theo yêu cầu (API call hoặc CLI)Database migration, one-off scripts
ScheduleChạy theo cron expressionBáo cáo hàng ngày, cleanup, data sync
EventChạy khi có event từ queue/topicXử lý ảnh, gửi email batch, ETL
# Tạo scheduled job chạy lúc 2:00 AM hàng ngày
az containerapp job create \
  --name job-daily-report \
  --resource-group rg-myapp \
  --environment env-myapp \
  --image myappacr.azurecr.io/report-generator:v1 \
  --trigger-type Schedule \
  --cron-expression "0 2 * * *" \
  --cpu 0.5 --memory 1Gi \
  --replica-timeout 3600 \
  --env-vars "DB_CONN=secretref:db-connection"

10. Networking & Security

10.1. Network Architecture

graph TB
    INET["Internet"]
    subgraph VNET["Azure Virtual Network"]
        subgraph SUBNET["ACA Subnet"]
            ENV["Container Apps Environment"]
            APP1["Public App
(External Ingress)"] APP2["Internal Service
(Internal Ingress)"] APP3["Background Worker
(No Ingress)"] end subgraph PRIV["Private Subnet"] DB["Azure SQL"] KV["Key Vault"] end end INET -->|"HTTPS"| APP1 APP1 -->|"Internal DNS"| APP2 APP2 --> APP3 APP2 --> DB APP1 --> KV style INET fill:#e94560,stroke:#fff,color:#fff style APP1 fill:#fff,stroke:#e94560,color:#2c3e50 style APP2 fill:#fff,stroke:#2c3e50,color:#2c3e50 style APP3 fill:#f8f9fa,stroke:#e0e0e0,color:#2c3e50 style DB fill:#2c3e50,stroke:#fff,color:#fff style KV fill:#2c3e50,stroke:#fff,color:#fff

Networking: kết hợp external/internal ingress với VNet integration

ACA hỗ trợ 3 cấp độ network access:

  • External ingress: Accessible từ internet qua HTTPS
  • Internal ingress: Chỉ accessible từ trong environment (service-to-service)
  • No ingress: Không nhận traffic từ bên ngoài, chỉ chạy background (workers, jobs)

10.2. Managed Identity

Thay vì lưu connection strings hay API keys, sử dụng Managed Identity để authenticate với Azure services — không credential nào cần quản lý:

// Sử dụng Managed Identity để truy cập Azure SQL
builder.Services.AddDbContext<AppDbContext>(options =>
{
    var conn = new SqlConnection(builder.Configuration.GetConnectionString("Default"));
    conn.AccessToken = new DefaultAzureCredential()
        .GetToken(new TokenRequestContext(new[] { "https://database.windows.net/.default" }))
        .Token;
    options.UseSqlServer(conn);
});

// Managed Identity cho Azure Blob Storage
builder.Services.AddAzureClients(clientBuilder =>
{
    clientBuilder.AddBlobServiceClient(new Uri("https://mystorage.blob.core.windows.net"));
    clientBuilder.UseCredential(new DefaultAzureCredential());
});

10.3. Confidential Computing (Preview 2026)

ACA giờ hỗ trợ Trusted Execution Environments (TEEs) cho workloads yêu cầu bảo mật dữ liệu ở mức hardware — data được mã hóa ngay cả khi đang xử lý trong memory. Phù hợp cho fintech, healthcare, và các ứng dụng xử lý PII.

11. Observability & Monitoring

ACA tích hợp sẵn với Azure MonitorLog Analytics. Tất cả stdout/stderr từ containers được thu thập tự động.

// Cấu hình OpenTelemetry cho ACA
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddAspNetCoreInstrumentation()
        .AddHttpClientInstrumentation()
        .AddSqlClientInstrumentation()
        .AddOtlpExporter())
    .WithMetrics(metrics => metrics
        .AddAspNetCoreInstrumentation()
        .AddRuntimeInstrumentation()
        .AddOtlpExporter());
// KQL query: Top 10 slowest endpoints
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == "my-api"
| where Log_s contains "Request finished"
| parse Log_s with * "in " Duration:real "ms"
| summarize avg(Duration), p95=percentile(Duration, 95) by Endpoint=extract("Path: ([^ ]+)", 1, Log_s)
| top 10 by p95 desc

12. Tính năng mới 2026

Tháng 1/2026
Flexible Workload Profile — kết hợp tính đơn giản của Consumption với hiệu năng của Dedicated. Pay-per-use nhưng có scheduled maintenance, dedicated networking, và replicas lớn hơn.
Tháng 3/2026
Serverless GPU GA — chạy AI/ML workloads trên GPU mà không cần provision cluster. Auto-scaling, per-second billing, tối ưu cold start cho inference.
Tháng 3/2026
Confidential Computing Preview — hardware-based TEEs (Trusted Execution Environments) để bảo vệ data-in-use. Phù hợp fintech và healthcare.
Tháng 3/2026
Dynamic Workers — cho AI agents, tự động horizontal scaling với persistent state. Kết hợp với Durable Object Facets cung cấp isolated SQLite per agent.
Tháng 4/2026
Private Endpoints GA — kết nối tới Container Apps environment qua private IP trong VNet, không expose ra internet. Workflows v2 — rearchitected control plane cho higher concurrency background tasks.

13. Best Practices cho Production

13.1. Container Image

  • Dùng Alpine hoặc distroless base images để giảm attack surface
  • Multi-stage build: tách build stage (SDK) và runtime stage (ASP.NET runtime)
  • Pin image version cụ thể (aspnet:10.0.1-alpine), không dùng :latest
  • Sử dụng .dockerignore để loại bỏ bin/, obj/, .git/

13.2. Configuration & Secrets

  • Dùng environment variables thay vì appsettings.json cho cloud config
  • Sensitive values → Azure Key Vault reference, không hardcode
  • Managed Identity cho mọi Azure service — không dùng connection strings có password

13.3. Scaling & Performance

  • Đặt minReplicas: 0 cho services không cần always-on (tận dụng free tier)
  • Dùng concurrentRequests scaling rule cho HTTP APIs (thường 50-100)
  • Enable Native AOT cho minimal APIs để giảm cold start từ ~3s xuống ~100ms
  • Stateless design — không lưu state trong container, dùng external store (Redis, Cosmos DB)

13.4. Reliability

  • Cấu hình Liveness, Readiness, Startup probes đầy đủ
  • Sử dụng revision management + traffic splitting cho zero-downtime deployments
  • Deploy ở Southeast Asia (Singapore) cho latency thấp nhất từ Việt Nam
  • Thiết lập alerts trên replica count, error rate, và response time

Checklist triển khai production

✅ Health probes (liveness + readiness) configured
✅ Managed Identity cho Azure services
✅ Secrets stored in Key Vault
✅ Min 2 replicas cho critical services
✅ VNet integration cho database access
✅ Log Analytics workspace configured
✅ Custom domain + TLS certificate
✅ Resource limits (CPU/memory) set explicitly

14. Kết luận

Azure Container Apps là lựa chọn lý tưởng cho đa số .NET developers muốn chạy container mà không phải đối mặt với complexity của Kubernetes. Với free tier rộng rãi (180K vCPU-seconds, 2M requests/tháng), scale-to-zero, Dapr integration sẵn có, và các tính năng mới 2026 như Serverless GPU và Confidential Computing — ACA đủ sức đáp ứng từ side projects đến production workloads nghiêm túc.

Nếu bạn đang chạy App Service và muốn nhiều control hơn, hoặc đang dùng AKS nhưng thấy quá phức tạp cho quy mô team hiện tại — hãy thử ACA. Bạn sẽ ngạc nhiên vì nó đơn giản đến mức nào mà vẫn đủ mạnh cho production.

Tài liệu tham khảo