Module 29 FinOps 5 labs

FinOps for Cloud & DevOps

Kiểm soát và tối ưu chi phí cloud trong vòng đời DevOps: tagging policy, budget alert, rightsizing, spot/reserved instances, Kubernetes cost allocation và tích hợp FinOps vào CI/CD pipeline.

Công cụ thực hành CLI, VS Code, Git, AWS CLI, Azure CLI, kubectl, Helm, Infracost
Nền tảng AWS (Cost Explorer, Budgets), Azure (Cost Management), GCP (Billing), Kubecost
Thời điểm phát hành 23/05/2026
Ngày biên soạn 23/05/2026
Người biên soạn Trần Văn Hòa — Microsoft Certified Trainer (MCT)

Mục tiêu học tập

1. Lý thuyết cốt lõi

1.1. FinOps là gì?

FinOps (Financial Operations) là một văn hóa và thực hành kết hợp Engineering, Finance và Business để tối ưu giá trị từ chi tiêu cloud. Không phải cắt giảm chi phí — mà là chi đúng chỗ, đúng lúc, đúng mức. Định nghĩa chính thức đến từ FinOps Foundation (Linux Foundation), một tổ chức phi lợi nhuận chuẩn hóa thực hành FinOps toàn cầu.

Vòng đời FinOps — Inform → Optimize → Operate

  • Inform: Hiển thị chi phí — tagging, cost allocation, showback/chargeback, dashboards.
  • Optimize: Giảm lãng phí — rightsizing, idle resource cleanup, Reserved/Savings Plan, Spot.
  • Operate: Nhúng FinOps vào quy trình — budget alert, CI cost gate, anomaly detection, governance policy.

1.2. Tagging Policy & Cost Allocation

Tag là nền tảng của FinOps. Không có tag đúng, không phân bổ được chi phí cho team/product. Bộ tag tối thiểu: env (prod/staging/dev), team, project, cost-center, owner. Cần enforce bằng AWS Tag Policy (Organizations), Azure Policy (Deny nếu thiếu tag bắt buộc) hoặc Terraform (default_tags provider).

1.3. Rightsizing, Spot và Commitment-based Discounts

Chiến lượcMô tảTiết kiệmPhù hợp
RightsizingHạ xuống instance type nhỏ hơn theo actual CPU/mem10–40%Over-provisioned VM
Spot / PreemptibleInstance dùng capacity dư, có thể bị thu hồi60–90%Batch, CI/CD runner, ML training
Reserved InstanceCam kết 1–3 năm, trả trước một phần/toàn bộ40–60%Steady-state workload
Savings PlanCam kết mức chi tiêu $/giờ linh hoạt hơn RIup to 66%AWS compute đa dạng instance

1.4. Kubernetes Cost Allocation

Kubernetes chia sẻ node nên chi phí cluster không tự phân bổ. Cần công cụ như Kubecost hoặc OpenCost để map chi phí node → namespace → workload → label. Nguyên tắc: request/limit ratio quyết định % chi phí allocated. Pod không set request → chi phí vào "unallocated" → khó chargeback.

1.5. FinOps trong CI/CD — Shift-Left Cost

Infracost phân tích Terraform plan và tính cost diff ($Δ) trước khi merge. Tích hợp vào GitHub Actions / GitLab CI: mỗi PR hiển thị "thay đổi này tốn thêm $X/tháng", giúp engineer nhận thức chi phí ngay lúc viết code IaC.

1.6. FinOps KPI quan trọng

2. Thực hành (Labs)

LAB-141

Tạo Budget Alert trên AWS & Azure

AWS CLI · Azure CLI

🎯 Mục tiêu: Tạo budget $50/tháng trên AWS với alert 80% và 100%; tạo budget tương đương trên Azure, nhận email khi vượt ngưỡng.

🧰 Công cụ / nền tảng: AWS CLI v2, Azure CLI 2.x, VS Code, Git.

📦 Chuẩn bị: AWS CLI configured (aws configure); Azure CLI logged in (az login); có địa chỉ email nhận alert.

▶️ Phần A — AWS Budget (CLI):

# Tạo file budget definition
cat > budget.json <<'EOF'
{
  "BudgetName": "monthly-devops-budget",
  "BudgetLimit": { "Amount": "50", "Unit": "USD" },
  "TimeUnit": "MONTHLY",
  "BudgetType": "COST"
}
EOF

# Tạo file notifications (80% và 100%)
cat > notifications.json <<'EOF'
[
  {
    "Notification": {
      "NotificationType": "ACTUAL",
      "ComparisonOperator": "GREATER_THAN",
      "Threshold": 80,
      "ThresholdType": "PERCENTAGE"
    },
    "Subscribers": [
      { "SubscriptionType": "EMAIL", "Address": "[email protected]" }
    ]
  },
  {
    "Notification": {
      "NotificationType": "ACTUAL",
      "ComparisonOperator": "GREATER_THAN",
      "Threshold": 100,
      "ThresholdType": "PERCENTAGE"
    },
    "Subscribers": [
      { "SubscriptionType": "EMAIL", "Address": "[email protected]" }
    ]
  }
]
EOF

# Lấy Account ID
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo "Account ID: $ACCOUNT_ID"

# Tạo budget
aws budgets create-budget \
  --account-id "$ACCOUNT_ID" \
  --budget file://budget.json \
  --notifications-with-subscribers file://notifications.json

# Xác nhận
aws budgets describe-budgets --account-id "$ACCOUNT_ID" \
  --query 'Budgets[?BudgetName==`monthly-devops-budget`].[BudgetName,BudgetLimit.Amount]' \
  --output table

▶️ Phần B — Azure Budget (CLI):

# Lấy subscription ID
SUB_ID=$(az account show --query id -o tsv)
echo "Subscription: $SUB_ID"

# Tạo budget $50/tháng với alert 80% và 100%
az consumption budget create \
  --budget-name "devops-monthly-budget" \
  --amount 50 \
  --time-grain Monthly \
  --start-date "2026-06-01" \
  --end-date "2027-05-31" \
  --resource-group "rg-devops" \
  --category Cost

# Thêm alert notification (Azure Portal hoặc REST API)
# Qua Portal: Cost Management → Budgets → chọn budget → Add alert

# Kiểm tra budget đã tạo
az consumption budget list --query '[].{Name:name, Amount:amount, CurrentSpend:currentSpend.amount}' -o table

🖥️ Đối chiếu GUI:

AWS Console: Billing → Budgets → Create budget. Azure Portal: Cost Management + Billing → Budgets → Add.

✅ Kết quả mong đợi: aws budgets describe-budgets trả về budget monthly-devops-budget với Amount=50 USD; Azure CLI liệt kê budget devops-monthly-budget. Email nhận thông báo test khi trigger threshold.

🧹 Cleanup:

# AWS
aws budgets delete-budget --account-id "$ACCOUNT_ID" --budget-name "monthly-devops-budget"
# Azure
az consumption budget delete --budget-name "devops-monthly-budget"
LAB-142

Tagging Policy — Enforce & Audit

AWS CLI · Azure CLI · Terraform

🎯 Mục tiêu: Định nghĩa tagging standard, enforce bằng Azure Policy (Deny) và kiểm tra tag coverage bằng CLI. Hiểu cách Terraform default_tags tự động gán tag.

🧰 Công cụ / nền tảng: Azure CLI, Terraform ≥1.5, VS Code, Git.

📦 Chuẩn bị: Azure subscription; Terraform installed; resource group rg-finops-lab đã tạo.

▶️ Phần A — Azure Policy: yêu cầu tag envteam:

# Xem built-in policy "Require a tag on resources"
az policy definition list --query "[?displayName=='Require a tag on resources'].{Name:name,ID:id}" -o table

# Assign policy yêu cầu tag "env"
az policy assignment create \
  --name "require-env-tag" \
  --display-name "Require env tag on all resources" \
  --policy "871b6d14-10aa-478d-b590-94f262ecfa99" \
  --params '{"tagName":{"value":"env"}}' \
  --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-finops-lab" \
  --enforcement-mode Default

# Assign policy yêu cầu tag "team"
az policy assignment create \
  --name "require-team-tag" \
  --display-name "Require team tag on all resources" \
  --policy "871b6d14-10aa-478d-b590-94f262ecfa99" \
  --params '{"tagName":{"value":"team"}}' \
  --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-finops-lab" \
  --enforcement-mode Default

# Kiểm tra policy assignments
az policy assignment list --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-finops-lab" \
  --query '[].{Name:name,DisplayName:displayName,EnforcementMode:enforcementMode}' -o table

▶️ Phần B — Terraform default_tags:

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

provider "azurerm" {
  features {}
}

# default_tags tự động gán cho mọi resource trong provider block
locals {
  default_tags = {
    env         = "dev"
    team        = "platform"
    project     = "finops-lab"
    cost-center = "CC-001"
    owner       = "tran.van.hoa"
    managed-by  = "terraform"
  }
}

resource "azurerm_resource_group" "lab" {
  name     = "rg-finops-lab"
  location = "Southeast Asia"
  tags     = local.default_tags
}

resource "azurerm_storage_account" "lab" {
  name                     = "stfinopslab${random_integer.suffix.result}"
  resource_group_name      = azurerm_resource_group.lab.name
  location                 = azurerm_resource_group.lab.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
  tags                     = local.default_tags
}

resource "random_integer" "suffix" {
  min = 1000
  max = 9999
}

# Audit tag coverage bằng CLI
az resource list --resource-group rg-finops-lab \
  --query '[].{Name:name,Type:type,EnvTag:tags.env,TeamTag:tags.team}' -o table

✅ Kết quả mong đợi: Thử tạo resource không có tag env → Azure trả lỗi Policy deny. CLI audit hiển thị tất cả resource có đầy đủ envteam tags.

🧹 Cleanup:

terraform destroy -auto-approve
az policy assignment delete --name "require-env-tag" --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-finops-lab"
az policy assignment delete --name "require-team-tag" --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/rg-finops-lab"
LAB-143

Rightsizing VM — Phân tích & Report

AWS CLI · Azure CLI · PowerShell

🎯 Mục tiêu: Truy vấn rightsizing recommendation từ AWS Cost Explorer và Azure Advisor, export CSV report, tính potential savings.

🧰 Công cụ / nền tảng: AWS CLI v2, Azure CLI, PowerShell, VS Code, Git.

📦 Chuẩn bị: AWS account với Cost Explorer enabled (tốn $0.01/request); Azure subscription có VM đã chạy ≥14 ngày để Advisor có data.

▶️ Phần A — AWS Cost Explorer Rightsizing:

# Lấy rightsizing recommendations cho EC2
aws ce get-rightsizing-recommendation \
  --service "AmazonEC2" \
  --configuration '{"RecommendationTarget":"SAME_INSTANCE_FAMILY","BenefitsConsidered":true}' \
  --query 'RightsizingRecommendations[*].{
    CurrentType:CurrentInstance.InstanceType,
    RecommendedType:RightsizingType,
    MonthlySavings:ModifyRecommendationDetail.TargetInstances[0].EstimatedMonthlySavings.Value,
    Currency:ModifyRecommendationDetail.TargetInstances[0].EstimatedMonthlySavings.Currency
  }' \
  --output table

# Tổng tiết kiệm ước tính
aws ce get-rightsizing-recommendation \
  --service "AmazonEC2" \
  --configuration '{"RecommendationTarget":"SAME_INSTANCE_FAMILY","BenefitsConsidered":true}' \
  --query 'Summary.{TotalRecommendations:TotalRecommendationCount,MonthlySavings:EstimatedTotalMonthlySavingsAmount,Currency:SavingsCurrencyCode}' \
  --output json

▶️ Phần B — Azure Advisor Rightsizing:

# Lấy Advisor recommendations loại Cost
az advisor recommendation list \
  --category Cost \
  --query '[?impactedField==`microsoft.compute/virtualmachines`].{
    ResourceName:impactedValue,
    Impact:impact,
    Problem:shortDescription.problem,
    Solution:shortDescription.solution
  }' -o table

# Export CSV bằng PowerShell
$recs = az advisor recommendation list --category Cost | ConvertFrom-Json
$report = $recs | Where-Object { $_.impactedField -eq "microsoft.compute/virtualmachines" } |
  Select-Object @{N='Resource';E={$_.impactedValue}},
                @{N='Impact';E={$_.impact}},
                @{N='Problem';E={$_.shortDescription.problem}}
$report | Export-Csv -Path rightsizing-report.csv -NoTypeInformation -Encoding UTF8
Write-Host "Saved: rightsizing-report.csv"
Import-Csv rightsizing-report.csv | Format-Table

✅ Kết quả mong đợi: AWS CLI liệt kê các EC2 instance có thể downsize với estimated savings USD/tháng. Azure Advisor trả danh sách VM với Impact (High/Medium/Low). File rightsizing-report.csv chứa danh sách VM cần xem xét.

🧹 Cleanup: Không tạo resource — xóa file CSV nếu không cần: Remove-Item rightsizing-report.csv

LAB-144

Infracost trong CI — Cost Gate cho Terraform PR

CLI · Infracost · GitHub Actions · Terraform

🎯 Mục tiêu: Tích hợp Infracost vào GitHub Actions để tự động comment cost diff ($Δ/tháng) lên mỗi PR chứa thay đổi Terraform.

🧰 Công cụ / nền tảng: Infracost CLI, GitHub Actions, Terraform, VS Code, Git.

📦 Chuẩn bị: Đăng ký API key tại infracost.io (free tier); GitHub repo có Terraform code; thêm secret INFRACOST_API_KEY vào repo.

▶️ Bước 1 — Cài Infracost CLI cục bộ:

# Linux/macOS
curl -fsSL https://raw.githubusercontent.com/infracost/infracost/master/scripts/install.sh | sh

# Windows (PowerShell)
winget install Infracost.Infracost
# Hoặc: choco install infracost

# Đăng ký API key
infracost auth login

# Kiểm tra
infracost --version

▶️ Bước 2 — Chạy locally để kiểm tra:

cd terraform/

# Tạo baseline cost từ main branch
git checkout main
infracost breakdown --path . --format json --out-file /tmp/infracost-base.json

# Tạo cost từ feature branch
git checkout feature/add-rds
infracost breakdown --path . --format json --out-file /tmp/infracost-pr.json

# So sánh diff
infracost diff \
  --path /tmp/infracost-pr.json \
  --compare-to /tmp/infracost-base.json \
  --format table

# Output mẫu:
# Project: terraform/
# ─────────────────────────────────
# + aws_db_instance.main        +$51.10/mo
# ─────────────────────────────────
# Monthly cost change: +$51.10 (+34%)

▶️ Bước 3 — GitHub Actions workflow:

# .github/workflows/infracost.yml
name: Infracost Cost Review

on:
  pull_request:
    paths:
      - 'terraform/**'

jobs:
  infracost:
    name: Cost Estimate
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write

    steps:
      - name: Checkout PR branch
        uses: actions/checkout@v4

      - name: Setup Infracost
        uses: infracost/actions/setup@v3
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}

      - name: Checkout base branch for comparison
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.base.ref }}
          path: base-branch

      - name: Generate Infracost cost estimate baseline
        run: |
          infracost breakdown --path=base-branch/terraform \
            --format=json \
            --out-file=/tmp/infracost-base.json

      - name: Generate Infracost diff
        run: |
          infracost diff --path=terraform \
            --format=json \
            --compare-to=/tmp/infracost-base.json \
            --out-file=/tmp/infracost-diff.json

      - name: Post Infracost comment
        uses: infracost/actions/comment@v3
        with:
          path: /tmp/infracost-diff.json
          behavior: update

✅ Kết quả mong đợi: Mỗi khi tạo PR có thay đổi Terraform, GitHub Actions tự động comment cost breakdown lên PR với bảng +/- $Δ/tháng cho từng resource. Engineer thấy ngay "thêm RDS tốn thêm $51/tháng" trước khi merge.

🧹 Cleanup: Không tạo cloud resource; xóa workflow file nếu không cần: git rm .github/workflows/infracost.yml

LAB-145

Kubecost — Kubernetes Cost Allocation

kubectl · Helm · Kubecost

🎯 Mục tiêu: Cài Kubecost trên cluster Kubernetes, xem cost allocation theo namespace, xác định namespace tốn kém nhất và namespace có unallocated cost.

🧰 Công cụ / nền tảng: kubectl, Helm ≥3.10, Kubernetes cluster (k3d/minikube/EKS/AKS), VS Code, Git.

📦 Chuẩn bị: kubectl context trỏ đến cluster; Helm installed; cluster có ≥2 CPU và 4GB RAM.

▶️ Bước 1 — Tạo cluster local với k3d (nếu chưa có):

# Cài k3d
curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash

# Tạo cluster 3 node
k3d cluster create finops-lab --agents 2 --port "8080:80@loadbalancer"
kubectl cluster-info

▶️ Bước 2 — Deploy demo workloads:

# Tạo namespaces đại diện các team
kubectl create namespace team-frontend
kubectl create namespace team-backend
kubectl create namespace team-data

# Deploy workload giả với resource requests
kubectl create deployment frontend --image=nginx --replicas=3 -n team-frontend
kubectl set resources deployment/frontend --requests=cpu=100m,memory=128Mi -n team-frontend

kubectl create deployment backend --image=nginx --replicas=5 -n team-backend
kubectl set resources deployment/backend --requests=cpu=200m,memory=256Mi -n team-backend

kubectl create deployment data-pipeline --image=nginx --replicas=2 -n team-data
kubectl set resources deployment/data-pipeline --requests=cpu=500m,memory=512Mi -n team-data

# Verify
kubectl get pods -A | grep -E "team-"

▶️ Bước 3 — Cài Kubecost bằng Helm:

# Thêm Helm repo Kubecost
helm repo add kubecost https://kubecost.github.io/cost-analyzer/
helm repo update

# Cài vào namespace kubecost (free tier - không cần API key)
helm install kubecost kubecost/cost-analyzer \
  --namespace kubecost \
  --create-namespace \
  --set kubecostToken="" \
  --set prometheus.nodeExporter.enabled=true \
  --set prometheus.pushgateway.enabled=false \
  --wait --timeout=5m

# Kiểm tra pods
kubectl get pods -n kubecost

▶️ Bước 4 — Truy cập dashboard & query API:

# Port-forward Kubecost UI
kubectl port-forward -n kubecost svc/kubecost-cost-analyzer 9090:9090 &
# Mở trình duyệt: http://localhost:9090

# Query cost allocation API (sau khi có ít nhất 1 giờ data)
# Cost theo namespace (last 7 ngày)
curl -s "http://localhost:9090/model/allocation?window=7d&aggregate=namespace&accumulate=false" \
  | python3 -m json.tool | head -80

# Cost theo label "app"
curl -s "http://localhost:9090/model/allocation?window=24h&aggregate=label:app" \
  | python3 -m json.tool

# Efficiency report — namespace nào lãng phí nhất
curl -s "http://localhost:9090/model/allocation?window=7d&aggregate=namespace&accumulate=true" \
  | python3 -c "
import json, sys
data = json.load(sys.stdin)
for ns, v in data['data'][0].items():
    cpu_eff = v.get('cpuEfficiency', 0)
    mem_eff = v.get('ramEfficiency', 0)
    cost = v.get('totalCost', 0)
    print(f'{ns:30s} cost=\${cost:.3f}  cpu_eff={cpu_eff:.1%}  mem_eff={mem_eff:.1%}')
"

✅ Kết quả mong đợi: Kubecost UI tại http://localhost:9090 hiển thị cost breakdown theo namespace. API query trả JSON với totalCost, cpuEfficiency, ramEfficiency per namespace. Xác định được namespace nào có efficiency thấp nhất (ứng viên optimize request/limit).

🧹 Cleanup:

helm uninstall kubecost -n kubecost
kubectl delete namespace team-frontend team-backend team-data kubecost
# Nếu dùng k3d
k3d cluster delete finops-lab

3. Tình huống doanh nghiệp thực tế

Bối cảnh: Startup SaaS — hóa đơn AWS tăng 3x trong 6 tháng

Một công ty SaaS B2B với 50 developers đang dùng multi-cloud (AWS chính + Azure cho office). Cloud bill AWS đột ngột tăng từ $8,000/tháng lên $24,000/tháng sau khi scale Kubernetes. Không ai biết team nào tốn nhiều nhất. CTO yêu cầu kiểm soát trong 30 ngày.

Giải pháp FinOps theo vòng đời:

  • Inform (Tuần 1): Enforce tagging policy (team/env/project) bằng Terraform default_tags. Cài Kubecost → phát hiện namespace ml-training chiếm 40% cost cluster do không set resource limit, chạy GPU instance suốt đêm dù job xong.
  • Optimize (Tuần 2–3): ML jobs chuyển sang Spot Instance (tiết kiệm 70%). Rightsizing 15 EC2 t3.xlarge → t3.large (CPU usage <20%). Mua Savings Plan $3,000/tháng cho steady-state workload → tiết kiệm thêm $1,800/tháng.
  • Operate (Tuần 4): Tích hợp Infracost vào CI → mọi PR thêm resource lớn phải có approval CFO. Budget alert $20,000 với escalation tự động lên Slack. Monthly FinOps review: team lead xem cost report, giải thích tăng/giảm.
  • Kết quả sau 30 ngày: Bill giảm từ $24,000 xuống $13,500/tháng (-44%). Tag coverage đạt 98%. Unit cost ($/transaction) giảm 31%. Engineer có ý thức chi phí vì thấy Infracost comment ngay trên PR.

📚 Nguồn tham khảo

Module 28: Cloud Security AWS/Azure/GCP Module 30: Platform Engineering & IDP
Zalo