Giới thiệu

Cùng với sự phát triển của ngành công nghệ thông tin trong những năm gần đây, việc sử dụng các dịch vụ điện toán đám mây như Amazon Web Service (AWS) đã không còn quá xa lạ đối với các công ty nói chung và các lập trình viên nói riêng. Cùng với những lợi ích to lớn của việc sử dụng AWS mang lại như: khả năng mở rộng (scalability), tính tin cậy (reliability), tính linh hoạt (flexibility),… việc quản lí chi phí cũng là một vấn đề vô cùng quan trọng và khá đau đầu khi sử dụng các dịch vụ của AWS. Tối ưu chi phí cũng là một trong 6 khía cạnh quan trọng nhất khi chúng ta muốn xây dựng một kiến trúc tốt trên AWS.

aws well architecture

Chuỗi bài viết này sẽ giới thiệu đến các bạn những công cụ giúp việc quản lý và tối ưu chi phí khi sử dụng AWS một cách hiệu quả hơn.

Trong bài đầu tiên, chúng ta sẽ cùng tìm hiểu AWS Budget, một công cụ giúp bản quản lý ngân sách sử dụng AWS hiệu quả

AWS Budget là gì?

AWS Budget là một dịch vụ miễn phí của AWS được thiết kế để giúp người dùng quản lý chi phí của họ trong môi trường đám mây của AWS. Dịch vụ này cho phép người dùng thiết lập và theo dõi các ngân sách chi phí và sử dụng tùy chỉnh, và cung cấp cảnh báo khi các ngưỡng ngân sách bị vượt quá hoặc dự báo sẽ vượt quá. Bằng cách này, người dùng có thể kiểm soát và quản lý chi phí của mình một cách hiệu quả, giúp họ tối ưu hóa việc sử dụng tài nguyên và đảm bảo rằng các dự án và ứng dụng của họ đang hoạt động trong phạm vi ngân sách.

Ngoài việc theo dõi ngân sách, bạn cũng có thể thêm các hành động vào ngân sách của mình để kiểm soát các tài nguyên AWS khi ngưỡng ngân sách bị hoặc được dự báo sẽ vượt quá.

aws budget

Các loại budget:

  • Cost budget: theo dõi chi phí của bạn so với số tiền được chỉ định và nhận thông báo khi đạt đến ngưỡng do người dùng xác định. Số tiền dự toán bạn đặt sẽ thể hiện mức chi tiêu dự kiến của bạn trên AWS.
  • Usage budget: bạn có thể sử dụng ngân sách sử dụng để giám sát việc sử dụng một số dịch vụ nhất định như Amazon EC2 và Amazon S3.
  • Savings Plans budget: Định nghĩa ngưỡng sử dụng và nhận thông báo khi mức sử dụng Savings Plans của bạn giảm xuống dưới ngưỡng đó.
  • Reservation budget: Định nghĩa ngưỡng sử dụng và nhận thông báo khi mức sử dụng Reversed Instance của bạn giảm xuống dưới ngưỡng đó.

Tạo và kiểm soát tài nguyên với AWS Budget

Trong phần này chúng ta cùng thực hiện một ví dụ đơn giản sử dụng AWS budget để quản lý chi phí, đồng thời tự động tắt các dịch vụ khác khi vượt qua ngưỡng chi phí định trước. Các bước thực hiện bao gồm:

  1. Tạo một budget
  2. Sử dụng dịch vụ SNS để gửi thông báo và trigger các hành động.
  3. Tạo Lambda Function để tắt các dịch vụ khác như EC2 khi vượt ngưỡng budget

budget example

Ngoài ra, khác với những bài viết khác, bài viết này sẽ sử dụng Terraform để tạo và quản lý tài nguyên thay vì sử dụng AWS Console. Terraform là một công cụ mạnh mẽ giúp có việc quản lý tài nguyên bằng mã nguồn (Infrastructure as Code). Bạn có thể tìm hiểu thêm về những lợi ích của IaS tại đây.

Yêu cầu

  • Cài đặt terraform: có xem hướng dẫn tại đây
  • AWS credentials: bao gồm access_keysecret_key. Chúng ta cần AWS credential khi cấu hình provider cho terraform
// filename: provider.tf
provider "aws" {
  region = "us-east-1"
  access_key = "xxxxxx"
  secret_key = "xxxxxx"
}

Tiếp theo chúng ta sẽ định nghĩa cấu hình tài nguyên với terraform

Cấu hình Budget

// filename: budget.tf
resource "aws_budgets_budget" "monthly_cost_budget" {
  name              = "Monthly-Cost-Budget"
  budget_type       = "COST"
  limit_amount      = 100.0
  limit_unit        = "USD"
  time_period_start = "2024-01-01_00:00"
  time_period_end   = "2024-12-31_23:59"
  time_unit         = "MONTHLY"
  
  cost_filter {
    name = "Service"
    values = [
      "Amazon Elastic Compute Cloud - Compute",
    ]
  }

  notification {
    comparison_operator = "GREATER_THAN"
    threshold           = 90
    threshold_type      = "PERCENTAGE"
    notification_type   = "ACTUAL"
    subscriber_email_addresses = ["test@example.com"]
  }
  
  notification {
    comparison_operator = "GREATER_THAN"
    notification_type   = "ACTUAL"
    threshold_type      = "PERCENTAGE"
    threshold           = 80
    subscriber_sns_topic_arns = [aws_sns_topic.budget_notifications.arn]
  }
}

Trong đó, các thuộc tính của aws_budgets_budget :

  • name: Tên của budget.
  • budget_type: Loại budget, có thể là COST hoặc USAGE.
  • limit_amount: Ngưỡng giới hạn của budget. Ví dụ 100$.
  • limit_unit: Đơn vị tiền tệ của budget.
  • time_period_start and time_period_end: Khoảng thời gian bắt đầu và kết thúc của budget.
  • time_unit: đơn vị thời gian budget của bạn, theo tháng MONTHLY, theo quý QUARTERLY, hoặc ANNUALLY.
  • cost_filter: Lọc theo một dịch vụ cụ thể. Ở đây, chúng ta quan tâm đến chi phí của EC2.
  • notification: Cài đặt thông báo khi vượt ngưỡng budget. Ở đây chúng ta sẽ gửi thông báo đến email chỉ định khi chi phí thực tế ACTUAL vượt quá 90% budget. Đồng thời, gửi thông báo đến SNS topicbudget_notifications khi vượt quá 80% budget. SNS topic này sẽ được hướng dẫn tạo ngay sau đây.

Chi tiết định nghĩa các thuộc tính budget có thể tham khảo tại đây.

Cấu hình SNS topic

// filename: sns.tf
resource "aws_sns_topic" "budget_notifications" {
  name = "budget-notifications"
}

resource "aws_sns_topic_subscription" "lambda_subscription" {
  topic_arn = aws_sns_topic.budget_notifications.arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.instance_shutdown.arn
}

resource "aws_lambda_permission" "allow_sns" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.instance_shutdown.function_name
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.budget_notifications.arn
}

Trong phần này, chúng ta định nghĩa 3 tài nguyên:

  • SNS topic budget_notifications
  • SNS topic subscription: hàm Lambda instance_shutdown sẽ theo dõi và nhận trigger từ SNS topic
  • Lambda permission: quyền cho phép SNS topic budget_notifications gọi hàm instance_shutdown

Cấu hình hàm Lambda và IAM Role cho hàm

// filename: lambda.tf
resource "aws_lambda_function" "instance_shutdown" {
  filename         = "lambda_function.zip"
  function_name    = "instanceShutdown"
  role             = aws_iam_role.lambda_exec.arn
  handler          = "lambda_function.lambda_handler"
  source_code_hash = filebase64sha256("lambda_function.zip")
  runtime          = "python3.8"

  environment {
    variables = {
      INSTANCE_REGION = "us-east-1"
    }
  }
}

Các thuộc tính của lambda function instance_shutdown:

  • filename:đường dẫn đến tệp file ZIP chứa code hàm Lambda. Trong trường hợp này, mã được đóng gói trong lambda_function.zip.
  • function_name: tên hàm
  • role: IAM Role mà hàm Lambda sử dụng để thực hiện các hành động. Ví dụ, Lambda phải có quyền tắt các EC2 instances. Role này sẽ được tạo ngay sau đây.
  • handler: Điểm đầu vào của hàm Lambda. Trong ví dụ này, lambda_function.lambda_handler tham chiếu đến hàm lambda_handler bên trong tệp lambda_function.py.
  • runtime: Chỉ định môi trường runtime cho hàm Lambda
  • Ngoài ra, chúng ta định nghĩa mội biến môi trường INSTANCE_REGION , biến này sẽ được sử dụng trong hàm Lambda với mục đích là xóa các EC2 instance tại vùng này.

Cấu hình IAM Role cho hàm Lambda

// filename: iam.tf
resource "aws_iam_role" "lambda_exec" {
  name = "lambda_exec_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_policy" "lambda_ec2_policy" {
  name        = "lambda_ec2_policy"
  description = "Policy to allow Lambda to stop EC2 instances"
  
  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "ec2:DescribeInstances",
          "ec2:StopInstances"
        ]
        Resource = "*"
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_attach" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = aws_iam_policy.lambda_ec2_policy.arn
}

resource "aws_iam_role_policy_attachment" "lambda_basic_attach" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

Ở phần này, chúng ta khai báo IAM Role lambda_exec sử dụng cho hàm Lambda, với 2 policy:

  • assume_role_policy : Policy cho phép hàm Lambda sử dụng role này
  • lambda_ec2_policy: Policy với 2 quyền là mô tả ec2:DescribeInstancesvà tắt EC2 Instances ec2:StopInstances

Mã nguồn hàm Lambda

Cuối cùng chúng ta cùng viết mã nguồn cho hàm Lambda như sau:

# filename: lambda_function.py
import boto3
import os

def lambda_handler(event, context):
    region = os.environ['INSTANCE_REGION']
    ec2 = boto3.client('ec2', region_name=region)
    
    instances = ec2.describe_instances(Filters=[{'Name': 'instance-state-name', 'Values': ['running']}])
    for reservation in instances['Reservations']:
        for instance in reservation['Instances']:
            instance_id = instance['InstanceId']
            ec2.stop_instances(InstanceIds=[instance_id])
            print(f'Stopped instance: {instance_id}')

Hàm này đơn giản chúng ta stop tất cả các EC2 instance tại vùng được lấy ra từ biến môi trường INSTANCE_REGION

Tạo tài nguyên trên AWS với Terraform

Bây giờ, chúng ta sẽ sử dụng các terraform command để tạo tài nguyên thực sự trên AWS, dựa vào các file cấu hình chúng ta định nghĩa phía trên.

Các terraform command cơ bản như sau:

  • terraform init: Khởi tạo môi trường
  • terraform validate: validate cú pháp của các file cấu hình
  • terraform plan: plan các thay đổi giữa các file cấu hình hiện tại và môi trường thực
  • terraform apply: Tạo hoặc update tài nguyên trên môi trường thật
  • terraform destroy: Xóa tài nguyên đã tạo trước đó

Sau khi thực hiện terraform apply , chúng ta cùng kiểm tra các tài nguyên đã được tạo trên môi trường AWS:

running budgetMontly Cost Budget

running snsSNS Budget notification topic

running lambdaHàm Lambda thực hiện dừng các EC2 instances khi vượt budget

Kết luận

Trong bài viết này, chúng ta đã cùng tìm hiểu về AWS Budget, một công cụ hiệu quả để quản lý ngân sách khi sử dụng AWS. Đồng thời, chúng ta đã cùng triển khai một ví dụ đơn giản để tắt các tài nguyên đang sử dụng khi đã vượt ngân sách.

Bạn có thể tham khảo toàn bộ source code trong bài viết tại đây.