Tag: aws

  • Kiểm soát chi phí sử dụng AWS thông qua việc tạo AWS Budget

    Kiểm soát chi phí sử dụng AWS thông qua việc tạo AWS Budget

    Bạn đã trải nghiệm với các dịch vụ trên AWS, nhưng không may bạn nhận được một bất ngờ không mong muốn trên hóa đơn AWS vào cuối tháng?

    Hoặc có lẽ ai đó trong tổ chức của bạn đã hỏi bạn về việc chi phí AWS tăng cao, có cách nào nhận thông báo chi phí đã sử dụng trên AWS theo hằng ngày được không.

    Đây là việc mà có lẽ hầu hết các kĩ sư cloud đã trải qua.

    AWS Budget sẽ giúp các bạn giải quyết các vấn đề đó. Theo dõi các bước bên dưới để thiết lập nó nhé.


    (1) Đăng nhập vào tài khoản AWS của bạn. Nhập AWS Budgets ở ô tìm kiếm. Sau khi hiển thị kết quả chọn AWS Budgets.

    budget1

    (2) Ở màn hình giao diện Budgets, chọn Create budget.

    budget2

    (3) Ở Step 1, chọn Budget types là Cost budget, sau đó ấn Next step.

    budget3

    (4) Ở Step2, nhập các thông tin budget như hình. Ở chỗ nhập Enter your budgeted amount nên nhập giá trị nhỏ, để Budget sẽ dễ dàng kiểm tra và thông báo cho bạn được thường xuyên. Mình hay để chỗ này tầm 5 hoặc 10$.

    budget4

    (5) Ở Step3, chọn Add an alert threadhold để cài đặt alert.

    budget5

    Trên giao diện Alert, mình sẽ cần nhập thông tin như bên dưới:

    • Threshold: Phần trăm cost sử dụng so với giá trị budget đã set ở Step2 để trigger thông báo. Mình hay để chỗ này tầm 50 hoặc 60.
    • Email recipients: Nhập các email bạn mong muốn để nhận thông báo cost. Các email sẽ cách nhau bởi dấu (,)

    budget6 Sau khi đã nhập xong thì mình chuyển sang step tiếp theo.

    (6) Ở Step4, mình sẽ để default không thay đổi gì cả và chuyển sang step tiếp theo. budget7

    (7) Ở Step5, mình sẽ nhìn lại các cài đặt ở các bước lúc trước. Nếu không có vấn đề gì thì mình chọn Create budget. budget8

    (8) Bạn sẽ nhận email có nội dung như bên dưới. budget9

  • How to build an end to end scalable visual search system with AI Computer Vision and AWS

    How to build an end to end scalable visual search system with AI Computer Vision and AWS

    With the rise of e-commerce, online retail, visual search is a rapid trend because they are largely driven by visual content. In this article, I will share with you guys the visual search project that was built in 2018 for my Japanese partner.

    What are the problems?

    My partner is one of the biggest retailers of toys, clothing, and baby product in Japan. They have lots of stores all over the world. On holiday, the long queues of customers wait to checkout happen in lots of stores. So to solve this problem, they decide to apply the new store like Amazon Go, no queues, no checkout, just walk out of the store. In short, this not only improves their customers’ buying experience but also maximizes revenue growth.

    Why do we need Visual Search?

    provider

    My partner has lots of providers. Each of them distributes different types of products. The products will be updated frequently by weekly, monthly, or yearly. So visual search system needs to be updated the same as the scale of products.

    What is the core technology here?

    provider

    By the time I started this project in 2018, Triplet loss had proved efficient in Face Recognition. With that starting point, we decide to apply Triplet Loss as our core visual search technology because our problem is quite similar to Face Recognition. To get the highest accuracy and make the system scalable, we classify products into different categories and subcategories because Triplet loss will have the best performance when all the products are in the same domain property. For example, when you do Face Recognition, all the images are facial, right? Then in our problem, we train all the toys that have a similar domain with one AI Model. For example, the Lego toys will be trained together, the Figures will be trained together, and so on. And not only that, one of the most advantages here is when new products need to be updated, our system don’t need to re-training the whole model, the whole process which can reduce the cost. Normally, it’s very costly and takes us lots of time for training an AI model.

    The architecture overview

    provider As you can see, we have two main components: Serving and Training. The training component is built to fit with Admin, Operator, Providers, and Developers with different purposes. For any Machine Learning production, one of the most challenging parts is how your system can run automatically with the minimum of human interference. The serving component will host all APIs needed for our web app and mobile app.

    Triplet Loss training strategy

    Our strategy here to get the best model is: Clustering the categories to group categories with similar type samples. For each anchor image, we will pick 1 hardest positive, 1 hardest negative among the image batch. We will keep multiple anchors and compute the centroid of anchors for each category. To reduce computation cost we will first match with anchor centroids. If the distance is lower than TL and higher than TH, we will give an immediate decision that the product exists and doesn’t exist respectively. We are using two thresholds. Lower threshold, TL, and higher threshold And in the end, our model has very good accuracy, for the trained data, the accuracy is over 99 percent and 97 percent for un-trained data respectively.

    Alt text

    Demo

    A Video Worth a Million words, so, please see this demo below on how we increase customer engagement with AR and AI.

    Alt text

    Conclusion

    This article is focused on sharing the overview flow, architecture, and an example use case when AI is applied in the real world. If you are curious more about the technology, the development, or the business side, please follow my next articles.

  • Triển khai CD cho dự án phát triển Website với Gitlab-CI và AWS S3

    Triển khai CD cho dự án phát triển Website với Gitlab-CI và AWS S3

    Article overview

    Giả sử chúng ta phát triển một sản phẩm Website với ReactJS và sử dụng Static Website Hosting của AWS S3. Mỗi lần deploy đều cần thực hiện build source và upload manual.
    Mục tiêu là triển khai CD để thay thế cho các công việc manual không cần thiết và giảm thiểu các sai sót ngoài ý muốn.

    Tổng quan về các công nghệ sử dụng:

    • ReactJS Website
    • Gitlab-CI
    • AWS S3, AWS CLI
    • Môi trường MacOS

    Table of contents

    Chúng ta cần một số bước sau:

    • Liên kết và khởi tạo Runner với Gitlab repository
    • [Cài đặt và cấu hình môi trường tại thiết bị chạy service runner](## Cài đặt và cấu hình môi trường tại thiết bị chạy service runner)
    • [Cấu hình các job CI/CD với .gitlab-ci.xml và Gitlab-CI](## Cấu hình các job CI/CD với gitlab-ci.xml và Gitlab-CI)

    Cài đặt và cấu hình môi trường tại thiết bị chạy service runner

    Giả định ở thiết bị MacOS chạy service runner đã build được Website ReactJS, chúng ta sẽ skip qua phần cài đặt cho ReactJS. Đầu tiên, chúng ta cần cài đặt AWS CLI.
    Sau khi cài đặt xong, ta thực hiện config với thông tin của AWS User có quyền deploy lên AWS S3 với câu lệnh sau:

    $ aws configure
    AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
    AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    Default region name [None]: us-west-2
    Default output format [None]: json

    Cấu hình các job CI/CD với gitlab-ci.xml và Gitlab-CI

    Đầu tiên, thay vì upload bằng tay các file trong thư mục build/ chúng ta sẽ sử dụng command aws s3 sync như sau:
    aws s3 sync build/ s3://ww95 với ww95 là tên của Bucket đang Host Website.
    Sau đó, chúng ta sẽ cài đặt command package.json như sau:

      "scripts": {
        "build": "react-scripts build", // Build source code để deploy
        "deploy": "aws s3 sync build/ s3://ww95" // Thực hiện deploy lên S3
      },

    Tiếp đó, ta sẽ cấu hình .gitlab-ci.yml để hệ thống tự động deploy khi có thay đổi trên nhánh master.

    stages:
      - Deployment
    deploy:
      stage: Deployment
      before_script: []
      only:
          - master
      allow_failure: true
      script:
        - yarn install
        - yarn build
        - yarn deploy

    Tuy nhiên, khi chạy thực tế trên Gitlab-CI ta sẽ gặp lỗi sau:

    Treating warnings as errors because process.env.CI = true.
    Most CI servers set it automatically. 
    Failed to compile.

    Để giải quyết vấn đề này ta phải setting lại process.env.CI = false bằng hai cách sau:

    • Thay đổi cấu hình .gitlab-ci.yml từ yarn build -> CI=false yarn build.
    • Cài đặt biến môi trường trong Gitlab-CI như ảnh sau

    Sau đó merge code vào master, và hưởng thành quả. Từ giờ các bạn không cần phải deploy bằng tay nữa rồi, chúc các bạn may mắn.

    Authors

    MinhNN44

  • Transfer file lên AWS EC2 với SFTP

    Transfer file lên AWS EC2 với SFTP

    Giả sử chúng ta có một AWS EC2 instance sử dụng linux và cần upload/download file. Trong trường hợp này, chúng ta có thể sử dụng SFTP để thực hiện upload/download file lên server.

    Mặc định, chúng ta cần dùng file key “.pem” để authen cho user ec2-user khi SSH vào EC2 instance. Chúng ta có thể sử dụng file .pem này để thực hiện SFTP tới instance như sau.

    Chú ý: Phần Host chúng ta điền public IP của instance.

    Tuy nhiên, phương pháp này có một số hạn chế và nguy cơ:

    1. Cần có file .pem để có thể SFTP tới EC2 instance. Rất bất tiện và yêu cầu phải chia sẻ file .pem nếu thực hiện SFTP trên nhiều thiết bị khác nhau.
    2. Việc chia sẻ và sử dụng file .pem để SFTP rất không an toàn. Nếu file .pem rơi vào tay kẻ xấu, họ có thể truy cập vào EC2 instance (SSH) và lấy cắp nhiều thông tin khi ec2-user có thể switch sang account root.

    Để giải quyết vấn đề này, chúng ta cần thực hiện chuyển cơ chế SFTP từ key .pem sang username/password và phân quyền cho các user đó.

    Chú ý, các câu lệnh sau cần được thực thi với quyền root

    Đầu tiên, chúng ta tạo ra các user để dành riêng cho việc sử dụng SFTP thay vì ec2-user:

    adduser user_gsthl
    adduser user_gstdn
    adduser user_gsthcm

    Và cài đặt mật khẩu cho các user với câu lệnh sau:

    passwd user_gsthl
    passwd user_gstdn
    passwd user_gsthcm

    Tiếp đó, chúng ta cần tạo một group dành riêng cho các user có quyền được phép sử dụng SFTP đến EC2 instance và add các user đó vào group:

    groupadd sftp
    usermod -a -G sftp user_gsthl
    usermod -a -G sftp user_gstdn
    usermod -a -G sftp user_gsthcm

    Chúng ta có thể kiểm tra các user ở trong group với câu lệnh sau:
    grep sftp /etc/group

    Tiếp đó, chúng ta tạo một thư mục dành riêng cho việc lưu trữ các file chuyển qua SFTP và phân quyền cho thư mục đó.
    mkdir -p /public/sftp/
    chmod 755 /public/sftp/
    Tiếp đó, ta tạo một file trong thư mục để client có thể download về.

    touch /public/sftp/hello.txt
    echo "This is a hello from SFTP directory" > /public/sftp/hello.txt

    Config file SFTP bằng cách thực hiện command sau
    sudo nano /etc/ssh/sshd_config
    Thêm đoạn config sau vào cuối của file sshd_config

    Port 22
    Subsystem sftp internal-sftp
    Match Group sftp
    ChrootDirectory /public/sftp
    X11Forwarding no
    AllowTcpForwarding no
    ForceCommand internal-sftp
    PasswordAuthentication yes

    Sau khi config, chúng ta sử dụng lệnh sudo systemctl restart sshd để khởi động lại sshd service. Nếu có lỗi trong quá trình khởi động lại, sử dụng lệnh systemctl status sshd.service -l để thực hiện kiểm tra trạng thái của service.

    Sau đó, ta có thể sử dụng FileZilla để kiểm tra SFTP đến server như sau:

    Như vậy là ta đã cài đặt xong SFTP sử dụng username/password cho một group user cho AWS EC2 chạy Linux. Mong là bài viết có thể giúp ích cho các bạn giải quyết các vấn đề liên quan đến SFTP với AWS EC2. Nếu có câu hỏi hay góp ý nào, rất mong mọi người comment, mình sẽ giải đáp và tiếp thu.

    Authors

    TinNH6

  • Triển khai Continuous Delivery cho dự án Serverless Backend với Gitlab-CI và AWS Lambda Function

    Triển khai Continuous Delivery cho dự án Serverless Backend với Gitlab-CI và AWS Lambda Function

    Article overview

    Giả sử chúng ta phát triển một sản phẩm Serverless Backend với AWS Lambda Function và mong muốn áp dụng CD để tự động hoá công việc deploy lên Cloud.
    Bài viết áp dụng cho cấu trúc hệ thống git với mỗi một Function sẽ có một branch phát triển riêng. Ví dụ source code cho Function authentication sẽ được lưu ở branch master-authentication.

    Tổng quan về các công nghệ sử dụng:

    • NodeJS
    • Gitlab-CI
    • AWS Lambda Function, AWS CLI
    • Môi trường MacOS, Linux

    Table of contents

    Chúng ta cần một số bước sau:

    Cài đặt và cấu hình môi trường tại thiết bị chạy service runner

    Đầu tiên, chúng ta cần cài đặt AWS CLI.
    Sau khi cài đặt xong, ta thực hiện config với thông tin của AWS User có quyền deploy lên AWS S3 với câu lệnh sau:

    $ aws configure
    AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
    AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
    Default region name [None]: us-west-2
    Default output format [None]: json

    Cấu hình các job CI/CD với gitlab-ci.xml và Gitlab-CI

    Đầu tiên, để có thể update code lên AWS Lambda chúng ta sẽ sử dụng command aws lambda update-function-code.

    Command hỗ trợ tham số –zip-file để upload source code dưới dạng .zip file, nên việc đầu tiên chúng ta cần làm là zip source code lại.
    zip -r deploy.zip .
    Sau khi zip xong, ta thực hiện deploy zip file lên AWS Lambda bằng câu lệnh sau:

    aws lambda update-function-code --function-name authentication --zip-file fileb://deploy.zip

    Với authentication là tên của Lambda Function, deploy.zip là tên file zip cần đẩy lên.

    Ta sẽ setting command cho package.json như sau:

    "scripts": {
        "deploy": "zip -r deploy.zip . && aws lambda update-function-code --function-name authentication --zip-file fileb://deploy.zip"
    }

    Tiếp đó, ta sẽ cấu hình .gitlab-ci.yml để hệ thống tự động deploy khi có thay đổi trên nhánh master-authentication.

    stages:
      - Deployment
    deploy:
      stage: Deployment
      before_script: []
      only:
          - master-authentication
      allow_failure: true
      script:
        - yarn install --production 
        - yarn deploy

    Sau đó merge code vào master-authentication, và hưởng thành quả. Từ giờ các bạn không cần phải deploy bằng tay nữa rồi, chúc các bạn may mắn.

    Authors

    ThangPV12

  • [AWS] Remote Debugging ứng dụng Lambda viết bằng Java với Visual Studio Code

    [AWS] Remote Debugging ứng dụng Lambda viết bằng Java với Visual Studio Code

    Debug cũng quan trọng giống như lúc bạn code vậy. Với những bạn làm quen với Lambda thì không phải ai cũng biết làm sao để có thể debug được. Đa phần các bạn sẽ chọn cách in dữ liệu ra màn hình để debug. Hôm nay tôi sẽ hướng dẫn các bạn cách debug ứng dụng viết bằng Lamba nhé.

    Remote Debugging

    Như các bạn đều biết thì để có thể debug được ứng dụng Java thì bạn cần phải Remote tới cổng Debug của trình thực thi Java. Quá trình này được gọi là Remote Debugging. Với ứng dụng Java bình thường các bạn có thể dễ dàng sử dụng các IDE có hỗ trợ Remote Debugging một cách dễ dàng. Với các ứng dụng Lambda bằng Java thì sao?

    Khởi động ứng dụng Lambda với chế độ Remote Debugging

    Trong bài viết Phát triển ứng dụng Lambda bằng Java, tôi đã hướng dẫn các bạn cách sử dụng SAM để chạy các ứng dụng Lambda viết bằng ngôn ngữ Java. Các bạn theo dõi bài viết trên sẽ thấy ứng dụng được chạy trên một máy ảo Java trông một docker container. Để khời động chế để Remote Debugging thì các bạn gõ lệnh sau(các bạn nhớ khởi động Docker trước khi khởi động SAM nhé):

    hieunv@HieuNV sam-app % sam local start-api -d 5858
    Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
    You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
    2020-03-30 20:10:33  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
    

    Các bạn sẽ thấy SAM được khởi động và lắng nghe ở cổng 3000. Còn cổng 5858 thì sao? Tại thời điểm này nó chưa được khởi động. Khi bạn access vào http://127.0.0.1:3000/hello thì cổng Remote Debugging 5858 mới được khởi động.

    Invoking helloworld.App::handleRequest (java11)
    
    Fetching lambci/lambda:java11 Docker container image......
    Mounting /Users/hieunv/Projects/hieunv/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
    Picked up _JAVA_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=*:5858 -XX:MaxHeapSize=2834432k -XX:MaxMetaspaceSize=163840k -XX:ReservedCodeCacheSize=81920k -XX:+UseSerialGC -XX:-TieredCompilation -Djava.net.preferIPv4Stack=true
    

    Cấu hình Remote Debug trong Visual Studio Code

    Các bạn quay lại Visual Studio Code, vào Tab Debug sau đó chọn create a launch.json file. Tại mục chọn kiểu Debug bạn chon Add Configuration và chọn

    add configuration

    Sau đó các bạn chon Attach To Remote Program

    Attach To Remote Program

    Tiếp đó các bạn sửa lại cấu hình hostName thành localhostport thành 5858(đấy là cổng Remote Debug của trình thực thi Java)

    {
      // Use IntelliSense to learn about possible attributes.
      // Hover to view descriptions of existing attributes.
      // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
      "version": "0.2.0",
      "configurations": [
        {
          "type": "java",
          "name": "Debug (Attach) - Remote",
          "request": "attach",
          "hostName": "localhost",
          "port": 5858
        }
      ]
    }
    

    Đặt break point

    Các bạn quay lại Visual Studio Code và mở mã nguồn muốn debug sau đó đặt break point

    break point

    Khởi động Visual Studio Code Debug bằng các click vào nut Start

    Xem output log bạn sẽ thấy thông báo sau:

    START RequestId: 4f69214b-9a3a-19ef-0137-5081d7caccea Version: $LATEST
    END RequestId: 4f69214b-9a3a-19ef-0137-5081d7caccea
    REPORT RequestId: 4f69214b-9a3a-19ef-0137-5081d7caccea	Init Duration: 58932.30 ms	Duration: 10421.29 ms	Billed Duration: 10500 ms	Memory Size: 512 MB	Max Memory Used: 73 MB
    2020-03-30 20:39:18 127.0.0.1 - - [30/Mar/2020 20:39:18] "GET /hello HTTP/1.1" 500 -
    ``
    

    Sau đó bạn access http://127.0.0.1:3000/hello bằng Postman và quay lại Visual Studio Code

    debug mode

    Như vậy là chúng ta đã debug thành công vào hàm Lambda rồi.

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết sẽ giúp ích với dự án của các bạn. Chúc các bạn thành công.

  • [AWS] Phát triển ứng dụng Lambda bằng Java

    [AWS] Phát triển ứng dụng Lambda bằng Java

    Như các bạn đã biết hiện nay môi trường thực thi sử dụng trong Lambda phần lớn đang sử dụng Node hay Python. Tuy nhiên trên thực tế đôi khi bạn cần sử dụng một môi trường thực thi khác như Java chẳng hạn. Trên thực tế thì AWS cũng đang hỗ trợ khá nhiều môi trường thực thi khác nhau. Có nhiều lý do dẫn tới việc chúng ta phải sử dụng một môi trường thực thi nào đó tuỳ vào tình hình dự án. Trong bài viết này tôi sẽ hướng dẫn các bạn xây dựng ứng dụng Lamba sử dụng môi trường thực thi là Java.

    Các công cụ cần thiết

    Docker

    Chúng ta cần Docker bởi vì công cụ thực thi SAM CLI sẽ sử dụng docker container để thực thi ứng dụng. Bạn thao khảo đường dẫn sau để cài đặt Docker

    SAM

    Chúng ta sẽ sử dụng SAM vì chúng ta cần một môi trường thực thi có thể chạy trên môi trường cục bộ và có thể debug được. Để cài SAM bạn làm theo hướng dẫn sau:

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

    Chúng ta sử dụng brew để cài SAM nên bạn cần cài brew trước. Nếu chưa cài brew thì bạn có thể thao khảo cách cài brew như sau:

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
    hieunv@HieuNV ~ % brew --version
    Homebrew 2.2.10
    Homebrew/homebrew-core (git revision f0179; last commit 2020-03-22)
    Homebrew/homebrew-cask (git revision 0a88ae; last commit 2020-03-22)
    

    Để kiểm tra xem bạn đã cài đặt thành công chưa, bạn sử dụng lệnh sau:

    hieunv@HieuNV ~ % sam --version
    SAM CLI, version 0.45.0
    

    Trên Windows thì bạn thao khảo đường dẫn này

    Oracle JDK

    Chúng ta sẽ sử dụng môi trường thực thi Java nên việc cài đặt Oracle JDK là đương nhiên đúng không. Các bạn tham khảo cách cài đặt Oracle JDK tại đây nhé.

    Maven

    SAM sẽ sử dụng maven để build nên chúng ta cần cài đặt thêm maven. Để cài đặt Maven các bạn sử dụng lệnh sau:

    brew install --ignore-dependencies maven
    

    Các bạn chú ý, chúng ta cần sử dụng --ignore-dependencies để bỏ qua việc cài đặt Open JDK nhé. Mặc định maven sẽ sử dụng Open JDK. Tuy nhiên chúng ta đã cài đặt Oracle JDK rồi nên không cần cài Open JDK nữa.

    Tài liệu tham khảo:

    Tạo project bằng SAM

    • Tạo một project mới
    hieunv@HieuNV hieunv % sam init -r java11
    Which template source would you like to use?
    	1 - AWS Quick Start Templates
    	2 - Custom Template Location
    Choice: 1
    
    Which dependency manager would you like to use?
    	1 - maven
    	2 - gradle
    Dependency manager: 1
    
    Project name [sam-app]:
    
    Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git
    
    AWS quick start application templates:
    	1 - Hello World Example: Maven
    	2 - EventBridge Hello World: Maven
    	3 - EventBridge App from scratch (100+ Event Schemas): Maven
    Template selection: 1
    
    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: java11
    Dependency Manager: maven
    Application Template: hello-world
    Output Directory: .
    
    Next steps can be found in the README file at ./sam-app/README.md
    
    • Trước khi thực thi bạn cần build project trước
    hieunv@HieuNV hieunv % cd sam-app
    hieunv@HieuNV sam-app % sam build
    Building resource 'HelloWorldFunction'
    /usr/local/bin/mvn is using a JVM with major version 13 which is newer than 11 that is supported by AWS Lambda. The compiled function code may not run in AWS Lambda unless the project has been configured to be compatible with Java 11 using 'maven.compiler.target' in Maven.
    Running JavaMavenWorkflow:CopySource
    Running JavaMavenWorkflow:MavenBuild
    Running JavaMavenWorkflow:MavenCopyDependency
    Running JavaMavenWorkflow:MavenCopyArtifacts
    
    Build Succeeded
    
    Built Artifacts  : .aws-sam/build
    Built Template   : .aws-sam/build/template.yaml
    
    Commands you can use next
    =========================
    [*] Invoke Function: sam local invoke
    [*] Deploy: sam deploy --guided
    
    • Khởi động ứng dụng (trước khi khởi động bạn cần đảm bảo rằng Docker đang hoạt động)
    hieunv@HieuNV sam-app % sam local start-api
    Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
    You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
    2020-03-22 22:07:45  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
    

    Chúng ta thử truy cập vào http://127.0.0.1:3000/hello bằng Postman. Nếu các bạn chưa chạy lần nào thì sẽ phải chờ hơi lâu một chút để Docker tải image cần thiết.

    start-api

    Trong bài viết này tôi đã hướng dẫn các bạn cách viết một API bằng Lambda sử dụng môi trường thực thi Java. Hy vọng bài viết sẽ giúp ích cho dự án của các bạn.

  • [AWS] Serverless và SAM, bạn chọn dùng cái nào?

    [AWS] Serverless và SAM, bạn chọn dùng cái nào?

    Mình đã viết khá nhiều bài sử dụng Serverless, tại sao mình lại viết bài này. Thực ra mình cũng mới bắt đầu làm AWS Lambda được một thời gian ngắn. Dự án đầu tiên mình làm Lambda thì đã các bạn đi được đã chọn Serverless để phát triển. Dự án thứ hai mình làm với AWS Lambda thì khách hàng đưa cho mình bộ mã nguồn đã được cấu hình sử dụng Serverless. Mọi thứ đều có vẻ ổn cho đến một ngày mình quyết định thử debug Lambda bằng Visual Studio Code. Mọi thứ trở nên phức tạp và mình tìm thấy SAM, dường như nó đã giải quyết vấn đề của mình nên mình quyết định viết bài này để cho các bạn nếu mới đến với thế giới AWS thì có thể dễ dàng lựa chọn thứ mình cần.

    Chọn Serverless hay SAM?

    Dự án đầu tiên mình dùng Serverless và viết bằng JavaScript, mọi thứ đều ổn vì mình chỉ dùng Serverless có kết hợp với Serverless Offline để chạy các hàm Lambda API trên máy tính cá nhân được. Việc debug cũng không gặp trở ngại gì do Serverless Offline có hỗ trợ debug. Thế nhưng đến dự án tiếp theo, ngôn ngữ được chọn làm môi trường thực thi là Python và mình thực sự gặp khó khăn. Mình vẫn có thể chạy được các hàm Lambda trên máy tính cá nhân nhưng không thể debug đươc. Và thế là mình bắt đầu tìm hiểu để giải quyết vấn đề này. Rồi mình tìm thấy SAM và mọi thứ dường như được giải quyết.

    Ngôn ngữ nào được hỗ trợ?

    • Serverless Offline hỗ trợ những ngôn ngữ sau:
      • Python
      • Ruby
      • Node
    • SAM hỗ trợ nhưng ngôn ngữ sau:
      • Python
      • Ruby
      • Node
      • Java
      • .NET Core

    Được hỗ trợ như thế nào?

    • Serverless Offline là plugin được cá nhân phát triển. Nó không phải gói được hỗ trợ chính thức từ AWS.

    • SAM được hỗ trợ chính thức từ AWS.

    Hỗ trợ debug như thế nào?

    • Serverless Offline chỉ hỗ trợ debug với Node.

    • SAM thì có vẻ như đã hỗ trợ tất cả các trình thực thi ở trên. Mình đã thử debug với Java thì thấy vẫn OK.

    Môi trường thực thi

    • Serverless chạy trực triếp trên máy host.
    • SAM thì sử dụng container trong docker để thực thi.

    Các bạn có thể tham khảo hướng dẫn sử dụng Serverless ở các tài liệu sau nhé:

    Kết luận

    SAM dường như có những lợi thế hơn hẳn so với Serverless. Nếu bạn quyết định phát triển bằng Node thì bạn sẽ không gặp nhiều khó khăn khi dùng Serverless hay SAM. Nếu bạn chọn một môi trường thực thi khác như Python hay Ruby hay bất kỳ môi trường nào khác thì lựa chọn SAM sẽ là quyết định sáng suốt hơn đấy. Mình sẽ hướng dẫn các bạn sử dụng SAM trong loạt bài viết về SAM sau nhé.

  • [AWS] Sử dụng API Gateway Lambda Authorizers với JWT như thế nào?

    [AWS] Sử dụng API Gateway Lambda Authorizers với JWT như thế nào?

    Một trọng những vấn đề quan trọng trong các dự án đó là điều khiển quyền truy cập. Với các ứng dụng xây dựng trên nền tảng AWS việc điều khiển truy cập cũng phức tạp hơn. Trong bài viết này tôi sẽ hướng dẫn các bạn cách tôi đã làm để điểu khiển truy cập với các API sử dụng API Gateway Lambda Authorizers.

    Luồng xác thực Lambda Authorizer

    Luồng xác thực của Lambda Authorizer được minh hoạ trong hình sau:

    auhorizer

    Các bược xác thực như sau:

    1. Máy khách gửi yêu cầu lên API Gateway API có kèm theo Bearer Token.
    2. API Gateway kiểm tra cấu hình authorizer đã được cấu hình tương ứng với hàm Lambda. Nếu nó tồn tại thì Lambda Authoirizer sẽ được gọi.
    3. Lambda Authorizer sẽ thực hiện xác thực bằng Bearer Token đã được gửi lên.
    4. Nếu việc gọi Lambda Authrorizer thực hiện thành công, hàm Lambda sẽ trả về thông tin chứa chính sách IAM và thông tin người dùng.
    5. API Gateway sử dụng thông tin trả về từ Lambda Authorizer để kiểm tra quyền truy cập:
    • Trường hợp nhận được thông tin từ chối truy cập thì API Gateway sẽ trả về mã 403 và từ chối truy cập tới API từ máy khách.
    • Trường hợp nhận được thôn tin cho phép truy cập thì phương thức sẽ được thực thi.

    Định nghĩa Lambda Authorizer

    • Khai báo authorizer trong serverless.yml:
    functions:
      authorizer:
        handler: src.api.authorizer.lambda_handler
        cors: true
    
    • Định nghĩa hàm Lambda Authorizer:
    import jwt
    
    
    def lambda_handler(event, context):
        try:
            token = event.get("authorizationToken").split(" ")[1] # lấy thông tin token trong Authorization header
            claims = jwt.decode(token, "secret", algorithms=["HS256"]) # decode xem token có hợp lệ không
            return {
                "principalId": claims["uid"], # lấy thông tin user đề gán vào IAM
                "policyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Action": "execute-api:Invoke",
                            "Effect": "Allow", # cho phép nếu token hợp lệ
                            "Resource": event["methodArn"],
                        }
                    ],
                },
            }
        except:
            return {
                "principalId": "denied",
                "policyDocument": {
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Action": "execute-api:Invoke",
                            "Effect": "Deny", # từ chối nếu token không hợp lệ
                            "Resource": event["methodArn"],
                        }
                    ],
                },
            }
    

    Định nghĩa hàm Lambda cần điều khiển quyề truy cập

    • Khai báo hàm Lambda trong serverless.yml
    functions:
      test:
        handler: src.api.test.lambda_handler
        events:
          - http:
              method: get
              path: api/test
              cors: true
              authorizer: authorizer # khai báo Lambda Authorizer
    
    • Định nghĩa hàm Lambda:
    import json
    
    
    def lambda_handler(event, context):
        headers = {"Access-Control-Allow-Origin": "*", "Accept": "application/json"}
        body = {"status": "success"}
        return {
            "statusCode": 200,
            "headers": headers,
            "body": json.dumps(body),
        }
    

    Test thử Lambda với Authorizer

    • Trường hợp không truyền token trên Authorizer Header, API Gateway sẽ trả về 403

    No Auth

    • Trường hợp có truyền token trên Authorization Header, API Gateway sẽ cho phép phương thức được thực thi

    Token được tạo như sau

    (zpn) hieunv@HieuNV lambda % python
    Python 3.7.7 (default, Mar 10 2020, 15:43:33)
    [Clang 11.0.0 (clang-1100.0.33.17)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import jwt
    >>> jwt.encode({'uid': 'hieunv'}, "secret", algorithm='HS256')
    b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOiJoaWV1bnYifQ.xuZSlS_3lw6NvGvw_fQ2qXGBWiv2HpXTFtYtO85lQac'
    

    Truyền token lên Authorizer Header

    Bearer Auth

    Tài liệu tham khảo:

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết có thể giúp các bạn cài đặt việc điều khiển truy cập dễ dàng hơn với các ứng dụng trên nền tảng AWS.

  • [AWS] Lambda và DynamoDB Streams không còn khó nữa!

    [AWS] Lambda và DynamoDB Streams không còn khó nữa!

    Với các ứng dụng hiện nay, việc giao tiếp giữa client và server phổ biến đang sử dụng Rest API. Trong một số trường hợp việc phải để client đợi xử lý là điều không thể chấp nhận được. Do đó để giải quyết vấn đề này thì phần lớn cách giải quyết là sử dụng batch process, nghĩa là tại thời điểm đó chúng ta sẽ trả lại dữ liệu cho client ở trạng thái đang xử lý(tránh xảy ra tình trạng timeout). Tuy nhiên ngay tại thời điểm đó một batch process sẽ được khởi động để thực thi tiếp các công việc còn lại. Trong bài viết này tôi sẽ hướng dẫn các bạn viết batch process bằng AWS Lambda bằng cách sử dụng DynamoDB Streams.

    DynamoDB Streams

    DynamoDB Streams là một tính năng trong DynamoDB cho phép bạn lắng nghe thay đổi trên một bảng dữ liệu nào đó và thực hiện các tác vụ đáp ứng yêu cầu nghiệp vụ trong ứng dụng của bạn. Mỗi khi có sự thay đổi DynamoDB sẽ ghi các bản ghi gần như ngay lập tức là dòng dữ liệu mà các ứng dụng đang lắng nghe.

    Với DynamoDB Streams để giải quyết vấn đề timeout của API chúng ta chỉ gần ghi dữ liệu vào bảng trong DynamoDB sau đó dữ liệu được ghi lên dòng dữ liệu mà batch process của chúng ta đang lắng nghe rồi tiếp tục thực hiện nhiệm vụ còn lại.

    Các bạn tham khảo link sau để cài đặt DynamoDB ở local nhé.

    Định nghĩa bảng trong DynamoDB

    Các bạn có thẻ sử dụng NoSQL Workbench for Amazon DynamoDB để tạo bảng hoặc viết code để chia sẻ với các member khác như sau:

    # -*- coding: utf-8 -*-
    import os
    from datetime import datetime
    import boto3
    
    dynamodb = boto3.client(
        "dynamodb",
        endpoint_url="http://localhost:8000",
        region_name="us-east-1",
        aws_access_key_id="test",
        aws_secret_access_key="test",
    )
    
    
    def create_orders():
        try:
            dynamodb.delete_table(TableName="dev_orders")
        except Exception as exp:
            print(exp)
    
        response = dynamodb.create_table(
            TableName="dev_orders",
            AttributeDefinitions=[
                {"AttributeName": "id", "AttributeType": "S"},
                {"AttributeName": "status", "AttributeType": "S"},
            ],
            KeySchema=[{"AttributeName": "id", "KeyType": "HASH"}],
            ProvisionedThroughput={"ReadCapacityUnits": 1, "WriteCapacityUnits": 1},
            GlobalSecondaryIndexes=[
                {
                    "IndexName": "statusGSIndex",
                    "KeySchema": [{"AttributeName": "status", "KeyType": "HASH"}],
                    "Projection": {"ProjectionType": "ALL"},
                    "ProvisionedThroughput": {
                        "ReadCapacityUnits": 1,
                        "WriteCapacityUnits": 1,
                    },
                },
            ],
            # bắt buộc phải có khai báo này để sử dụng DynamoDB Streams cho bảng này
            StreamSpecification={
                "StreamEnabled": True,
                "StreamViewType": "NEW_AND_OLD_IMAGES",
            },
        )
        print(response)
    
    
    create_orders()
    

    Kiểm tra bảng được tạo bằng NoSQL Workbench for Amazon DynamoDB

    dev_orders

    Các bạn chú ý giá trị bôi vàng nhé. Đây là dòng dữ liệu sẽ được DynamoDB ghi lên đó. Khi ứng dụng của bạn lắng nghe dòng dữ liệu này thì bất kỳ hành động nào xảy ra trên bảng sẽ được ghi lên dòng dữ liệu và ứng dụng của chúng ta sẽ phát hiện được điều đó.

    Định nghĩa Lambda lắng nghe dòng dữ liệu từ DynamoDB

    Để lắng nghe dòng dữ liệu từ DynamoDB Streams bạn cần thêm serverless-offline-dynamodb-streams và cấu hìn serverless.yml như sau:

    custom:
      # ...
      serverless-offline-dynamodb-streams:
        endpoint: http://dynamodb:8000
        accessKeyId: root
        secretAccessKey: root
    # ...
    plugins:
      - serverless-offline
      - serverless-python-requirements
      - serverless-offline-dynamodb-streams
    

    Các bạn tham khảo bài viết Mô phỏng AWS Lambda & API Gateway bằng Serverless Offline để biết các viết API bằng Lambda nhé.

    Trong bài viết này, dể thực hiện lắng nghe dòng dữ liệu, bạn định nghĩa hàm Lambda trong Serverless như sau:

    jobs_order:
      handler: src.jobs.order.lambda_handler
      events:
        - stream:
            enabled: true
            type: dynamodb
            # đây là giá trị màu vàng tôi có đề cập ở trên
            arn: arn:aws:dynamodb:ddblocal:000000000000:table/dev_orders/stream/2020-03-15T07:59:46.532
            batchSize: 1
    

    Thử viết Rest API ghi dữ liệu vào bảng và kiểm tra DynamoDB Streams

    Các bạn định nghĩa một API như sau:

    functions:
      post_orders:
        handler: src.api.post_orders.lambda_handler
        events:
          - http:
              method: post
              path: api/orders
              cors: true
    

    src/api/post_orders.py

    import json
    import logging
    from datetime import datetime
    from uuid import uuid4
    import boto3
    
    LOGGER = logging.getLogger()
    LOGGER.setLevel(logging.INFO)
    
    
    def lambda_handler(event, context):
        headers = {"Access-Control-Allow-Origin": "*", "Accept": "application/json"}
        body = json.loads(event["body"])
        dynamodb = boto3.client(
            "dynamodb",
            endpoint_url="http://localhost:8000",
            region_name="us-east-1",
            aws_access_key_id="test",
            aws_secret_access_key="test",
        )
        now = int(datetime.utcnow().timestamp())
        body = dynamodb.put_item(
            TableName="dev_orders",
            Item={
                "id": {"S": str(uuid4())},
                "name": {"S": body["name"]},
                "status": {"S": " "},
                "created_at": {"N": str(now)},
                "updated_at": {"N": str(now)},
            },
        )
        return {
            "statusCode": 200,
            "headers": headers,
            "body": json.dumps(body),
        }
    

    Các bạn thử post dữ liệu bằng Postman nhé post_orders

    Các bạn để ý Terminal sau khi post dữ liệu nhé

    terminal

    Cám ơn các bạn đã theo dõi bài viết. Hy vọng bài viết đã giúp các bạn có thể sử dùng Lambda và DynamoDB tốt hơn.