0
0
Lập trình
TT

Phát triển AWS Lambda địa phương hiệu quả

Đăng vào 3 tuần trước

• 8 phút đọc

Chủ đề:

#aws#lambda#howto

Vấn đề thường gặp

Trong sự nghiệp của mình, tôi thường thấy AWS Lambda được triển khai trực tiếp mà không có mã nguồn được cam kết trên GitHub. Thậm chí tệ hơn, nhiều dự án thiếu một kiến trúc rõ ràng hoặc công cụ cho phép kiểm tra Lambdas cục bộ trước khi triển khai. Ở đây, tôi sẽ hướng dẫn cách giới thiệu một số công cụ cơ bản để khắc phục điều này.

Thiết lập AWS cục bộ

Để chạy và gỡ lỗi Lambdas cục bộ, chúng ta cần một môi trường thực thi mô phỏng các dịch vụ AWS. Để thực hiện điều này, tôi khuyên bạn nên sử dụng LocalStack với Docker:

yaml Copy
services:
  localstack:
    image: localstack/localstack
    ports:
      - "4566:4566"
      - "4510-4559:4510-4559"
    environment:
      - SERVICES=lambda,logs
      - DEBUG=1
      - LAMBDA_EXECUTOR=docker
      - DATA_DIR=/tmp/localstack/data
      - AWS_DEFAULT_REGION=eu-north-1
      - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY-}
      - USE_SSL=false
    volumes:
      - "./localstack/volume:/var/lib/localstack"
      - "/var/run/docker.sock:/var/run/docker.sock"

Có hai điểm bạn cần chú ý:

  1. Trong biến môi trường SERVICES, chúng ta cần định nghĩa hai dịch vụ:
    • lambda: chỉ ra rằng chúng ta cần sử dụng localstack cho việc thực thi lambda.
    • logs: nơi bất kỳ bản ghi nào từ lambda sẽ được xuất ra stdout. Điều này tương đương với dịch vụ CloudWatch.
  2. Chúng ta đã vô hiệu hóa ssl với USE_SSL.
  3. Container được khởi động cần giao tiếp với docker để chạy lambda. Để thực hiện điều này, chúng ta cần định nghĩa:
    • LAMBDA_EXECUTOR là docker.
    • Ánh xạ tệp socket của docker bên trong container thông qua một bind-mount. Điều này đạt được bằng cách thêm /var/run/docker.sock:/var/run/docker.sock vào phần volumes.

LocalStack có sẵn thông qua http://localhost:4566 như đã định nghĩa ở trên:

yaml Copy
  ports:
      - "4566:4566"

Tải mã Lambda

Mã Lambda thường được lưu trữ dưới dạng tệp .zip, chứa mã ứng dụng cùng với các phụ thuộc của nó:

Phát hiện điểm vào của Lambda

Lambdas là các script Node.js hoặc Python, thường là một hàm bên trong một tệp cụ thể.

Ví dụ, trong một Lambda Python, điểm vào thường được xác định là file_name.handler_function:

Trong trường hợp này, AWS sẽ bắt đầu thực thi từ phương thức lambda_handler bên trong lambda_function.py:

Việc xác định điểm vào là rất quan trọng vì nó giúp xác định các phụ thuộc và thiết lập.

Cài đặt phiên bản Python hoặc Node.js yêu cầu

AWS Lambdas chạy với các runtime Python (hoặc Node.js) cụ thể (ví dụ: Python 3.9, 3.10).

Bạn có thể kiểm tra runtime đang được sử dụng dưới tab Code trong bảng điều khiển AWS Lambda:

Tổ chức mã và phụ thuộc

Khi bạn đã tải xuống tệp .zip của Lambda, hãy giải nén nó vào một thư mục làm việc. Tôi khuyên bạn nên tạo hai thư mục:

  1. Original Lambda → Nội dung thô của tệp .zip (ví dụ: my-lambda-orig)
  2. Clean Repo → Một dự án có cấu trúc tách biệt mã và phụ thuộc (ví dụ: my-lambda). Cấu trúc sau được khuyến nghị:
    • src → chứa mã nguồn lambda
    • tools → cho các công cụ hữu ích

Tại sao phải tách biệt chúng?
AWS thường đóng gói Lambdas với cả mã nguồn và phụ thuộc. Thay vào đó, bạn sẽ muốn quản lý các phụ thuộc bằng pip (và sau này là requirements.txt/poetry/pipenv).

Dưới đây là quy trình:

  1. Sao chép tệp Lambda chính (ví dụ: lambda_function.py) vào ./src.
  2. Kiểm tra phần đầu của tệp Lambda (ví dụ: lambda_function.py). Tại đó, bạn có thể phân biệt các tệp cần thiết và các thư viện bên thứ ba. Bất kỳ thư viện không phải bên thứ ba nào hãy sao chép chúng vào thư mục src của clean repo.
  3. Sử dụng tên, bạn có thể phát hiện các thư viện bên thứ ba và các thư viện cần thiết. Tốt nhất là giữ một danh sách các thư viện bên thứ ba.
  4. Sao chép chỉ mã ứng dụng (các tệp .py của bạn) vào clean repo.

Một thư viện phổ biến là thư viện boto được sử dụng để giao tiếp với AWS.

Sau khi tách biệt mã, hãy khởi tạo git và thực hiện commit đầu tiên:

bash Copy
git init
git commit -m "Cleaned Code"

Tạo một virtualenv

Chúng ta cần có danh sách các phụ thuộc lambda, vì vậy chúng ta cần khởi tạo một môi trường ảo:

bash Copy
python -m venv ./.venv
echo ".env" > .gitignore
git add .gitignore
git commit -m "Ignoring virtualenv"
source .venv/bin/activate

Sau đó, sử dụng pip install, chúng ta sẽ cài đặt các phụ thuộc cần thiết, ví dụ cho boto, chúng ta chạy:

bash Copy
pip install boto3

Khi các phụ thuộc đã được cài đặt, chúng ta cần giữ chúng trong một danh sách, vì vậy chúng ta cần chạy:

bash Copy
pip freeze > ./requirements.txt
git add requirements.txt
git commit -m "Added Dependencies"

Bây giờ mỗi khi chúng ta cần cài đặt chúng, chúng ta có thể làm:

bash Copy
pip install -r requirements.txt

Phát hiện biến môi trường

Lambdas cũng nhận cài đặt từ các biến môi trường bên ngoài. Đối với lambdas Python, hãy quét các chuỗi như os.environ.get(, tham số được truyền vào chứa biến môi trường yêu cầu.

Triển khai trên LocalStack

Bây giờ mà chúng ta đã sắp xếp mã, chúng ta có thể tạo một lambda trong LocalStack. Để làm điều này, chúng ta cần đóng gói lambda thành một zip mới:

bash Copy
mkdir package
echo "package" >> .gitignore
git add .gitignore
git commit -m "Ignoring support folder for packaging"

# Sao chép mã
cp -r ./src package/

# Cài đặt các phụ thuộc vào thư mục package
pip install -r requirements.txt -t package

# Nén gói
cd package
zip -r9 function.zip 
cd ../

# Thư mục gói là tạm thời
rm -rf ./package 

Các lệnh ở trên thực hiện 2 điều:

  • Tạo một thư mục trung gian nơi mã được chuẩn bị, thư mục này được đặt tên là package. Thư mục này nên được bỏ qua trong git.
  • Sao chép tất cả mã nguồn lambda vào thư mục package. Hãy nhớ rằng chúng ta cần sao chép nội dung của src và không phải thư mục src chính nó.
  • Cài đặt tất cả các phụ thuộc vào thư mục package. Điều này được thực hiện bằng cách cung cấp tên thư mục vào tham số -t.

Phương pháp mô tả ở trên cũng có thể được sử dụng để đóng gói lambda cho sản xuất. Tệp zip có thể được tải lên, do đó thay thế mã lambda.

Triển khai trên LocalStack

Để làm điều này, chúng ta có thể chạy:

bash Copy
aws --endpoint-url=http://localhost:4566 lambda create-function \ 
    --function-name "my-function" \ 
    --runtime "python3.9" \ 
    --role "arn:aws:iam::000000000000:role/lambda-role" \ 
    --handler "lambda_function.lambda_handler" \ 
    --zip-file "fileb://function.zip" \ 
    --environment Variables="{VAR1=\"Hello\"}"

Lệnh trên tạo chức năng my-function, đây là chức năng lambda mà chúng ta cần tạo. Trong lệnh trên, chúng ta cần chú ý đến một số tham số:

  • --endpoint-url: Trong trường hợp của chúng ta, chúng ta cần cung cấp nó với thiết lập LocalStack. Nếu không, nó sẽ cố gắng tạo lambda trên AWS thực tế. Trong trường hợp của chúng ta, điều này không mong muốn.
  • --function-name: một tên hàm đặc trưng. Mỗi lambda nên có tên riêng của nó.
  • --role: Giữ giá trị arn:aws:iam::000000000000:role/lambda-role là tốt cho mọi lần bạn tạo một lambda mới. LocalStack không kiểm tra các vai trò nhưng chúng ta cần đặt điều này để tránh bất kỳ hành vi không mong muốn nào.
  • --handler: Đặt cái mà lambda thực sự sử dụng trên AWS. Tại đây, chúng ta định nghĩa cái sẽ được sử dụng cho việc thực thi lambda.
  • --zip-file: Tệp mà chúng ta đã tạo chứa mã + phụ thuộc.
  • --environment: Nếu không có biến môi trường nào được sử dụng, hãy bỏ qua nó. Giá trị là một chuỗi được đóng gói trong {} có định dạng này (đừng nhầm lẫn với JSON):
bash Copy
    {VARIABLE_NAME=VALUE,VARIABLE_NAME2=VALUE2}

Phát triển và tái triển khai

Trong quá trình phát triển, nếu cần thay đổi, bạn cần phải đóng gói lại lambda. Việc tái tạo là không cần thiết trừ khi container LocalStack bị kết thúc.

Cập nhật mã được thực hiện như sau:

bash Copy
aws --endpoint-url=http://localhost:4566 lambda update-function-code --function-name "my-function" --zip-file "fileb://function.zip"

Trong khi nếu cần thay đổi các biến môi trường, bạn có thể làm như sau:

bash Copy
aws --endpoint-url=http://localhost:4566 lambda update-function-configuration \ 
    --function-name "my-function" \ 
    --environment Variables="{VARIABLE_NAME=VALUE,VARIABLE_NAME2=VALUE2}"

Một số mẹo khác

Nếu cần một phụ thuộc bổ sung, thì tốt nhất là kích hoạt môi trường ảo được tạo ra, sau đó cài đặt nó qua pip. Sau đó, cập nhật mã trên LocalStack như đã đề cập ở trên.

Các thực tiễn tốt nhất

  • Kiểm tra cục bộ: Luôn kiểm tra mã của bạn trước khi triển khai lên AWS.
  • Sử dụng công cụ CI/CD: Tích hợp các công cụ CI/CD để tự động hóa quy trình triển khai.

Các cạm bẫy thường gặp

  • Bỏ qua biến môi trường: Đảm bảo bạn đã định nghĩa các biến môi trường cần thiết trước khi triển khai.
  • Không quản lý phụ thuộc: Luôn kiểm tra các phụ thuộc của bạn để không gặp lỗi trong quá trình triển khai.

Mẹo hiệu suất

  • Sử dụng bộ nhớ tối ưu: Đảm bảo rằng bạn đã định cấu hình bộ nhớ phù hợp cho Lambda để tối ưu hóa hiệu suất.
  • Giảm kích thước mã: Giảm kích thước mã sẽ giúp tăng tốc thời gian khởi động của Lambda.

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

  • Làm thế nào để gỡ lỗi Lambda cục bộ? Sử dụng LocalStack và các công cụ gỡ lỗi như pdb cho Python hoặc node --inspect cho Node.js.
  • Có cần thiết phải sử dụng Docker không? Có, vì Docker giúp mô phỏng môi trường AWS chính xác hơn.
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