Deploy code nextjs lên S3 và serverless API

·

5 min read

Với yêu cầu deploy api lên lambda và static pages lên S3 => phải tách BE ra chứ không viết trong nextjs được nếu dùng sam.

Deploy FE lên S3 sẽ dùng aws cli, deploy BE lên lambda dùng sam cli.

Sam là framework để triển khai serverless lên aws, có thể config, mô tả các functions, api, databases trong file yaml

FE deploy lên S3 là các file html, css, js, images, json ...

BE ở đây là 1 serverless application, serverless application là một tập hợp các Lamda function, even sources và các resources khác cùng làm việc để thực hiện các tác vụ khác nhau cho một hệ thống. Sam khi deploy sẽ bao gồm các lambda function, API gateway cho phép thực thi lambda function tại đường dẫn mình tạo ra. Lambda function sẽ đi kèm vời một IAM role cho phép tương tác với các tài nguyên AWS khác, ví dụ như database.

Tổng quan hoạt động

Deploy BE lên lambda, source code BE này sẽ được lưu trên S3 (sam tự tạo bucket và lưu vào) => sau đấy nó sẽ tạo ra 1 endpoint, FE nhận endpoint trên và build, sau đấy deploy bản build này lên S3, không truy cập trực tiếp vào S3 mà sẽ thông qua cloudfront, khi deploy thì phải config trong sam để sam tự tạo 1 distributions, thằng này sẽ trỏ vào S3 FE, nó sẽ tạo ra 1 domain name => link này chính là website ta cần access vào.

Lí do truy cập thông qua cloudfront :

- Bảo mật: vì không truy cập trực tiếp vào tài nguyên s3 mà và cần có quyền thì mới truy cập vào được, ngoài ra cloudfront hỗ trợ https.

- Nhanh hơn: vì cloudfront phân phối data đến các Egde Location gần vị trí truy cập.

- Tiết kiệm chi phí: vì việc cung cấp dữ liệu trực tiếp từ S3 tốn nhiều chi phí hơn so với việc cung cấp chúng thông qua phân phối CloudFront.

Đầu tiên phải install aws cli, config aws, install sam cli. Đầu tiên phải khởi tạo 1 application thì dùng lệnh sam init, sau đó lựa chọn loại template và loại application (app mình đang dùng application là Serverless API). Trước khi deploy thì cần [config file template.yaml](https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md), dựa vào file này thì khi build sam sẽ chuyển đổi sang AWS Cloudformation để xây dựng dịch vụ Serverless trên AWS.
CloudFormation là một công cụ từ AWS cho phép ta khởi tạo, điều phối tài nguyên một cách dễ dàng từ 1 file template. 1 template như một bản thiết kế để xây dựng các tài nguyên AWS, mô tả tất cả các tài nguyên và tính chất của chúng, tập hợp tài nguyên liên kết với template này được gọi là stack.

  • Globals: config các thông tin common cho Function, APi ... (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html) như cors, timeout ....

  • Resources: cấu hình các resource cần thiết để build:

    • Bucket: cấu hình cho bucket sẽ được tạo (Bucket này là để chứa code FE chứ không phải code BE, code BE thì sam tự tạo riêng và k cần config gì) như tên, quyền truy cập.

    • CloudFrontOriginIdentity: ta cần truy cập vào cloudfront, cloudfront cần có quyền truy cập vào S3 để lấy data trả về, do đó tạo 1 indentity để cloudfront xác thực với S3 rằng có quyền truy cập.

    • BucketPolicy: tạo policy cho Bucket chứa code FE, tại đây sẽ set quyền truy cập là đối tượng indentity được tạo ở trên mới có quyền truy cập vào bucket này, set vào Principal.

    • CloudFrontDistribution: sam sẽ tạo 1 cloudfront distribution.

    • Outputs: in ra thông tin sau khi tạo xong.

    • Parameters: parameters khi deploy mình sẽ nhập vào.

Để deploy thì code bằng ts nên phải chuyển sang js trước (npm run build để chạy "tsc -p tsconfig.json"). Sau đó chạy sam build để build application, xong thì sam deploy --guided để deploy, chỗ này cần nhập các thông tin yêu cầu. Sau khi build xong sẽ có endpoint, end point này là API FE cần để đưa vào .env, lúc này cũng đã có domain cloudfront gen ra, chạy lệnh sau để lấy url:
aws cloudfront list-distributions --output table --query 'DistributionList.Items[*].DomainName'

Dù đã có url nhưng S3 chưa có gì => cần build và đẩy code FE lên S3

cd frontend-folder

pnpm build

pnpm export

# first of all we delete everything from the bucket
# (S3-bucket-name is the name you typed for
# the BucketName parameter when you deployed the S3 bucket)
aws S3 rm S3://${S3-bucket-name}/ --recursive

# push(sync) the `_next` folder to S3
aws S3 sync ./out/_next/ S3://${S3-bucket-name}/_next/

# find all .html files and remove their extension
for file in $(find ./out -name "*.html"); do mv "$file" "${file%%.html}"; done

# push(sync) all the html files without extension to S3 and
# set the content type to text/html by
# excluding file extensions and chunk folder
aws S3 sync --content-type "text/html" --metadata-directive REPLACE ./out/ S3://${S3-bucket-name}/ --exclude "*.jpg" --exclude "*.png" --exclude "*.jpeg" --exclude "_next/*" --exclude "*.svg"

# push(sync) all other kind of files such as images or SVGs
aws S3 sync ./out/ S3://${S3-bucket-name}/ --exclude "*.*" --include "*.jpg" --include "*.png" --include "*.jpeg" --include "*.svg"

Chú ý file 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,…). Nếu chỉ thay đổi code mà không có thay đổi gì khác config trong file này thì khi deploy chỉ cần sam deploy. Nếu deploy có lỗi thì xáo đi deploy lại: sam delete, nếu mà chưa thấy xóa hết thì lên trang chủ của aws xáo đi: bucket, cloudformation. Check log thì vào cloudwatch.

https://github.com/aws/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction