Sử dụng SAM để triển khai Serverless Application


Giới thiệu

AWS Serverless Application Model (SAM) là một open-source framework để xây dựng và triển khai các ứng dụng Serverless trên AWS

SAM cung cấp các cú pháp đơn giản để mô tả các functions, APIs, databases even source trên AWS bằng việc sử dụng YAML structure.

Trong quá trình triển khai ứng dụng, SAM sẽ chuyển đổi file YAML này sang AWS Cloudformation để xây dựng dịch vụ Serverless trên AWS

Về ích lợi của SAM, thì mình có thể miêu tả ngắn gọn như sau:

  • SAM có thể tổ chức các AWS serverless service config lại thành một, và có thể triển khai nhanh chóng
  • Bạn có thể test debug trực tiếp thông qua SAM
  • SAM build dựa trên CloudFormation, nên cú pháp hoàn toàn tương tự với CloudFormation, bạn có thể làm quen một cách nhanh chóng
  • Có thể tích hợp với nhiều tools khác nhau cho quá trình Integration hoặc Delivery

Cài đặt SAM

MAC OS

Bạn có thể cài SAM trên MAC OS thông qua Brew. Cách tải Brew trên MAC OS ở đây.

brew tap aws/tap
brew install aws-sam-cli

Linux

Download SAM zip file

wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip

Verify file tải về bằng cách sử dụng giá trị Hash. Sau đó kiểm tra với release hash

sha256sum aws-sam-cli-linux-x86_64.zip

Giải nén file zip và đưa vào thư mục sam-installation

unzip aws-sam-cli-linux-x86_64.zip -d sam-installation

Cài đặt SAM

sudo ./sam-installation/install

Sau khi cài đặt xong, nếu kiểm tra được version của SAM thì xem như bạn đã cài đặt thành công

sam --version

SAM CLI, version 1.18.0

Windows

Đối với windows 64 bit, bạn có thể cài đặt thông qua file MSI. Sau khi download về, bạn cài click vào và cài đặt theo hướng dẫn

Đối với windows 32 bit, chưa có một bản cài đặt hoàn chỉnh nào dành cho SAM, tuy nhiên bạn có thể cài đặt thông qua Python pip ở mục sau.

Cài đặt thông qua Python

Trên tất cả các môi trường, bạn hoàn toàn có thể cài đặt SAM thông qua Python Pip (yêu cầu Python version >= 3.6).

pip install aws-sam-cli

Xây dựng Lambda function thông qua SAM và Cloudformation

Lý thuyết nhiêu đó đủ rồi, mình sẽ thử build một Application thông qua SAM nhé :P.

Application này khá là đơn giản. Mình sẽ truyền một event với Lambda Function có chứa các thông tin về filename message để lưu vào file và put lên trên S3 bucket. S3 bucket cũng sẽ được tạo song song cùng với Lambda function này thông qua SAM luôn.

Code Structure

Đầu tiên mình sẽ xây dựng một structure cho SAM trước

Nhìn sơ qua thì cấu trúc của SAM cũng thương tự như các application khác. Cụ thể như sau:

  • app: chứa toàn bộ source code Lambda Function của bạn
  • events: chứa một số sample event để làm mẫu hoặc dùng khi chạy app cho việc test, debug,…
  • tests: chứa code unit tests
  • samconfig.toml: chứa các config của SAM (ví dụ như version, environment, stack name, s3 bucket – nơi chứa các package khi deploy, AWS region, AWS profile, parameters,…)
  • teamplate.yaml: chứa template format của SAM để có thể build các application

Xây dựng Lambda function

Như ở trên đã đề cập, mình sẽ xây dựng một Lambda function để đẩy file lên trên S3 Bucket (thông tin file này ở trong event). Còn S3 bucket mình sẽ để ở biến environment (tại sao mình lại để ở environment thì tí nữa sẽ bật mí nhé).

Đầu tiên mình sẽ đưa ra một cái event.json trước đã.

{
  "filename": "new_file.txt",
  "message": "Welcome to Thachanpy blog"
}

Sau đó thêm một một handle function đơn giản cho requirement như trên. Nếu put thành công file lên s3 thì sẽ về status code200

import os
import time
import boto3


def lambda_handler(event=None, context=None) -> dict:
    try:
        filename = event.get("filename", f"file_{int(time.time())}.txt")
        bucket_name = os.getenv("s3_bucket_name")
        message = event.get("message", "")
        client = boto3.client('s3')
        resp = client.put_object(
            Body=message,
            Bucket=bucket_name,
            Key=filename
        )
        status_code = resp['ResponseMetadata']['HTTPStatusCode']
    except Exception as e:
        print(e)
        status_code = 500
    return {
        "status_code": status_code
    }

Lưu ý thêm vì mình sử dụng python nên cần tạo file requirements.txt để chứa các external library nhé. Ở đây mình sẽ thêm vào thư viện boto3 (mặc định trên lambda function đã hỗ trợ boto3 luôn rồi, không nhất thiết mình phải đưa vào requirements.txt, tuy nhiên cứ đưa vào để xem quá trình build như thế nào nhé)

boto3==1.17.49

Vậy là coi như xong phần Lambda function rồi!

Xây dựng template.yaml

Bây giờ mình mới vào vấn đề chính của hôm nay, mình sẽ tạo ra một file template.yaml để cấu hình các resource cần thiết cho việc build Lambda function ở trên.

Mình sẽ mô tả sơ qua về template này.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Thachanpy's Application deployment by using SAM

Resources:
  NewS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: Private

  NewLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Handler: app.lambda_handler
      Timeout: 5
      Runtime: python3.8
      Policies:
        - Statement:
          - Sid: S3Policies
            Effect: Allow
            Action:
              - s3:PutObject
            Resource: !Sub "arn:aws:s3:::${NewS3Bucket}/*"
      Environment:
        Variables:
          s3_bucket_name: !Ref NewS3Bucket

Outputs:
  NewS3Bucket:
    Description: "New S3 Bucket Name"
    Value: !Ref NewS3Bucket
  NewLambdaFunction:
    Description: "New Lambda Function ARN"
    Value: !GetAtt NewLambdaFunction.Arn

  • Resources:
    • NewS3Bucket: mình sẽ tạo ra một S3 Bucket để Lambda function có thể đẩy file lên. S3 này mình để ở chế độ private nhé.
    • NewLambdaFunction: đây chính là Lambda function mình đã tạo ở trên, phần này dùng để cấu hình các thông số cơ bản của function như:
      • Handler: nơi chứa handle function
      • Timeout: timeout của request tới function
      • Runtime: ở đây mình dùng Python 3.8
      • Policies: chứa các policies cần thiết. Ở đây có một policy duy nhất là cấp quyền cho Lambda function có thể put một file lên s3 vừa tạo ở trên
      • Environment: như mình đã nói, mình sẽ tạo một biến environment chưa thông tin s3 bucket name vừa tạo để function có thể đẩy lên được (đọc lại code Lambda function sẽ thấy)
  • Outputs: in ra thông tin về s3 Bucket NameLambda function ARN cho việc validate, test or debug sau này.

Để đảm bảo template.yaml của bạn hợp lệ (không bị lỗi syntax, profile thiếu config hoặc không đủ quyền). Bạn nên chạy một bước validate trước khi build.

sam validate

Khi đó, SAM sẽ validate template của bạn và trả về kết quả

2021-04-13 10:36:04 Loading policies from IAM...
2021-04-13 10:36:15 Finished loading policies from IAM.
/home/thachanpy/thachanpy-app/template.yaml is a valid SAM Template

SAM build

Khi bạn đã tạo xong file template.yaml, nhiệm vụ của bạn đầu tiên là phải build SAM Application này trước, để tạo ra các packages và download các dependencies cần thiết.

sam build

Sau khi build xong, bạn sẽ thấy được thư mục .aws-sam được tạo ra. Bên trong đó chứa các artifacts tương ứng với từng Lambda Function có trong application của bạn và .

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Tạo samconfig.toml file

Sau khi build xong, bạn có thể tạo ra file samconfig.toml để cấu hình một số thông tin cần thiết của SAM.

Bạn nên khởi tạo file này thông qua việc deploy lần đầu tiên với cú pháp:

sam deploy --guided

Khi đó, SAM tạo guide để cho bạn có thể setup một số thông tin cần thiết. Bạn cứ chọn theo mặc định, sau này mình có thể sửa sau được. Sau khi hoàn thành guide thì sẽ tạo cho bạn một file samconfig.toml như sau:

version = 0.1
[default]
[default.deploy]
[default.deploy.parameters]
stack_name = "thachanpy-app"
s3_prefix = "thachanpy-app"
region = "us-east-1"
confirm_changeset = true
capabilities = "CAPABILITY_IAM"
s3_bucket = "aws-sam-cli-managed-default-samclisourcebucket-kqa7oi49tfol"

File samconfig.toml sẽ định dạng theo kiểu table, nghĩa là một table chính là một môi trường và trong đó có nhiều config tương ứng với môi trường đó.

Ở đây, bạn sẽ thấy table mình đang dùng là default, tương ứng với default environment. Nếu bạn muộn chọn một môi trường cụ thể, thì có thể thêm vào trong parameter của command. Ví dụ cho thay đổi environment sang dev

sam deploy --config-env dev

Bạn nên tạo ra nhiều môi trường như dev, qa, prod, để dễ quản lý cũng như thay đổi một số config phù hợp với môi trường đó.

Trong mỗi table, bạn sẽ có config về các command như deploy, build và các parameters tương ứng. Mình sẽ mô tả sơ qua về các parameter của command deploy

  • stack_name: Cloudformation stack name
  • s3_prefix: prefix của s3 bucket chứa các bản Lambda function build
  • region: AWS region
  • confirm_changeset: cần xác nhận lại trước khi deployment hay không
  • capabilities: type quyền của bạn để có tạo các resource trên CloudFormation stack
  • s3_bucket: nơi chứa các SAM config và template của Application, mỗi account region sẽ có một s3_buckey này

Bạn hoàn toàn có thể thay thế các parameters thông qua cli của SAM với các argument tương ứng khi run command. Ví dụ để thay đổi stack name:

sam deploy --stack-name MyNewStack

Triển khai Application lên AWS

Sau khi đã hoàn thất mọi cấu hình, bạn dễ dàng deploy Application này lên trên AWS với một câu lệnh đơn giản:

sam deploy --no-confirm-changeset

Mình thêm vào param –no-confirm-changeset để không cần phần xác nhận lại SAM config, phù hợp cho quá trình automation

Sau khi deploy xong, nếu thành công thì sẽ xuất hiện Outputs chứa các thông tin mình đã cấu hình trên template.yaml

-----------------------------------------------------------------------------------------------------------------
Outputs
-----------------------------------------------------------------------------------------------------------------
Key                 NewS3Bucket 
Description         New S3 Bucket Name 
Value               thachanpy-app-news3bucket-3oc1m4udw37q  

Key                 NewLambdaFunction 
Description         New Lambda Function ARN 
Value               arn:aws:lambda:us-east-1:1234567891011:function:thachanpy-app-NewLambdaFunction-9ZYT5220S7VP
-----------------------------------------------------------------------------------------------------------------

Test Application vừa triển khai

Sau khi đã triển khai xong, mình sẽ cùng test thử Lambda function có hoạt động không nhé.

Đầu tiên thì mình sẽ tạo một sample event (mình sẽ lấy event đã tạo ra ở trên nhé)

{
  "filename": "new_file.txt",
  "message": "Welcome to Thachanpy blog"
}

Sau đó mình sẽ invoke Lambda function với name là Lambda function ARN output ở trên

aws lambda invoke --function-name arn:aws:lambda:us-east-1:1234567891011:function:thachanpy-app-NewLambdaFunction-9ZYT5220S7VP --cli-binary-format raw-in-base64-out --payload '{ "filename": "new_file.txt", "message": "Welcome to Thachanpy blog" }' resp.json

Nếu invoke thành công, thì Lambda function sẽ trả về cho bạn Status code 200:

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

Kiểm tra lại trên S3 bucket thử xem filename có được tạo ra không nhé

aws s3 ls s3://thachanpy-app-news3bucket-3oc1m4udw37q

2021-04-13 15:15:10         25 new_file.txt

Bạn có thể thấy file new-file.txt bên trong event đã được tạo thành công rồi. Giờ mình download về và kiểm tra nội dung bên trong xem sao.

aws s3 cp s3://thachanpy-app-news3bucket-3oc1m4udw37q/new_file.txt new_file_local.txt

cat new_file_local.txt
---
Welcome to Thachanpy blog

Nội dung y chan như trong event rồi nhé ^^

Xóa Application

Rất tiếc là hiện tại SAM không hỗ trợ việc xóa Application, nên bạn có thể xóa thông qua CloudFormation Stack nhé.

Trước tiên là empty S3 đã, vì CloudFormation sẽ không tự động empty đâu, sẽ phát sinh lỗi khi delete stack

aws s3 rm s3://thachanpy-app-news3bucket-3oc1m4udw37q --recursive

Sau đó có thể delete stack được rồi

aws cloudformation delete-stack --stack-name thachanpy-app

Tổng kết

Như vậy là mình đã giới thiệu sơ qua về SAM để build một Serverless Application (ở đây là một Lambda function đơn giản).

SAM được ứng dụng nhiều trong quá trình CI cũng như CD, giúp cho việc build và deploy infra as code (cụ thể là dùng CloudFormation) trở nên dễ dàng và thuận tiện hơn.

Nếu có bất kỳ câu hỏi nào, thì mời các bạn comment lại nhé. Tụi mình sẽ cùng trao đổi 😛


5 1 vote
Article Rating
guest
0 Comments
Inline Feedbacks
View all comments