Ngừng trả phí cho môi trường phát triển AWS: Hướng dẫn sử dụng LocalStack và Docker

DevOps tutorial - IT technology blog
DevOps tutorial - IT technology blog

Cái giá đắt của việc phát triển “chỉ trên Cloud”

Hầu hết các dự án cloud-native đều bắt đầu theo cùng một cách: bạn cung cấp thẻ tín dụng và chờ đợi. Bạn viết một hàm AWS Lambda đơn giản, đẩy code lên, và rồi cuộc chơi chờ đợi bắt đầu. Bạn đợi pipeline CI/CD, đợi Terraform khởi tạo tài nguyên, và cuối cùng là kiểm tra AWS Console để xem nó có hoạt động hay không. Nếu bạn lỡ quên một dấu phẩy trong IAM policy, bạn sẽ phải bắt đầu lại chu kỳ 15 phút đó từ đầu.

Vòng lặp phản hồi này là kẻ thù của năng suất. Tôi đã chứng kiến nhiều đội ngũ tiêu tốn 2.000 USD chỉ trong một tháng cho chi phí kiểm thử chỉ vì họ để quên các instance RDS hoặc NAT Gateway chạy xuyên cuối tuần. Một NAT Gateway tiêu tốn khoảng 32 USD mỗi tháng ngay cả khi không có lưu lượng truy cập. Những chi phí này sẽ cộng dồn lại khi bạn chỉ muốn xác minh các logic cơ bản.

Chuyển sang quy trình ưu tiên local (local-first) sẽ thay đổi cuộc chơi. Bằng cách sử dụng LocalStack và Docker, bạn có thể chạy một bản sao AWS đầy đủ chức năng ngay trên laptop của mình. Điều này cho phép bạn tách biệt logic phát triển khỏi bộ phận thanh toán của công ty.

So sánh các phương pháp: AWS thật và LocalStack

Việc lựa chọn môi trường phù hợp tùy thuộc vào nhu cầu cụ thể của bạn. Dưới đây là bảng so sánh hai phương pháp chính trong thực tế:

1. Phương pháp “Tài khoản Sandbox”

Phương pháp này bao gồm việc tạo một tài khoản AWS riêng biệt cho các lập trình viên sử dụng API thật.

  • Ưu điểm: Giống 100% với môi trường production và áp dụng IAM thực tế.
  • Nhược điểm: Độ trễ cao; tốn kém; yêu cầu kết nối internet liên tục; và việc dọn dẹp là một cơn ác mộng khi các tài nguyên bị bỏ quên vẫn tồn tại.

2. Phương pháp LocalStack

Bạn chạy một bản mô phỏng (mock) được container hóa của các dịch vụ AWS ngay trên phần cứng của mình.

  • Ưu điểm: Chi phí bằng không; phản hồi tức thì; hoạt động offline; và bạn có thể reset toàn bộ trạng thái hệ thống trong vài giây.
  • Nhược điểm: Không hỗ trợ mọi dịch vụ ngách, và các tính năng nâng cao như cluster RDS Aurora thường yêu cầu giấy phép Pro.

Tại sao mô phỏng tại local lại chiếm ưu thế

LocalStack không phải là một sự thay thế hoàn hảo 1:1 cho toàn bộ hệ sinh thái AWS. Tuy nhiên, đối với 90% các tác vụ phát triển hàng ngày, nó là quá đủ. Nó thu hẹp khoảng cách giữa việc viết code và việc nhìn thấy nó vận hành.

Các lợi thế

  • Tốc độ: Tạo một S3 bucket trên AWS có thể mất 30 giây; trong LocalStack, chỉ mất 200ms.
  • Chi phí: Bạn có thể kích hoạt 100.000 lần thực thi Lambda trong một bài kiểm thử tích hợp (integration test) và trả đúng 0 USD.
  • An toàn: Không có rủi ro vô tình xóa bucket production hoặc để lộ cơ sở dữ liệu ra internet công cộng.
  • Tích hợp CI/CD: Bạn có thể chạy các bài kiểm thử tích hợp đầy đủ trong GitHub Actions mà không cần quản lý các AWS secret phức tạp.

Các đánh đổi

  • Độ trung thực: LocalStack mô phỏng các phản hồi API. Mặc dù có độ chính xác cao, nó có thể không bắt được mọi hành vi biên (edge-case) cụ thể của engine AWS thực tế.
  • Tài nguyên hệ thống: Chạy các dịch vụ nặng như OpenSearch hoặc mô phỏng RDS đa node bên trong Docker sẽ tiêu tốn khá nhiều RAM của bạn.

Thiết lập: Docker Compose

Tôi khuyên bạn nên sử dụng Docker Compose cho việc thiết lập. Nó giữ cấu hình hạ tầng trong repo git để mọi lập trình viên đều có môi trường giống hệt nhau. Tạo một file docker-compose.yml trong thư mục gốc của dự án:

version: "3.8"

services:
  localstack:
    container_name: localstack_main
    image: localstack/localstack:latest
    ports:
      - "127.0.0.1:4566:4566"
      - "127.0.0.1:4510-4559:4510-4559"
    environment:
      - DEBUG=1
      - DOCKER_HOST=unix:///var/run/docker.sock
    volumes:
      - "./volume:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

File này sẽ map LocalStack Gateway vào cổng 4566. Cổng duy nhất này xử lý các yêu cầu cho mọi dịch vụ, bao gồm S3, Lambda và SQS.

Bắt đầu thực hiện

Khởi động container bằng lệnh docker-compose up -d. Mặc dù AWS CLI tiêu chuẩn vẫn hoạt động, bạn nên cài đặt awslocal. Đây là một wrapper nhỏ tự động điều hướng các lệnh của bạn đến container local, giúp bạn không phải nhập URL endpoint thủ công mỗi lần.

pip install awscli-local

Ví dụ 1: Quản lý S3 Bucket

Việc tạo một bucket và tải file lên không yêu cầu thông tin xác thực thật hay kết nối internet.

# Tạo một bucket
awslocal s3 mb s3://my-test-bucket

# Liệt kê các bucket
awslocal s3 ls

# Tải một file lên
echo "Xin chào từ LocalStack" > test.txt
awslocal s3 cp test.txt s3://my-test-bucket/

Ví dụ 2: Triển khai một hàm Lambda

LocalStack giúp việc kiểm thử Lambda trở nên cực kỳ dễ dàng. Tạo một file tên là handler.py:

def hello(event, context):
    return {
        'statusCode': 200,
        'body': 'Xin chào từ Lambda local!'
    }

Nén nó lại và triển khai bằng CLI:

zip function.zip handler.py

awslocal lambda create-function \
    --function-name my-local-lambda \
    --runtime python3.9 \
    --handler handler.hello \
    --role arn:aws:iam::000000000000:role/lambda-role \
    --zip-file fileb://function.zip

# Chạy hàm
awslocal lambda invoke --function-name my-local-lambda response.json
cat response.json

Kết nối mã nguồn ứng dụng

Khi sử dụng boto3 trong Python, bạn chỉ cần trỏ endpoint_url tới container local của mình. Tôi thường sử dụng pattern này để tự động chuyển đổi giữa các môi trường:

import boto3
import os

# Chuyển hướng sang LocalStack nếu môi trường được thiết lập là local
if os.getenv('ENV') == 'local':
    s3 = boto3.client('s3', endpoint_url='http://localhost:4566')
else:
    s3 = boto3.client('s3')

# Phần còn lại của mã nguồn không thay đổi
print(s3.list_buckets())

Lời kết

Áp dụng quy trình ưu tiên local sẽ thay đổi cách bạn xây dựng phần mềm. Bạn không còn phải lo lắng về hóa đơn hàng tháng và có thể tập trung hoàn toàn vào kiến trúc. Docker và LocalStack cung cấp một môi trường sandbox nhanh chóng, có thể tái lập và miễn phí.

Thiết lập này sẽ không thay thế môi trường staging cuối cùng của bạn trên cloud thật. Tuy nhiên, nó đảm bảo rằng mã nguồn của bạn không còn các lỗi cấu hình hiển nhiên trước khi rời khỏi máy cá nhân. Đây là một tiêu chuẩn chuyên nghiệp giúp tiết kiệm cả thời gian của bạn và tiền bạc của công ty.

Share: