(AWS) Ứng dụng về Lambda mà các DEV nên biết: Kết hợp Lambda với S3

AWS Jul 01, 2021

Lambda là dịch vụ của AWS được dùng khá phổ biến, nó có thể được dùng kết hợp với nhiều những dịch vụ khách của AWS như API Gateway, S3...Ở bài viết này mình sẽ lấy ví dụ về một ứng dụng (usecase) của Lambda kết hợp với S3. Các bạn cùng tham khảo nhé.

Lambda kết hợp với S3 trigger

Trước đây mình cũng đã tìm hiểu sơ sơ về lý thuyết của Lambda rồi, tuy nhiên  vẫn chưa tự tay tạo một Lambda function nào cả, vì vậy vẫn chưa thực sự hiểu về Lambda.

Dạo gần đây dự án mà mình phụ trách phải làm khá nhiều với keyword "Lambda" này (Khoảng 3 dự án Project-base đã dùng Lambda), vì thế mình quyết định sẽ tìm hiểu rõ hơn cách Lambda vận hành như nào? Thực sự thì bên trong Lambda có những thứ gì? Cần config những gì để chạy được?...Để giải quyết tất cả những thắc mắc đó thì bước đầu mình chọn cách "Tự tay" thực hiện một usecase khá phổ biến của Lambda đó là: Sử dụng S3 trigger để invoke Lambda Function. Ngoài ra cũng hi vọng, bằng những hình ảnh mình chụp từ AWS console, biết đâu sẽ giúp ích cho các bạn cũng đang tìm hiểu về Lambda nhưng chưa có tài khoản AWS, có thể nhìn ảnh trong các step làm của mình để hình dung rõ hơn về Lambda và những lý thuyết mình đã đọc.

Để thực hiện usecase này mình đã dùng bài Tutorial trên https://docs.aws.amazon.com/, cùng với sự trợ giúp kỹ thuật về Nodejs từ "Dev nhà trồng được" (Vì ngôn ngữ mình dùng để code trên Lambda là Nodejs)

Trước khi đi vào mô tả từng step thực hiện của usecase này, mình sẽ nói sơ qua một chút về khái niệm "Lambda", vậy Lambda là gì?

Lambda là gì?

AWS Lambda là một dịch vụ "serverless compute", cho phép bạn chạy mã nguồn (Source code) mà không cần cấu hình server.

Nếu bạn dùng EC2 để dựng server của mình, và mục đích sau cùng là để chạy được source code thì chúng ta phải làm rất nhiều các task như:

  • Chọn OS cho máy tính
  • Chọn cấu hình cho máy tính
  • Install phần mềm server
  • Install trình biên dịch....

Tuy nhiên với Lambda, bạn sẽ không phải lo các task như mình vừa kể, chỉ đơn giản và cho code lên lambda function và nó sẽ chạy (Lambda không support toàn bộ các ngôn ngữ hiện có mà chỉ support những ngôn ngữ như: Java, Go, PowerShell, Node.js, C#, Python, Ruby...), và bạn chỉ phải trả tiền khi Lambda function được excute.

Lambda phù hợp với những task nhỏ, dùng để dựng micro service tách biệt với server bạn đang có, nhằm giảm tải cho server chính và cũng dễ quản lý hơn.

Giờ chúng mình cùng đi thực hiện các step với usecase: Sử dụng S3 trigger để invoke Lambda Function nhé.

Khái quát về usecase mà mình định làm:

Ở usecase này, mình sẽ dùng 2 bucket trên S3 (Dịch vụ lưu trữ data dạng file của AWS) và 1 lambda function để thực hiện.

User sẽ thực hiện upload ảnh lên Bucket số 1 trên S3, Lambda sẽ liên kết với S3 để nhận biết được sự kiện "Có ảnh được upload lên S3", sau đó sẽ thực hiện resize ảnh đó về dạng ảnh thumbnail, sau cùng Lambda sẽ thực hiện upload ảnh thumbnail thành phẩm đó lên Bucket số 2 trên S3.

Flow thực hiện có thể được khái quát trong ảnh sau:

Flow trong usecase về lambda mình định làm

Nào giờ chúng ta sẽ đi đến phần chính "get your hands dirty" <3

Các bước thực hiện

Bước số 1: Tạo 2 bucket trên S3, một bucket để đựng ảnh gốc, 1 bucket để đựng ảnh thumbnail thành phẩm

Đăng nhập vào AWS --> Chọn dịch vụ S3 --> Tạo bucket

Màn hình tạo bucket trên S3

Ở bước này mình đã tạo bucket chứa ảnh gốc có tên là: "hoabucket", và bucket để chứa ảnh thumbnail là "hoabucket-resized".

Kết quả sau khi tạo xong sẽ như này.

Bước số 2: Tạo IAM Policy

Đến bước này có thể nhiều bạn chưa biết IAM policy là cái gì? Dùng để làm gi? thì mình xin giải thích qua.

Với một tài khoản AWS, phía AWS cung cấp cho người dùng một dịch vụ free đó là IAM (Identity and Access Management), giúp bạn quản lý việc truy cập vào các tài nguyên (resource) thuộc tài khoản AWS bạn sở hữu.

Ví dụ: Nam là chủ sở hữu một tài khoản AWS tên là A, Nam muốn một người khác trong team mình tên là Minh cũng truy cập được vào tài khoản này.

Lúc này để Minh có thể truy cập vào tài khoản của Nam, thì Nam không nhất thiết phải cung cấp cả tài khoản và password cho Minh.

Thay vào đó, Nam có thể dùng dịch vụ IAM, tạo cho Minh một tài khoản khác (IAM user) để access vào resource trong tài khoản của Nam, lúc này khi tạo IAM user, bạn Nam có thể tùy chỉnh để cho phép Minh chỉ truy cập được vào resource nào trên aws của mình? Có những quyền gì với resource đó?

(Ví dụ Nam có thể tạo IAM user cho Minh với một quyền hạn rất tối thiểu đó là "Nhìn được list bucket trên S3" chẳng hạn....).

Ngoài ra IAM còn dùng để tạo ra các quyền hạn (Role) để gắn cho các dịch vụ khác trong AWS, để dịch vụ đó "thay mặt" user thực hiện thao tác. Và đây cũng chính là ứng dụng của IAM mà mình sẽ dùng ở bài này: Tạo role cho Lambda, để Lambda có quyền lấy các ảnh trong bucket mình chỉ định (Nếu mình không cấp quyền cho Lambda, thì lambda sẽ không có cách nào có thể tương tác và lấy dữ liệu trong S3 của mình).

Vậy là các bạn đã hiểu sơ qua về IAM là gì rồi, giờ chúng mình sẽ tiến hành tạo role cho Lambda nhé:

  • Bước 1: Tạo một IAM policy (Cái này sẽ có tác dụng định nghĩa quyền hạn của một thực thể trong AWS, xem thực thể đó có thể làm những gì? với cái gì?)
  • Bước 2: Chọn màn hình quản lý IAM --> Mục policies ở leftmenu--> Chọn tab JSON (Ở bài này mình sẽ định nghĩa policy này bằng dạng file JSON)

Sau đó sẽ định nghĩa policy theo nội dung như dưới đây:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:PutLogEvents",
                "logs:CreateLogGroup",
                "logs:CreateLogStream"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::hoabucket/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::hoabucket-resized/*"
        }
    ]
}   

Đoạn JSON này có ý nghĩa là: Mình đã cho phép thực thể được gán với policy này có quyền GetObject với các bucket có tên là "hoabucket" và có quyền PutObject lên bucket  "hoabucket-resized".

Sau đó chọn Next: Tags.

Chọn Next: Review.

Ở mục Review policy, Chọn tên của policy là  AWSLambdaS3Policy.

Chọn Create policy.

Sau khi tạo xong chúng ta sẽ có Policy sau:

Bước 3: Tạo execution role

3.1: Tại màn hình IAM console, chọn mục Role ở leftmenu.

3.2: Sau đó thực hiện Create role theo các thông tin như dưới đây:

  • Trusted entityLambda
  • Permissions policyAWSLambdaS3Policy
  • Role namelambda-s3-role
Màn hình tạo Role trên IAM console

Sau khi tạo xong bạn sẽ có kết quả như sau:

Bước 4: Code chức năng resize ảnh bằng Nodejs

Để resize được ảnh mình đã dùng đoạn code phía dưới này.

// dependencies
const AWS = require('aws-sdk');
const util = require('util');
const sharp = require('sharp');

// get reference to S3 client
const s3 = new AWS.S3();

exports.handler = async (event, context, callback) => {

  // Read options from the event parameter.
  console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
  const srcBucket = event.Records[0].s3.bucket.name;
  // Object key may have spaces or unicode non-ASCII characters.
  const srcKey    = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));
  const dstBucket = srcBucket + "-resized";
  const dstKey    = "resized-" + srcKey;

  // Infer the image type from the file suffix.
  const typeMatch = srcKey.match(/\.([^.]*)$/);
  if (!typeMatch) {
      console.log("Could not determine the image type.");
      return;
  }

  // Check that the image type is supported  
  const imageType = typeMatch[1].toLowerCase();
  if (imageType != "jpg" && imageType != "png") {
      console.log(`Unsupported image type: ${imageType}`);
      return;
  }

  // Download the image from the S3 source bucket. 

  try {
      const params = {
          Bucket: srcBucket,
          Key: srcKey
      };
      var origimage = await s3.getObject(params).promise();

  } catch (error) {
      console.log(error);
      return;
  }  

  // set thumbnail width. Resize will set the height automatically to maintain aspect ratio.
  const width  = 200;

  // Use the sharp module to resize the image and save in a buffer.
  try { 
      var buffer = await sharp(origimage.Body).resize(width).toBuffer();
          
  } catch (error) {
      console.log(error);
      return;
  } 

  // Upload the thumbnail image to the destination bucket
  try {
      const destparams = {
          Bucket: dstBucket,
          Key: dstKey,
          Body: buffer,
          ContentType: "image"
      };

      const putResult = await s3.putObject(destparams).promise(); 
      
  } catch (error) {
      console.log(error);
      return;
  } 
      
  console.log('Successfully resized ' + srcBucket + '/' + srcKey +
      ' and uploaded to ' + dstBucket + '/' + dstKey); 
};
            

Việc cuối cùng ở bước này đó là mình sẽ thực hiện  zip lại các file, các dependencies cần thiết lại. (Dạng file zip) --> Việc này rất quan trọng.

Bước 6: Tạo Lambda function

Vào màn hình Lambda console, sau đó chọn "Create Function".

Sau đó chọn "Author from scractch" --> Đặt tên cho function của bạn ở mục "Function Name" (Ở đây mình đặt là CreateThumbnail) --> Sau đó chọn ngôn ngữ cho Lambda của bạn (Mình đã chọn Nodejs).

Sau đó kéo xuống phía dưới,tại mục "Change default execution role", các bạn chọn role đã tạo ở các bước trước đó là "lambda-s3-role".Ở bước này bạn đã chính thức gán quyền cho Lambda, cho Lambda được access vào các file trong bucket ở S3 mà bạn đã chỉ định.

Cuối cùng bạn click button "Create Function".

Sau khi tạo xong, các bạn sẽ thấy Lambda function ở màn hình Lambda console.

Sau đó bạn click function để config phần chi tiết của Lambda và thực hiện upload code lên lambda.

Bước 7: Config Lambda và thực hiện upload code

Các bạn add trigger của Lambda là S3, sau đó chọn bucket nguồn để làm trigger.

Sau đó tại mục Upload from, bạn chọn ".zip file". Lúc này bạn chọn file code bạn đã zip ở bước trước nhé.

Sau khi upload xong, thì lúc này lambda cũng hoạt động rồi.

Giờ chúng mình cùng test thành quả nhé.

Bước 8: Test thành quả

Mình sẽ thực hiện test theo các bước sau:

8.1: Vào bucket hoabucket, sau đó upload một ảnh lên

8.2: Vào bucket hoabucket-resized để check ảnh thumbnail thành phẩm.

Chúng mình cùng thực hiện nào.

Trước khi thực hiện check mình sẽ cho các bạn  nhìn bucket số 2 của mình khi CHƯA EXCUTE LAMBDA FUNCTION nhé. Nó sẽ trống trơn không có gì.

Trước khi excute Lambda function, bucket số 2 của mình trống trơn

8.1: Vào bucket hoabucket, sau đó upload một ảnh lên

Sau khi ảnh mình chọn được upload thành công lên "hoabucket" thì Lamba sẽ nhận được "tín hiệu", và excute function mình đã tạo (Resize lại ảnh được up lên bucket hoabucket)

8.2: Vào bucket hoabucket-resized để check ảnh thumbnail thành phẩm.

Ồ trong bucket-resized đã có ảnh thumbnail thành phẩm rồi.

Chúng mình cùng mở ảnh đó xem thế nào nhé

Vậy là các bạn đã cùng mình thực hiện từng bước trong usecase: Sử dụng S3 trigger để invoke Lambda Function.

Hi vọng bài viết này sẽ có ích cho các bạn trong quá trình tìm hiểu về AWS service.

Chúc các bạn luôn kiên trì trong những mục tiêu mình đã định ra ♥️

Tags

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.