Tối ưu hóa chi phí sử dụng Lambda và Tags

Bạn có một số máy chủ chỉ cần khởi chạy thực hiện một số tác vụ hằng ngày và sau đó sẽ được tắt đi để tiết kiệm chi phí. Vậy bạn đã tìm đúng bài viết phục vụ cho nhu cầu của bạn rồi.

Bài viết này sẽ hướng dẫn cách sử dụng Lambda function để tối ưu chi phí cho hệ thống của bạn trên môi trường AWS.
Mô hình triển khai bạn có thể xem như hình bên dưới:

Bài viết sẽ bao gồm một số bước như sau:

I. Thêm các Tag cho Instance

II. Thêm Role cho Lambda

III. Tạo các Lambda Function

IV. Kiểm tra kết quả

I. THÊM CÁC TAG CHO MÁY CHỦ ẢO CẦN LẬP LỊCH

Thông thường, chúng ta sẽ gắn các Tag cho instance để nhằm lọc ra những instance cần thực hiện công việc tối ưu.

Có thể ví dụ như sau:

Name : application-instance
Environment_Auto : true

Thêm Tag cho Instance

II. THÊM ROLE CHO LAMBDA

  1. Trong Bảng điều khiển IAM, truy cập vào mục Roles
  2. Tạo một Role mới với Trust Entity được lựa chọn:
    – Common use cases : Lambda
  3. Ở role Permission, chọn hai policy được tạo sẵn:
    – AmazonEC2FullAccess
    – CloudWatchFullAccess
  4. Bạn có thể đặt bất kì tên gì cho Role này (VD: dc-common-lambda-role)
Tạo một Role mới với đầy đủ Permission cho Lambda

III. TẠO LAMBDA FUNCTION

Tạo Function dừng các máy ảo

  1. Trong Bảng điều khiển Lambda, chọn vào mục Functions.
  2. Tạo một Function mới với các thông số:
    – Function name : dc-common-lambda-auto-stop
    – Runtime : Python 3.8
    – Permission : Chọn Use an existing role với tên role đã tạo ở trên dc-common-lambda-role
  3. Thêm vô biến môi trường cho Function:
    – Key : Enviroment_Auto
    – Value : true
    1. Ở mục Function code sẽ sử dụng đoạn mã nguồn sau: (Hãy thay đổi webhook_urlđể nhận được thông báo khi Lambda được trigger)
    import boto3
    import os
    import json
    import urllib3ec2_resource = boto3.resource('ec2')
    http = urllib3.PoolManager()
    webhook_url = "https://hooks.slack.com/services/T01H4J6EGGN/B01J15NP6E4/XXXXXXXXXXXXXXX"def lambda_handler(event, context):
        environment_auto= os.environ.get('environment_auto')
        if not environment_auto:
            print('Target is empty')
        else:
            instances = ec2_resource.instances.filter(
                Filters=[{'Name': 'tag:Enviroment_Auto', 'Values': [environment_auto]}]
            )     
            if not list(instances):
                response = {
                    "statusCode":500,
                    "body": "Target Instance is None"
                }
            else:
                action_stop = instances.stop()
                sent_slack(action_stop)
                response = {
                    "statusCode":200,
                    "body": "EC2 Stopping"
                }
            return responsedef sent_slack(action_stop):
        list_instance_id = []
        if (len(action_stop)>0) and ("StoppingInstances" in action_stop[0]) and (len(action_stop[0]["StoppingInstances"])>0):
            for i in action_stop[0]["StoppingInstances"] :
                list_instance_id.append(i["InstanceId"])
                msg = "Stopping Instances ID:\n %s" %(list_instance_id)
                data = {"text":msg}
                r = http.request("POST",
                    webhook_url,
                    body = json.dumps(data),
                    headers = {"Content-Type":"application/json"})
        else:
            print ('Not found Instances Stop')

    Tạo CloudWatch Rule thực thi Lambda Function dừng máy chủ ảo.

  1. Trong Bảng điều khiển CloudWatch, chọn vào mục Events Rules.
  2. Tạo một Rule mới với các thông số:
    – Event Source :
    Schedule Cron expression > Chọn khoảng thời gian
    (VD: 0 0 18 ? * MON-FRI *→ Dừng lúc 18h00 các ngày trong tuần)
    Tham khảo thêm cách xây dựng Cron Expression
    – Targets: Chọn Add target*
    Chọn Lambda function và chọn function tạo ở trên. (VD: dc-common-lambda-auto-stop)
  3. Sau đó đặt Tên và tạo Rule.

Tạo Function khởi chạy các máy ảo

  1. Trong Bảng điều khiển Lambda, chọn vào mục Functions.
  2. Tạo một Function mới với các thông số:
    – Function name : dc-common-lambda-auto-start
    – Runtime : Python 3.8
    – Permission : Chọn Use an existing role với tên role đã tạo ở trên dc-common-lambda-role
  3. Thêm vô biến môi trường cho Function:
    – Key : Enviroment_Auto
    – Value : true
  4. Ở mục Function code sẽ sử dụng đoạn mã nguồn sau: (Hãy thay đổi webhook_urlđể nhận được thông báo khi Lambda được trigger)
import boto3
import os
import json
import urllib3ec2_resource = boto3.resource('ec2')
http = urllib3.PoolManager()
webhook_url = "https://hooks.slack.com/services/T01H4J6EGGN/B01J15NP6E4/XXXXXXXXXXXXXXX"def lambda_handler(event, context):
    environment_auto= os.environ.get('environment_auto')
    if not environment_auto:
        print('Target is empty')
    else:
        instances = ec2_resource.instances.filter(
            Filters=[{'Name': 'tag:Enviroment_Auto', 'Values': [environment_auto]}]
        )     
        if not list(instances):
            response = {
                "statusCode":500,
                "body": "Target Instance is None"
            }
        else:
            action_start = instances.start()
            sent_slack(action_start)
            response = {
                "statusCode":200,
                "body": "EC2 Starting"
            }
        return responsedef sent_slack(action_start):
    list_instance_id = []
    if (len(action_start)>0) and ("StartingInstances" in action_start[0]) and (len(action_start[0]["StartingInstances"])>0):
        for i in action_start[0]["StartingInstances"] :
            list_instance_id.append(i["InstanceId"])
            msg = "Starting Instances ID:\n %s" %(list_instance_id)
            data = {"text":msg}
            r = http.request("POST",
                webhook_url,
                body = json.dumps(data),
                headers = {"Content-Type":"application/json"})
    else:
        print ('Not found Instances Start')

Tạo CloudWatch Rule thực thi Lambda Function chạy máy chủ ảo.

  1. Trong Bảng điều khiển CloudWatch, chọn vào mục Events Rules.
  2. Tạo một Rule mới với các thông số:
    – Event Source :
    Schedule Cron expression > Chọn khoảng thời gian
    (VD: 0 0 6 ? * MON-FRI *→ Chạy lúc 6h00 các ngày trong tuần)
    Tham khảo thêm cách xây dựng Cron Expression
    – Targets: Chọn Add target*
    Chọn Lambda function và chọn function tạo ở trên. (VD: dc-common-lambda-auto-start)
  3. Sau đó đặt Tên và tạo Rule.
Thiết lập thời gian chạy tiến trình chạy máy chủ ảo

IV. KIỂM TRA THÀNH QUẢ

Khi để tự động, các máy chủ sẽ được tự động khởi chạy vào lúc 6 giờ và tắt vào lúc 18 giờ. Khi đó các resource như máy chủ ảo, RDS với tag được xác định sẽ được tiết kiệm chi phí.

Để thử nghiệm quá trình này, chúng ta có thể kiểm tra hoạt động thông qua việc chạy các Lambda Function một các thủ công bằng việc chạy Test trong Lambda Function.

Thử nghiệm tắt máy chủ bằng Lambda Function
Thông tin cảnh báo được gửi về Slack sử dụng Webhook

Như vậy, bạn đã nắm được cách mà chúng ta có thể tiết kiệm được chi phí đối với các tài nguyên có thể bật tắt và chỉ cần hoạt động trong một thời gian nhất định.

Đây là một phương án đơn giản nhất mà chúng ta có thể nghĩ đến trong quá trình tối ưu hóa chi phí cho các tài nguyên chạy trên môi trường AWS.

Hiện tại, AWS cũng đã giới thiệu đến người dùng Amazon EventBridge. Và chúng ta hoàn toàn có thể sử dụng dịch vụ này phục vụ cho việc thực thi các hành động khi có các sự kiện như việc tắt/chạy các tài nguyên này và hơn thế nữa. Chúng ta hẹn gặp nhau ở một bài viết khác để tìm hiểu về dịch vụ này.

Tác giả: Lê Duy Minh