0
0
Lập trình
Admin Team
Admin Teamtechmely

Tự động hóa ENI Failover với AWS Lambda và EventBridge

Đăng vào 7 tháng trước

• 10 phút đọc

Chủ đề:

#aws

Tự động hóa ENI Failover với AWS Lambda và EventBridge

Giới thiệu

Trong môi trường đám mây, việc duy trì tính sẵn sàng và khả năng phục hồi của ứng dụng là rất quan trọng. Một trong những cách để đạt được điều này trên AWS là tự động hóa quá trình chuyển giao Elastic Network Interfaces (ENIs) từ một phiên bản EC2 chính sang một phiên bản EC2 phụ khi phiên bản chính ngừng hoạt động hoặc bị xóa. Hướng dẫn này sẽ giúp bạn thiết lập quy trình tự động hóa này bằng sự kết hợp giữa AWS Lambda và Amazon EventBridge.

Tổng quan kiến trúc

Quá trình tự động hóa này bao gồm các bước sau:

  1. EventBridge nhận thông báo thay đổi trạng thái phiên bản EC2 cho phiên bản chính (ví dụ: stopped, terminated).
  2. EventBridge kích hoạt hàm Lambda.
  3. Lambda gọi API EC2 để ngắt kết nối ENIs đã cấu hình từ phiên bản chính và gán chúng cho phiên bản phụ.

Điều kiện tiên quyết

Trước khi bắt đầu, bạn cần chuẩn bị những điều sau:

  1. ID của phiên bản EC2 chính và phụ.
  2. ID của ENI mà bạn muốn di chuyển (các ENI phải nằm trong cùng một Availability Zone với phiên bản mà bạn muốn gán).
  3. Quyền IAM để tạo vai trò, Lambda, và quy tắc EventBridge.

Bước 1 — Tạo vai trò IAM cho Lambda

  1. Truy cập vào IAM ConsoleRolesCreate role.
  2. Chọn loại thực thể đáng tin cậy: AWS service → Trường hợp sử dụng: LambdaNext.
  3. Đính kèm chính sách quản lý AWSLambdaBasicExecutionRole (cho logging).
  4. Click Next.
  5. Đặt tên cho vai trò là lambda-eni-mover-role và tạo nó.
  6. Sau khi tạo, mở vai trò và đi đến tab PermissionsAdd permissionsCreate inline policy.
  7. Chọn trình soạn thảo JSON và dán:
    json Copy
    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "ec2:DescribeInstances",
            "ec2:DescribeNetworkInterfaces",
            "ec2:DetachNetworkInterface",
            "ec2:AttachNetworkInterface"
          ],
          "Resource": "*"
        }
      ]
    }
    Lưu chính sách với tên LambdaEC2ENIPermissions.

Bước 2 — Tạo hàm Lambda

  1. Truy cập vào Lambda ConsoleCreate function.
  2. Chọn Author from scratch.
  3. Tên hàm: eni-mover.
  4. Runtime: Python 3.10.
  5. Vai trò thực thi: Chọn Use the existing role và chọn lambda-eni-mover-role.
  6. Nhấn Create function.
  7. Sau khi tạo, cuộn xuống phần Code Source editor. Thay thế mã mặc định bằng mã Python được cung cấp (xem bên dưới).
  8. Trong tab ConfigurationGeneral configuration, thiết lập: Timeout: 3 phút (180 giây) Memory: 512 MB (có thể điều chỉnh).
  9. Trong tab ConfigurationEnvironment variables, thêm:
    Copy
    PRIMARY_INSTANCE = your primary instance ID
    SECONDARY_INSTANCE = your secondary instance ID
    SECONDARY_ENIS = comma-separated ENI IDs (ví dụ: eni-abc123,eni-def456)
  10. Dán đoạn mã Python sau vào trong phần mã:
    python Copy
    import boto3
    import time
    from concurrent.futures import ThreadPoolExecutor, as_completed
    
    ec2 = boto3.client('ec2')
    PRIMARY_INSTANCE = "INSTANCE_ID_1"
    SECONDARY_INSTANCE = "INSTANCE_ID_2"
    SECONDARY_ENIS = [
        "ENI_ID_1",
        "ENI_ID_2"
    ]
    
    def wait_for_available(eni_id, timeout=180):
        start = time.time()
        while time.time() - start < timeout:
            eni = ec2.describe_network_interfaces(NetworkInterfaceIds=[eni_id])['NetworkInterfaces'][0]
            if eni['Status'] == 'available':
                print(f"ENI {eni_id} hiện đã có sẵn.")
                return True
            time.sleep(3)
        raise TimeoutError(f"ENI {eni_id} không trở thành có sẵn trong {timeout} giây")
    
    def wait_for_in_use(eni_id, timeout=180):
        start = time.time()
        while time.time() - start < timeout:
            eni = ec2.describe_network_interfaces(NetworkInterfaceIds=[eni_id])['NetworkInterfaces'][0]
            if eni['Status'] == 'in-use':
                print(f"ENI {eni_id} hiện đã được gán.")
                return True
            time.sleep(3)
        raise TimeoutError(f"ENI {eni_id} không được gán trong {timeout} giây")
    
    def move_eni_to_secondary(eni_id, device_index):
        eni = ec2.describe_network_interfaces(NetworkInterfaceIds=[eni_id])['NetworkInterfaces'][0]
        attachment = eni.get('Attachment')
        if attachment:
            print(f"Ngắt kết nối ENI {eni_id} từ {attachment['InstanceId']}...")
            ec2.detach_network_interface(AttachmentId=attachment['AttachmentId'], Force=True)
            wait_for_available(eni_id)
        else:
            print(f"ENI {eni_id} đã ngắt kết nối.")
        print(f"Gán ENI {eni_id} cho phiên bản phụ tại DeviceIndex {device_index}...")
        ec2.attach_network_interface(NetworkInterfaceId=eni_id, InstanceId=SECONDARY_INSTANCE, DeviceIndex=device_index)
        wait_for_in_use(eni_id)
        return eni_id
    
    def lambda_handler(event, context):
        print("Sự kiện nhận được:", event)
        detail = event.get("detail", {})
        if detail.get("instance-id") != PRIMARY_INSTANCE:
            print("Sự kiện không dành cho phiên bản chính. Bỏ qua.")
            return {"status": "bỏ qua - không phải chính"}
        if detail.get("state") not in ["stopping", "stopped", "shutting-down", "terminated"]:
            print("Trạng thái phiên bản không phù hợp. Bỏ qua.")
            return {"status": "bỏ qua - trạng thái không phù hợp"}
    
        # Thu thập chỉ số thiết bị hiện tại trên phiên bản phụ
        existing_indexes = []
        response = ec2.describe_instances(InstanceIds=[SECONDARY_INSTANCE])
        for iface in response['Reservations'][0]['Instances'][0]['NetworkInterfaces']:
            existing_indexes.append(iface['Attachment']['DeviceIndex'])
    
        # Chuẩn bị chỉ số thiết bị cho từng ENI
        device_indices = []
        next_index = 1
        for _ in SECONDARY_ENIS:
            while next_index in existing_indexes:
                next_index += 1
            device_indices.append(next_index)
            existing_indexes.append(next_index)
            next_index += 1
    
        # Di chuyển ENIs song song
        results = []
        with ThreadPoolExecutor(max_workers=len(SECONDARY_ENIS)) as executor:
            future_to_eni = {executor.submit(move_eni_to_secondary, eni, idx): eni for eni, idx in zip(SECONDARY_ENIS, device_indices)}
            for future in as_completed(future_to_eni):
                eni_id = future_to_eni[future]
                try:
                    result = future.result()
                    print(f"{result} đã được di chuyển thành công.")
                    results.append(result)
                except Exception as e:
                    print(f"Lỗi di chuyển {eni_id}: {e}")
  11. Nhấn Deploy.

Bước 3 — Tạo quy tắc EventBridge

  1. Truy cập vào Amazon EventBridge ConsoleRulesCreate rule.
  2. Tên: eni-mover-primary-stop.
  3. Loại quy tắc: Rule with event pattern.
  4. Mẫu sự kiện → Custom pattern (trình soạn thảo JSON) → dán:
    json Copy
    {
      "source": [
        "aws.ec2"
      ],
      "detail-type": [
        "AWS API Call via CloudTrail"
      ],
      "detail": {
        "eventSource": [
          "ec2.amazonaws.com"
        ],
        "eventName": [
          "StopInstances"
        ],
        "requestParameters": {
          "instanceId": [
            PRIMARY_INSTANCE
          ]
        }
      }
    }
  5. Tiếp theo, thêm một Target → chọn Lambda function → chọn eni-mover.
  6. Tạo quy tắc. Giờ đây, EventBridge sẽ tự động kích hoạt Lambda khi phiên bản chính ngừng hoạt động.

Thực hành tốt nhất

  • Kiểm tra định kỳ: Đảm bảo kiểm tra định kỳ hàm Lambda và quy tắc EventBridge để đảm bảo chúng hoạt động như mong đợi.
  • Giám sát: Sử dụng CloudWatch để giám sát log và theo dõi hiệu suất của hàm Lambda.

Những cạm bẫy phổ biến

  • Quyền IAM không đầy đủ: Đảm bảo rằng vai trò IAM có đủ quyền để thực hiện các hành động cần thiết.
  • ENIs không trong cùng một Availability Zone: Kiểm tra rằng các ENIs bạn muốn di chuyển đều nằm trong cùng một Availability Zone với phiên bản phụ.

Mẹo hiệu suất

  • Đặt thời gian chờ hợp lý cho các hàm Lambda để tránh timeout trong trường hợp có nhiều ENIs cần di chuyển.
  • Sử dụng các chỉ số hiệu suất để tối ưu hóa số lượng ENIs có thể di chuyển trong một lần.

Khắc phục sự cố

  • Nếu hàm Lambda không hoạt động, kiểm tra log trong CloudWatch để xác định nguyên nhân.
  • Đảm bảo rằng định dạng của mẫu sự kiện trong EventBridge là chính xác.

Kết luận

Việc tự động hóa quá trình chuyển giao ENI với AWS Lambda và EventBridge giúp tăng cường tính sẵn sàng của ứng dụng trên AWS. Bằng cách làm theo hướng dẫn này, bạn có thể dễ dàng thiết lập một quy trình tự động hóa hiệu quả. Hãy thử ngay hôm nay để bảo vệ ứng dụng của bạn khỏi những sự cố không mong muốn!

Câu hỏi thường gặp (FAQ)

1. Làm thế nào để kiểm tra xem hàm Lambda có hoạt động không?

Bạn có thể kiểm tra log trong AWS CloudWatch để xem các thông tin chi tiết về việc thực thi hàm Lambda.

2. Tôi có thể sử dụng cách này cho các dịch vụ khác ngoài EC2 không?

Có, nhưng bạn sẽ cần phải điều chỉnh mã và quyền IAM cho phù hợp với dịch vụ đó.

3. Có cách nào để giảm thiểu chi phí khi sử dụng Lambda không?

Bạn có thể tối ưu hóa mã của mình để giảm thời gian thực thi và tránh việc kích hoạt quá nhiều lần không cần thiết.

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào