Hướng dẫn sử dụng AWS Lambda với NodeJS – phần 2


1061

Ứng dụng Lambda đầu tiên của bạn với NodeJS

Bây giờ, chúng ta sẽ tạo một ứng dụng hello world với NodeJS đơn giản. Sau đó, tạo một ứng dụng nâng cao hơn để tải hình ảnh xuống từ một URL, thay đổi kích thước và sau đó tải hình ảnh đó lên AWS S3, một dịch vụ lưu trữ đối tượng có khả năng mở rộng cao.

Trước tiên, chúng ta sẽ bắt đầu bằng cách sử dụng công cụ Serverless CLI để khởi động dự án của mình:

$ serverless create --template hello-world

Nếu bạn chạy lệnh trên thành công, bạn đã có hai tệp được tạo cho mình.

.
├── handler.js
└── serverless.yml

Chúng ta đã cung cấp argument –template để cho Serverless CLI biết lựa chọn template. Có hàng tá template mà công cụ Serverless CLI hỗ trợ. Bạn có thể tìm thấy chúng trong repository.

Handler.js

Bây giờ, handler.js là function Lambda. Đây là nơi logic của bạn

'use strict';
module.exports.helloWorld = (event, context, callback) => {
...

Function này chấp nhận ba argument: event, context, và callback.

Event

Argument event chứa dữ liệu event. Có nhiều loại event khác nhau và mỗi loại thường chứa các attributes khác nhau. Thoạt đầu, bạn có thể hơi khó hiểu về cách hoạt động của các function Lambda.

Điều đầu tiên cần lưu ý là một function Lambda phải được trigger bởi một service và không thể tự chạy. Bạn sẽ tìm thấy danh sách các service có khả năng gọi các function Lambda tại đây.

Context

Sử dụng argument context để truyền tham số runtime cho function Lambda.

Callback

Sử dụng argument callback để return response cho người gọi.

Serverless.yml

Tệp serverless.yml chứa định nghĩa API của bạn và các tài nguyên khác. Đây là những service mà ứng dụng của bạn phụ thuộc vào để hoạt động như mong đợi. Ở phần sau của bài đăng này, chúng ta sẽ cần một bộ chứa S3 để lưu trữ images

Hãy thực hiện một số sửa đổi đối với serverless.yml. Chúng ta sẽ thay đổi thuộc tính runtime thành NodeJS 8.10. Sau đó, thêm một thuộc tính mới, region, vào object nhà cung cấp, object này sẽ triển khai ứng dụng cho region mà đã chỉ định. Điều này là hoàn toàn tùy chọn và AWS sẽ mặc định là us-East-1 nếu không được chỉ định. Điều quan trọng là chọn các khu vực gần với người dùng của bạn trong quá trình sản xuất vì độ trễ.

service: serverless-hello-world
# The `provider` block defines where your service will be deployed
provider:
  name: aws
  runtime: nodejs8.10
  region: eu-west-1
.... 

Cách deploy ứng dụng NodeJS

Chúng ta deploy ứng dụng với argumentdeploy . Từ console, thực hiện lệnh dưới đây:

serverless deploy

Sau khi hoàn thành, bạn sẽ thấy output trong console của mình. Điều quan trọng cần lưu ý ở đây là endpoint.

...
api keys:
  None
endpoints:
  GET - https://ss7n639ye3.execute-api.eu-west-1.amazonaws.com/dev/hello-world
functions:
  helloWorld: serverless-hello-world-dev-helloWorld
...

Nếu bạn truy cập endpoint từ trình duyệt của mình, bạn sẽ thấy request được in lại cho bạn. Xin chúc mừng! Bạn vừa tạo ứng dụng Lambda đầu tiên của mình.

Đi xa hơn nữa

Ứng dụng hello world nổi tiếng mà chúng ta đã xây dựng trong phần trước khá đơn giản.

Chúng ta sẽ xây dựng một ứng dụng Lambda lấy hình ảnh từ một URL, thay đổi kích thước chúng một cách nhanh chóng và tải chúng lên bucket S3, như tôi đã nói trước đó. Bạn có thể sửa đổi ứng dụng hello world trước đó hoặc bắt đầu một dự án mới từ đầu.

Chúng ta sẽ thực hiện các thay đổi đối với serverless.yml như sau:

# filename: serverless.yml
service: ImageUploaderService
# The `provider` block defines where your service will be deployed
custom:
  bucket: getting-started-lambda-example
provider:
  name: aws
  runtime: nodejs8.10
  region: eu-west-1
  stackName: imageUploader
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "s3:PutObject"
      Resource:
        - "arn:aws:s3:::${self:custom.bucket}/*"
# The `functions` block defines what code to deploy
functions:
  UploadImage:
    handler: uploadImage.handler
    # The `events` block defines how to trigger the uploadImage.handler code
    events:
      - http:
        path: upload
        method: post
        cors: true
    environment:
      Bucket: ${self:custom.bucket}
resources:
  Resources:
    StorageBucket:
      Type: "AWS::S3::Bucket"
      Properties:
        BucketName: ${self:custom.bucket}

Những gì ở đây là custom object trong tệp YAML nơi xác định tên bucket. Bạn nên chọn tên bucket khác; bạn không thể sử dụng tên bucket mà đã sử dụng. Tài liệu AWS cho biết, “tên bucket Amazon S3 là duy nhất trên toàn cầu và namespace được chia sẻ bởi tất cả các tài khoản AWS. Điều này có nghĩa là sau khi một bucket được tạo, tên của bucket không thể sử dụng bởi một tài khoản AWS khác trong bất kỳ Khu vực AWS nào cho đến khi bucket bị xóa. ”

Stack là tập hợp các tài nguyên AWS có thể quản lý. Chúng ta cũng chỉ định IamRoleStatement global . Function Lambda cần quyền để truy cập các tài nguyên AWS khác. Trong trường hợp của chúng tacần quyền để ghi vào bucket S3. Quyền này được cung cấp trong các statements về role IAM.

Bên dưới function Lambda UploadImage,đã thêm một object mới có tên là environment. Với điều này, có thể đặt các biến environment mà nhận được thông qua object process.env trong quá trình thực thi. Hãy ghi lại tên của người xử lý.

Cuối cùng, kết thúc bằng cách xác định resource bucketS3 nơi các image sẽ được lưu trữ.

Thêm package npm

Bạn không cần phải phát minh lại bánh xe. Bạn có thể sử dụng các gói npm yêu thích của mình trong ứng dụng Lambda. Chúng sẽ được đóng gói cùng với các functions của bạn khi deploy NodeJS.

Chúng ta sẽ sử dụng package npm có tên uuid để tạo tên riêng cho images và chúng ta sẽ sử dụng jimp để xử lý images đã tải lên.

Đầu tiên, chúng ta cần một tệp package.json.

npm init

Bạn sẽ được hỏi một số câu hỏi. Chỉ cần tiếp tục và trả lời họ.

npm install jimp uuid

Bây giờ, hãy cập nhật chức năng xử lý. Đừng quên đổi tên function thành uploadImage.js. Bạn nên đặt tên cho function

// filename: uploadImage.js
"use strict";
const AWS = require("aws-sdk");
const uuid = require("uuid/v4");
const Jimp = require("jimp");
const s3 = new AWS.S3();
const width = 200;
const height = 200;
const imageType = "image/png";
const bucket = process.env.Bucket;
module.exports.handler = (event, context, callback) => {
    let requestBody = JSON.parse(event.body);
    let photoUrl = requestBody.photoUrl;
    let objectId = uuid();
    let objectKey = `resize-${width}x${height}-${objectId}.png`;
    fetchImage(photoUrl)
        .then(image => image.resize(width, height)
            .getBufferAsync(imageType))
        .then(resizedBuffer => uploadToS3(resizedBuffer, objectKey))
        .then(function(response) {
            console.log(`Image ${objectKey} was uploaed and resized`);
            callback(null, {
                statusCode: 200,
                body: JSON.stringify(response)
            });
        })
        .catch(error => console.log(error));
};
/**
* @param {*} data
* @param {string} key
*/
function uploadToS3(data, key) {
    return s3
        .putObject({
            Bucket: bucket,
            Key: key,
            Body: data,
            ContentType: imageType
        })
        .promise();
}
/**
* @param {url}
* @returns {Promise}
*/
function fetchImage(url) {
    return Jimp.read(url);
)

Nếu bạn nhìn vào uploadImage.js, bạn có thể thấy chúng ta có phương thức fetchImage chịu trách nhiệm lấy image từ một URL.

Bạn có thể đọc thêm về hoạt động bên trong của package jimp trong tệp readme của chúng.

Sau khi thay đổi kích thước, chúng ta tải lên bucket S3 của mình bằng phương pháp putObject trong AWS SDK.

Cách đăng nhập các hàm AWS Lambda

Logging cung cấp khả năng hiển thị về cách các ứng dụng chạy trong quá trình sản xuất. Nó có thể giúp bạn tiết kiệm rất nhiều thời gian khi khắc phục sự cố.

Mặc dù có nhiều dịch vụ tổng hợp ghi log, như RetraceAWS Cloudwatch và các function Lambda hoạt động tốt cùng nhau.

Ngoài ra, AWS Lambda thay mặt bạn giám sát các function và báo cáo các chỉ số thông qua Amazon CloudWatch. Các chỉ số này bao gồm tổng số requests, thời lượng và tỷ lệ lỗi. Ngoài việc theo dõi và ghi log được cung cấp, bạn cũng có thể ghi lại một sự kiện từ code của mình với console.log:

console.log('An error occurred')

Trong function của chúng ta(nghĩa là uploadImage.js), chúng ta đăng nhập vào AWS CloudWatch khi image được xử lý thành công và khi xảy ra lỗi.

Deploy và test

Cho dù bạn đang cập nhật ứng dụng hiện có hay deploy ứng dụng mới, bạn sẽ deploy với lệnh sau:

serverless deploy

Ouput của bạn sẽ tương tự như bên dưới (và vui lòng lưu ý endpoint):

.....
  None
endpoints:
  POST - https://0sdampzeaj.execute-api.eu-west-1.amazonaws.com/dev/upload
functions:
  UploadImage: ImageUploaderService-dev-UploadImage
layers:

Nếu bạn thực hiện curl request tới endpoint này với nội dung yêu cầu phù hợp, image sẽ được tải xuống từ URL, được thay đổi kích thước và tải lên bộ chứa S3. Hãy nhớ thay đổi endpoint trong console của bạn.

curl -H "Content-type: application/json" -d '{"photoUrl":"https://www.petmd.com/sites/default/files/what-does-it-mean-when-cat-wags-tail.jpg"}' 'https://0sdampzeaj.execute-api.eu-west-1.amazonaws.com/dev/upload'

Giờ đây, bạn có thể xem log trong CloudWatch và images của mình trong S3 bucket

Bạn có thể tham khảo thêm về việc xử lý lỗi tại đây :

Kết luận

Qua bài viết, bạn đã có thể setup function NodeJS với AWS Lambda một cách dễ dàng.

Tham khảo thêm về NodeJS : Cách xử lý error trong ứng dụng Express và NodeJS

Tham khảo thêm về React : Tạo authen cho app React


Like it? Share with your friends!

1061