EngineeringSolution ArchitectPlatform and DevOps

Session 03 - Deployment Strategies

Tổng quan các chiến lược

StrategyDowntimeRiskRollback speedChi phí
Blue-GreenZeroThấpNgay lập tức (swap)2x resource
CanaryZeroRất thấpNhanh (route lại)+10-20% resource
RollingZeroTrung bìnhChậm (roll back từng instance)Bằng hiện tại
RecreateCóCaoChậm (redeploy)Bằng hiện tại

Blue-Green Deployment - Azure App Service Slots

Playbook hoàn chỉnh

bash
# 1. Tạo deployment slot (chỉ cần 1 lần)
az webapp deployment slot create \
  --name myapp-production \
  --resource-group rg-myapp \
  --slot staging

# 2. Cấu hình slot settings (không swap theo slot)
az webapp config appsettings set \
  --name myapp-production \
  --resource-group rg-myapp \
  --slot staging \
  --settings ASPNETCORE_ENVIRONMENT=Staging

# 3. Deploy code lên staging slot
az webapp deploy \
  --name myapp-production \
  --resource-group rg-myapp \
  --slot staging \
  --src-path ./publish.zip \
  --type zip

# 4. Warm up staging slot - quan trọng tránh cold start
curl -s https://myapp-production-staging.azurewebsites.net/health

# 5. Swap staging → production (zero downtime)
az webapp deployment slot swap \
  --name myapp-production \
  --resource-group rg-myapp \
  --slot staging \
  --target-slot production

# 6. Verify production
curl -s https://myapp-production.azurewebsites.net/health

# ROLLBACK nếu có lỗi - swap ngược lại
az webapp deployment slot swap \
  --name myapp-production \
  --resource-group rg-myapp \
  --slot staging \
  --target-slot production

GitHub Actions - Blue-Green Pipeline

yaml
deploy-production:
  runs-on: ubuntu-latest
  environment: production
  steps:
    - uses: azure/login@v2
      with:
        creds: ${{ secrets.AZURE_CREDENTIALS }}

    - name: Deploy to Staging Slot
      uses: azure/webapps-deploy@v3
      with:
        app-name: myapp-production
        slot-name: staging
        package: ./publish

    - name: Warm Up
      run: |
        for i in {1..5}; do
          curl -sf https://myapp-production-staging.azurewebsites.net/health && break
          sleep 10
        done

    - name: Swap Slots
      run: |
        az webapp deployment slot swap \
          --name myapp-production \
          --resource-group rg-myapp \
          --slot staging \
          --target-slot production

Canary Releases

Dùng Azure App Service traffic routing:

bash
# Gửi 10% traffic sang staging slot (canary)
az webapp traffic-routing set \
  --name myapp-production \
  --resource-group rg-myapp \
  --distribution staging=10

# Monitor metrics, nếu OK → tăng dần
az webapp traffic-routing set \
  --distribution staging=50

# Hoàn tất → swap
az webapp deployment slot swap \
  --name myapp-production \
  --resource-group rg-myapp \
  --slot staging

# Clear traffic routing
az webapp traffic-routing clear \
  --name myapp-production \
  --resource-group rg-myapp

Feature Flags - Azure App Configuration

Setup trong .NET

csharp
// Program.cs
builder.Configuration.AddAzureAppConfiguration(options =>
{
    options.Connect(builder.Configuration["AppConfig:ConnectionString"])
           .UseFeatureFlags(flagOptions =>
           {
               flagOptions.CacheExpirationInterval = TimeSpan.FromSeconds(30);
           });
});

builder.Services.AddAzureAppConfiguration();
builder.Services.AddFeatureManagement();
csharp
// Controller sử dụng feature flag
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly IFeatureManager _featureManager;

    public OrdersController(IFeatureManager featureManager)
    {
        _featureManager = featureManager;
    }

    [HttpPost]
    public async Task<IActionResult> CreateOrder(OrderRequest request)
    {
        if (await _featureManager.IsEnabledAsync("NewOrderFlow"))
        {
            return await CreateOrderV2(request);
        }
        return await CreateOrderV1(request);
    }
}
bash
# Tạo feature flag trong Azure App Configuration
az appconfig feature set \
  --name myapp-appconfig \
  --feature NewOrderFlow \
  --label Production

# Enable feature flag
az appconfig feature enable \
  --name myapp-appconfig \
  --feature NewOrderFlow \
  --label Production

# Disable (rollback feature)
az appconfig feature disable \
  --name myapp-appconfig \
  --feature NewOrderFlow \
  --label Production

Zero-Downtime Database Migration

Database migration là phần khó nhất trong zero-downtime deployment. Nguyên tắc chính:

Expand-Contract Pattern

Ví dụ: Rename column an toàn

csharp
// Migration 1: Thêm column mới (deploy cùng app v1)
public partial class AddNewEmailColumn : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        // Expand: thêm column mới, copy data
        migrationBuilder.AddColumn<string>(
            name: "EmailAddress",
            table: "Users",
            nullable: true);
        
        migrationBuilder.Sql(
            "UPDATE Users SET EmailAddress = Email");
    }
}

// Migration 2: Drop column cũ (deploy cùng app v2, sau khi v1 không còn chạy)
public partial class RemoveOldEmailColumn : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        // Contract: xoá column cũ
        migrationBuilder.DropColumn(
            name: "Email",
            table: "Users");
    }
}

Playbook: Safe Database Migration

bash
# 1. Tạo migration
dotnet ef migrations add AddNewEmailColumn

# 2. Generate SQL script (review trước khi chạy)
dotnet ef migrations script --idempotent -o migration.sql

# 3. Review SQL script - check không có breaking changes
#    - Không DROP column đang dùng
#    - Không ALTER column type không compatible
#    - Không thêm NOT NULL constraint trên column cũ

# 4. Apply migration trên staging trước
dotnet ef database update --connection "staging-connection"

# 5. Deploy app mới (tương thích cả schema cũ và mới)

# 6. Verify, sau đó apply migration contract phase

Rollback Procedures

Tình huốngHành độngThời gian
App lỗi, DB không đổiSwap slot lại< 30s
App lỗi, DB có migration compatibleSwap slot + keep DB< 30s
App lỗi, DB có breaking migrationRollback migration + swap slot5-30 phút
Data corruptionRestore DB backup + redeploy30-60 phút

Best practice: Luôn test rollback procedure trên staging. Tự động hoá rollback trong pipeline với health check gate - nếu health check fail sau deploy, tự động swap lại.