Category: AWS

  • Infrastructure as Code

    Infrastructure as Code

    Lời nói đầu

    Với sự phát triển manh mẽ của Cloud Computing, các ứng dụng mà đơn vị GST đang phát triển được xây dựng trên cloud như AWS ngày càng nhiều. Việc quản lý resource trên cloud cũng là một vấn đề cực kì quan trọng. Hôm nay mình sẽ giới thiệu về Infrastructure as Code(IaC) và Terraform, những công cụ giúp chúng ta quản lý resource cloud dễ dàng hơn.

    Nội dung

    Vấn đề

    Như đã nói ở phía trên, vấn đề chúng ta bàn đến chính là quản lý resouce cloud(AWS, Azure, GPC..). Tại sao lại phải quản lý? Lý do là mỗi dự án sử dụng khoảng 10-15 services, mỗi service có khoảng 1-10 resources, mỗi resource lại có nhiều config khác nhau. Vì vậy nếu không quản lý tốt, sẽ rất dễ bị miss resource, hoặc config giữa các resource khác nhau giữa các môi trường, lúc tạo môi trường mới mất nhiều thời gian để config, compare các môi trường với nhau, rủi ro khi xử lý manual là rất lớn. Vì vậy việc sử dụng tool để quản lý resource là cần thiết và vô cùng quan trọng. Infrastructure as Code đã được sinh ra để giải quyết các vấn đề đó.

    Infrastructure as Code

    Định nghĩa IaC thì mỗi ông định nghĩa 1 kiểu, sau đây mình sẽ trích dẫn định nghĩa mà mình cho là khá dễ hiểu:

    Infrastructure as code (IaC) is the process of managing and provisioning computer data centers through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools. The IT infrastructure managed by this process comprises both physical equipment, such as bare-metal servers, as well as virtual machines, and associated configuration resources. The definitions may be in a version control system. It can use either scripts or declarative definitions, rather than manual processes, but the term is more often used to promote declarative approaches.

    Refer: https://docs.microsoft.com/en-us/devops/deliver/what-is-infrastructure-as-code

    Hiểu một cách đơn giản hơn thì IaC có nghĩa là chúng ta sử dụng các đoạn code theo format có sẵn(giống như 1 ngôn ngữ lập trình hoặc 1 dạng template: yaml, json..) để quản lý các resource của hệ thống. Khi cần thêm, sửa, xoá 1 resource thì update vào code và apply để thay đổi infra.

    Cụ thể IaC giải quyết vấn đề gì?

    • Giải quyết vấn đề đồng bộ giữa các môi trường, không có chuyện môi trường staging 1 kiểu, môi trường prd config lại khác, vì resource cùng sinh ra từ 1 đoạn code
    • Giảm thiểu chi phí xây dựng môi trường. Ban đầu sẽ hơi mất thời gian 1 chút để tạo các resource bằng code, tuy nhiên sau khi dựng xong 1 môi trường hoàn chỉnh, tạo các môi trường khác thì chỉ cần sử dụng lại code đã tạo cho môi trường đầu tiên. Nếu có 1,2 môi trường thì lợi ích có thể ít, nhưng mình đã làm 1 dự án có 9 môi trường, việc này tiết kiệm rất nhiều thời gian
    • Khả năng tái sử dụng: Ví dụ Project A sử dụng VPC, Subnet, EC2 server, Project B cũng sử dụng các resource như vậy, chúng ta có thể tái sử dụng lại source code infra của A, optimize lại 1 chút để sử dụng luôn cho project B
    • Automation: Việc tự động tạo, update, xoá các resource khiến cho việc thục hiện manual được ít đi rất nhiều, giảm thiểu rủi ro do ngứa tay

    Một số Iac tool phổ biến:

    Terraform

    Để dễ hình dung hơn về IaC, mình sẽ giới thiệu về Terraform, một IaC tool khá phổ biến.
    Terraform là gì?

    Terraform là một IaC tool mã nguồn mở, công cụ phần mềm mã cung cấp quy trình làm việc CLI nhất quán để quản lý hàng trăm dịch vụ đám mây. Terraform mã hóa các API đám mây thành các file khai báo cấu hình.

    Một số điểm đáng chú ý:

    • Phát triển bằng Go
    • Phát triển bời HashiCorp, công ty với mục tiêu cách mạng hóa việc quản lý trung tâm dữ liệu: phát triển, phân phối và bảo trì ứng dụng
    • Multi cloud: Support tạo resource cho nhiều cloud provider khác nhau: AWS, Azure, GPC, Oracle..
    • Cung cấp cơ sở hạ tầng trên hơn 300 đám mây và dịch vụ public bằng cách sử dụng một quy trình làm việc duy nhất

    Terraform hoạt động thế nào?

    Terraform cho phép cơ sở hạ tầng được thể hiện dưới dạng mã bằng một ngôn ngữ đơn giản, con người có thể đọc được gọi là HCL (HashiCorp Configuration Language). Nó đọc các file cấu hình và cung cấp một kế hoạch thực hiện các thay đổi, có thể được xem xét để đảm bảo an toàn, sau đó mới áp dụng các thay đổi.

    Các nhà cung cấp có thể mở rộng cho phép Terraform quản lý nhiều loại tài nguyên, bao gồm IaaS, PaaS, SaaS và các dịch vụ phần cứng.

    Ví dụ Terraform và 1 số câu lệnh đơn giản

    Syntax cơ bản của Terraform

    Khi muốn apply code lên Infra của mình, thực hiện câu lệnh

    terraform apply

    Khi muốn xem sự thay đổi của code hiện tại với trạng thái trước khi thay đổi

    terraform plan

    Kết quả sau khi apply thành công

    Export file terraform thành dạng graph sử dụng lệnh

    terraform graph | dot -Tsvg > graph.svg

    Kết quả sẽ là file svg có tên là graph.svg, dùng extension để view file, ta có kết quả như sau

    CICD với terraform

    Terraform là code, thực hiện quản lý, thay đổi tác động đến Infra của hệ thống. Vậy đã là code thì hoàn toàn có thể apply deploy tự động.

    Cơ bản CICD với Terraform cũng giống như IaC với ngôn ngữ khác, thay vì các lệnh build thì chúng ta thay bằng các command của terraform.

    Kết luận

    Bài viết này mình đã giới thiệu về Infrastructure as Code, tại sao lại cần đến nó, lợi ích khi sử dụng. Mình cũng đã giới thiệu ngắn gọn về một IaC tool khá phổ biến là Terraform. Mong rằng bài viết sẽ cho mọi người thấy được tầm quan trọng của IaC và có thể nghiên cứu apply vào dự án của mình.

  • Case study ứng dụng serverless trên AWS phục vụ Olympic Tokyo

    Case study ứng dụng serverless trên AWS phục vụ Olympic Tokyo

    Lời nói đầu

    Ở đâu đó có thể các bạn đã nghe thấy khái niệm serverless hay chạy ứng dụng không mà không cần sử dụng một server nào (non-server). Hiện nay với sự phát triển mạnh mẽ của các nền tảng public cloud như AWS, Azure, Alibaba.., khái niệm serverless đang dần trở nên thân thuộc hơn với những lập trình viên. Tuy nhiên bạn đã bao giờ tự tay xây dựng một hệ thống API mà không phải sử dụng server bao giờ chưa? Theo mình thấy thì hiện tại sự trải nghiệm của các dev với serverless thực sự chưa nhiều, một phần có lẽ do người ta vẫn tin tưởng ở server truyền thống hơn(Cái gì sờ thấy được cũng chắc chắn hơn). Ở loạt bài này, mình sẽ trình bày về một dự án team mình xây dựngAPI 100% sử dụng serverless . Mình sẽ tập trung vào kiến trúc hệ thống, giải thích các thành phần và framework hỗ trợ deploy serverless nhé!

    Nội dung

    Bối cảnh

    Khách hàng của mình đã xây dựng hệ thống trên môi trường AWS, sử dụng EC2 làm server, ngôn ngữ là Java và sử dụng framework là Struts . Hệ thống hiện tại chi phí đang quá lớn (Bao gồm cả chi phí AWS cũng như các chi phí liên quan khác), thời gian sử dụng và chạy job trong ngày là không cố định(do nghiệp vụ), nhiều khi không có người sử dụng cũng như không có job nào chạy nhưng cũng phải trả tiền cho 1 server API và 1 server Job. Khách hàng đã yêu cầu chuyển hệ thống cũ sang serverless và phát triển thêm tính năng dựa trên kiến trúc mới này. Hệ thống này mình xây dựng hoàn toàn trên Amazon Web Service, nên các dịch vụ cứ mặc định là của AWS nhé!

    Mô hình hệ thống Serverless

    Có lẽ nhiều người cũng đã nhìn qua kiến trúc serverless như thế này:



    Đúng, nó là 1 kiến trúc chung thường thấy của 1 serverless system triển khai trên AWS. Flow sẽ là:

    • App call API qua API Gateway
    • API Gateway trigger lambda
    • Lambda query data từ DB, trả về kết quả
    • API Gateway response data cho client

    Bla…Bla..

    Tuy nhiên, để ứng dụng nó vào 1 dự án cụ thể cần nhiều hơn thế này, theo dõi phần tiếp theo nhé!

    Hệ thống Serverless trong thực tế

    Mỗi hệ thống sẽ có những điểm giống và khác nhau tuỳ thuộc vào bài toán cần giải quyết. Không loằng ngoằng mình sẽ đưa ra kiến trúc mình đã xây dựng luôn (Đã lược bỏ một số chi tiết, tập trung chính vào phần serverless)

    Overview hệ thống này nhé:

    • Phần màu đỏ là hosting cho Frontend(được viết bằng Angular xxx). Phần FrontEnd sẽ bao gồm một S3 Bucket được setting làm static web, 1 Cloudfront Distribution để cache lại các resource tĩnh GLOBAL.
    • Phần màu xanh là hệ thống API serverless. Chúng ta sẽ quan tâm đến phần này nhiều hơn vì nó là trọng tâm của bài viết này. Nó bao gồm những dịch vụ gì, đi lần lượt nhé:
      • WAF: Web Application Firewall – Đây được coi là bức tường lửa đầu tiên để bảo vệ web. Nhiêm vụ của nó là bảo vệ app qua rule do người dùng thiết lập, ví dụ Whitelist IP, Blacklist IP… Quan trọng hơn là nó có thể phát hiện và chặn những request có dấu hiệu tấn công như XSS, SQL Injection….
      • API Gateway: Điểm nhận tất cả các request từ phía client. AWS cho phép route từng path của request đến những handler tương ứng.
      • Cognito: Dịch vụ này cung cấp phương thức xác thực, phân quyền và quản lý người dùng.
      • Lambda (Authenticate): Vì app của mình có tính năng authen hơi đặc biệt, do vậy mình phải dùng lambda function này để add thêm 1 số feature mà Cognito không đáp ứng đủ. Lambda function này sẽ được đính trực tiếp vào API Gateway, đóng vai trò tương tự như 1 middleware, cũng đặt trong private subnet nhé, nhưng vẽ như thế để tránh rối
      • VPC, Public subnet và private subnet: Cái này nếu ai đã làm qua với AWS và network của nó thì có thể nắm được rồi. Public subnet thì có thể internet facing, private subet là nơi đặt các server EC2, RDS, Lambda là private. Không thể truy cập trực tiếp từ internet vào các dịch vụ được đặt trong private subnet.
      • InternetGateway cho phép VPC có thể truy cập Internet, VPC Endpoint cho phép kết nối đến các dịch vụ khác của AWS mà ko qua đường truyền internet
      • Squid Proxy Server: Đóng vai trò là proxy cho phép các resource từ private subet kết nối ra ngoài Internet(Nhiều người sẽ dùng NAT Gateway hoặc NAT Instance).
      • Lambda (Đặt trong private subnet): Đây chính là linh hồn của Serverless, đóng vai trò tương tự 1 server. Mỗi path của API Gateway sẽ được xử lý bởi 1 lambda function. Lambda sẽ nhận request từ API Gateway, xử lý, trả response về API Gateway -> Response về Client
      • S3: Nếu ko có server thì file được lưu trữ ở đâu, up/down thế nào? Thông thường nếu hệ thống sử dụng autoscale thì cũng cần 1 nơi lưu trữ file chung (EFS hoặc S3 ….). Với Lambda cũng vậy, mình chọn S3 để lưu trữ file. Nhưng làm thế nào để upload và download file qua lambda nhỉ. Câu trả lời là sẽ không up/download file qua lambda, lambda chỉ là trung gian, generate Pre-signed URL để client thực hiện upload và download trực tiếp với S3.
      • DynamoDB: Đây là 1 database dạng NoSQL do AWS phát triển. Lưu data dạng Key-Value. Nếu cần thiết phải sử dụng CSDL quan hệ, mình khuyến khích dùng AWS Aurora serverless(MySQL hoặc PostgreSQL), hỗ trợ tốt nếu sử dụng serverless
      • CloudWatch: Phần này có 1 số dịch vụ nhỏ hơn. Tuy nhiên có 2 service chính là Logs và Rules. Logs là nơi xem, truy vấn log mà Lambda function đã ghi ra trong quá trình chạy, Rules được sử dụng để lập lịch cho 1 số job chạy cố định hàng ngày, khi đến thời gian nó sẽ gọi lambda function tương ứng.
      • SQS: Queue được dùng cho sử dụng cho những job muốn chạy ngay lập tức. SQS trigger đến Lambda function(Job) mỗi khi có message mới được đẩy vào queue.
      • X-Ray: Service này khá hay, nó giúp monitor ứng dụng một cách chi tiết hơn, visualize nó lên trên dashboard AWS, giúp gỡ lỗi ứng dụng, phán đoán lỗi cũng như cải tiến ứng dụng tốt hơn. Ví dụ: Thời gian query data từ DynamoDb, thời gian upload file S3…….
      • SNS: Gửi notification.

    Serverless framework

    Nếu đã từng làm việc với lambda, mọi người sẽ biết được rằng mỗi Lambda function là độc lập với nhau, source code vì vậy cũng hoàn toàn riêng biệt. Vậy với 1 project lớn bao gồm hàng trăm API, làm thế nào chúng ta quản lý source code và deploy, không thể build và upload bản build cho từng lambda function được. Vì vậy team đã quyết định sử dụng framework là serverless(https://www.serverless.com)

    Serverless framework là fw hỗ trợ nhiều cloud provider phổ biến như AWS, Azure, GPC, Alibaba… Nó cung cấp cho chúntg ta 1 công cụ để quản lý full life cycle cho ứng dụng serverless. Serverless framework cũng hỗ trợ nhiều ngôn ngữ như Java, Nodejs, Go, Python …

    Cấu hình serverless:
    Tư tưởng của framework hiểu đơn giản là chúng ta cần mapping Path của API Gateway với class, file xử lý logic cho function tương ứng.

    Đây là 1 file cấu hình sample của project serverless. Một số thành phần quan trọng bao gồm:

    • provider
      • name: Tên cloud provider(aws, gpc, azure)
      • runtime: Môi trường thực thi(java8, java11, nodejs12..)
    • package:
      • artifact: Đường dẫn trỏ đến file build
    • functions: List API của project
      • Tên lambda function:
        • handler: class xử lý logic cho API
        • events:
          • http: (nếu là HTTP thì lambda function này sẽ được trigger từ API Gateway)
            • path: Đường dẫn API
            • method: HTTP method(get, post …)

    Mình chỉ giới thiệu qua cấu hình cơ bản của serverless. Lợi ích của nó là giúp chúng ta dễ dàng quản lý life cycle của project serverless, sử dụng các architype có sẵn khi tạo project.

    Tổng kết lại

    Túm lại, để nói về 1 serverless system thì 1 bài viết là không đủ. Ở phần này mình chỉ overview hệ thống, các dịch vụ và vai trò của nó . Mong rằng qua bài viết này các bạn có thể nắm được cơ bản về kiến trúc 1 hệ thống không sử dụng server truyền thống nó như thế nào, đánh giá xem có thể apply trực tiếp vào dự án tiếp theo được không. Mong rằng sẽ có nhiều hơn dự án sử dụng serverless trong đơn vị để mọi người có thêm những trải nghiệm mới.

  • Cost-effective, High Availability Cassandra with AWS EKS and EC2 Spot instance.

    Cost-effective, High Availability Cassandra with AWS EKS and EC2 Spot instance.

    Mở đầu

    Cassandra hay Apache Cassandra, là một hệ thống quản lý cơ sở dữ liệu NoSQL, mã nguồn mở, miễn phí, phân tán dựa trên mạng ngang hàng P2P, hiện tại thường dùng dễ lưu trữ dữ liệu dưới dạng timeseries.

    Bản thân Cassandra đã có khả năng High availability với thiết kế no single point of failure và bản thân Cassandra cũng hỗ trợ việc mở rộng node một cách dễ dàng, vậy tại sao không mang sức mạnh của EC2 Spot Instance (chi phí rẻ cho khả năng tính toán lớn).

    Chúng ta lợi dụng một số tính năng sau của Cassandra để xử lý:

    • Data Center

      image

      • Trong đó data center sẽ đóng vai trò như một cụm node, Cassandra có thể live backups giữa các data center, data sẽ tự động copy async sang DC khác, khi một DC down các DC khác vẫn hoạt động bình thường
    • Seed nodes: Seed nodes sẽ là nơi các node mới connect và thông báo về việc chúng join cluster Seed node hoạt động như các điểm chung chuyển, các node sẽ trao đổi với các node seeds hơn các node khác, và các node này thường sẽ có các thông tin mới nhất và đầy đủ nhất, nhưng chúng sẽ gặp vấn đề overhead nên đừng sử dụng mọi node làm seeds.

    • Data replication: Cassandra lưu trữ dữ liệu trên nhiều node để đảm bảo tính toàn vẹn và fault tolerance (mình khá không thích dịch tiếng việt tự này, có thể dịch là khả năng chịu lỗi). Có 2 strategy: Simple và NetworkTopology, vì chúng ta dự định sử dụng data center nên hãy chọn NetworkTopology

    Như vậy về mặt lý thuyết chúng ta có thể xử lý được toàn bộ vấn đề, hãy mapping chúng với, K8S và AWS thậm chí hoàn toàn có thể xử lý được với trường hợp sử dụng Spot Instance.

    image

    Chúng ta sẽ sử dụng luôn khái niệm Availability Zone của AWS cho tương ứng với data center. Như vậy sẽ có 1 Statefulset cài đặt Cassandra, 1 Service để expose với mỗi DC.

    Cài đặt nào

    Thực ra script đã được chuẩn bị ở đây rồi.

    Mình sẽ giải thích một vài điểm cần chú ý

    Chúng ta add label cho các pod, việc này để các service có thể chọn được các pod của cassandra

      template:
        metadata:
          labels:
            app: cassandra
            interface: cassandraa
    

    Chọn node để cài đặt cassandra, chúng ta có thể dùng các key khác nhưng để cho tiện thì mình dùng tạm key này, việc này đảm bảo node của DC được cài đặt theo AZ của AWS đúng tinh thần High availability

          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: topology.kubernetes.io/zone
                    operator: In
                    values:
                    - ap-southeast-1a
    

    Cassandra seeds node, node đầu tiên của các statefulset được chọn làm seed, ở đây mình xử lý dùng 1 service cassandra thay vì dùng 3 service cho 3 AZ (một điểm nho nhỏ khác biệt), việc này không ảnh hưởng lắm.

      - name: CASSANDRA_SEEDS
        value: cassandraa-0.cassandra.thingsboard.svc.cluster.local,cassandrab-0.cassandra.thingsboard.svc.cluster.local,cassandrac-0.cassandra.thingsboard.svc.cluster.local
    

    Chúng ta không cần tất cả các seed cùng một lúc, nên ngay cả khi seed down thì node vẫn hoạt động bình thường.

    Ở các pod sử dụng cassandra này thì cần chỉ rõ DC nào của Cassandra để kết nối đến, ở đây mình đang cài đặt Thingsboard nên sẽ thêm environment variable sau, tất nhiên sẽ phải xử lý tách application của bạn ra 3 statefulset hoặc deployment khác nhau:

      - name: CASSANDRA_LOCAL_DATACENTER
        value: ap-southeast-1a
    

    Tada

    2021-08-17 18:08:36
    2021-08-17 11:08:36,628 [main] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
    2021-08-17 18:08:52
    2021-08-17 11:08:52,732 [main] INFO  c.d.o.d.internal.core.ContactPoints - Contact point cassandra:9042 resolves to multiple addresses, will use them all ([cassandra/10.0.1.112, cassandra/10.0.2.149, cassandra/10.0.1.150])
    2021-08-17 18:08:53
    2021-08-17 11:08:53,734 [main] INFO  c.d.o.d.i.c.DefaultMavenCoordinates - DataStax Java driver for Apache Cassandra(R) (com.datastax.oss:java-driver-core) version 4.10.0
    2021-08-17 18:08:54
    2021-08-17 11:08:54,956 [Thingsboard Cluster-admin-0] INFO  c.d.o.d.internal.core.time.Clock - Could not access native clock (see debug logs for details), falling back to Java system clock
    2021-08-17 18:08:56
    2021-08-17 11:08:56,621 [Thingsboard Cluster-admin-0] WARN  c.d.o.d.i.c.l.h.OptionalLocalDcHelper - [Thingsboard Cluster|default] You specified ap-southeast-1b as the local DC, but some contact points are from a different DC: Node(endPoint=cassandra/10.0.1.112:9042, hostId=a56560a6-1274-43f9-b72e-d8b1e7b33bf8, hashCode=6a745db0)=ap-southeast-1a, Node(endPoint=cassandra/10.0.1.150:9042, hostId=c7f9bc1c-c066-40d6-9def-7fbe58af90bb, hashCode=2c4f4fec)=ap-southeast-1a; please provide the correct local DC, or check your contact points
    

    Nếu dòng log cuối gây confuse thì hãy sử dụng các sevice riêng biệt nhé

    Happy Coding

  • 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

  • Docker thường thức – Phần 1: Giới thiệu về Containers, Virtual machines và Docker

    Docker thường thức – Phần 1: Giới thiệu về Containers, Virtual machines và Docker

    Docker thường thức – Phần 1: Giới thiệu về Containers, Virtual machines và Docker

    Dù bạn là một Kỹ sư phần mềm hay một nhà Khoa học dữ liệu, dù bạn đang lập trình Web hay đang lập trình Mobile,… thì ít nhiều đã nghe nói về Docker. Theo một thống kê của Stack Overflow trong năm 2020; Docker xếp hạng thứ 2 trong số các nền tảng được yêu thích nhất, đồng thời dẫn đầu trong số các nền tảng mà các developers muốn tìm hiểu nhất. Như vậy có thể thấy, Docker đang dần trở thành xu thế tất yếu mà bất kỳ ai tham gia vào ngành công nghiệp công nghệ thông tin cũng nên tìm hiểu, để biết cách sử dụng nó, áp dụng nó, và biến nó trở thành công cụ hữu ích cho các dự án.

    Chuỗi bài viết về chủ đề Docker của tôi nhằm mang lại cho người đọc mới bắt đầu tìm hiểu về docker có những cái nhìn tổng quan, cơ bản nhất xung quanh công nghệ đang là hot trend này, từ đó họ có thể dễ dàng chuyển sang các chủ đề chuyên sâu hơn mà phù hợp với dự án của mỗi người.

    Trong phần 1, mục đích của bài viết này nhằm mang lại cho bạn đọc các khái niệm cơ bản liên quan đến Docker, chúng sẽ là những thứ mà bạn nhất định phải biết nếu muốn đi sâu vào công nghệ này, ngoài những giải thích bằng lời, tôi cũng cung cấp các hình ảnh trực quan cùng với các ví dụ dễ hiểu.

    Công nghệ đến rồi công nghệ đi, nhưng cái nhìn sâu sắc là ở lại trong ta mãi mãi!

    Danh mục nội dung

    Tại sao lại cần Docker?

    Trước khi đi vào các khái niệm cụ thể, tôi muốn đưa bạn qua một ví dụ để bạn có thể hình dung ra Docker hữu ích như thế nào. Giả sử như bạn đang xây dựng một hệ thống end-to-end với tech stack bao gồm: web server sử dụng NodeJs, database sử dụng MongoDB, messaging system sử dụng Redis, và một orchestration tool.

    Cách tiếp cận truyền thống

    Với các cách tiếp cận truyền thống (mà không sử dụng Docker), chúng ta sẽ gặp phải nhiều vấn đề với tech stack nói trên – chúng là các components/services khác nhau trong hệ thống cần xây dựng.

    • Đầu tiên là khả năng tương thích (compatibility) với hệ điều hành nền tảng (underlying os), chúng ta phải đảm bảo rằng tất cả các services khác nhau nói trên tương thích với OS mà chúng ta đang sử dụng. Trong trường hợp tồn tại một service trong tech stack đó có version mà chúng ta định sử dụng không tương thích với OS, thì chúng ta lại phải tìm kiếm OS khác tương thích với tất cả các services để phù hợp với nhu cầu của hệ thống ta muốn xây dựng.

    • Thứ 2 là chúng ta phải kiểm tra khả năng tương thích giữa các services khác nhau này với các libraries và các dependencies trên OS. Sẽ có vấn đề nếu như một service yêu cầu một phiên bản của dependent library, trong khi đó một service khác lại yêu cầu một phiên bản khác của dependent library đó.

    Kiến trúc của hệ thống sẽ thay đổi qua thời gian, chúng ta sẽ phải upgrade lên các phiên bản mới hơn của các thành phần này. Và mỗi lần có một thứ gì đó cần thay đổi, chúng ta lại phải kiểm tra khả năng tương thích của nó với underlying infrastructure (OS, libraries, dependencies,…). Hơn nữa, mỗi khi có một developer mới onboard, chúng ta sẽ gặp khó khăn khi set up môi trường làm việc cho developer đó.

    The Matrix from Hell !!

    Tất cả những vấn đề nói trên dẫn đến việc developing, building và shipping hệ thống gặp nhiều khó khăn.

    Cách tiệp cận sử dụng Docker

    Như vậy, chúng ta cần một cái gì đó có thể giúp chúng ta giải quyết vấn đề về tính tương thích giữa các thành phần này với OS, chúng ta cũng cần một thứ gì đó có thể giúp chúng ta sửa đổi hoặc thay đổi các thành phần này mà không ảnh hưởng đến các thành phần khác trong hệ thống. Docker đã giải quyết tốt cho chúng ta.

    The services with containers

    Với Docker, ta có thể chạy mỗi component trong một container riêng biệt với các dependencies và các libraries của riêng nó, tất cả trên một VM (Virtual machine) và một OS nhưng tách biệt môi trường. Chúng ta chỉ phải build cấu hình Docker một lần và các developer có thể bắt đầu với một lệnh docker run đơn giản, không phân biệt underlying operating system mà chúng ta đang chạy. Tất cả những cái chúng ta cần là có Docker đã được cài đặt.

    Containers vs Virtual Machines

    Cả Containers và Virtual Machines (VMs) đều giống nhau ở mục tiêu, đó là: cô lập môt ứng dụng và các dependencies của nó thành một đơn vị khép kín (self-contained unit) mà có thể chạy ở bất cứ đâu, bất cứ môi trường nào.

    Hơn nữa, các Containers và VMs loại bỏ nhu cầu về phần cứng vật lý, cho phép sử dụng hiệu quả hơn các tài nguyên máy tính, cả về tiêu thụ năng lượng và hiệu quả chi phí.

    Sự khác biệt chính giữa Containers và VMs là ở cách tiếp cận kiến trúc của chúng.

    Virtual machines

    VMs về cơ bản là một sự mô phỏng của một máy tính thực, thực thi các chương trình giống như một máy tính thực.

    VMs chạy trên một máy vật lý sử dụng cái gọi là hypervisor. Một hypervisor chạy trên một host machine hoặc trên một bare-metal.

    • Một hypervisor là một phần của software, firmware hoặc hardware mà VMs chạy trên đó. Bản thân các hypervisors chạy trên một máy tính vật lý, được gọi là host machine. Host machine cung cấp các tài nguyên cho VMs bao gồm RAM và CPU. Các tài nguyên này được phân chia giữa các VMs và có thể được phân phối khi bạn cảm thấy phù hợp. Vì vậy, nếu một VM đang chạy một ứng dụng cần nhiều tài nguyên hơn thì bạn có thể phân bổ nhiều tài nguyên hơn cho VM đó so với các VM khác đang chạy trên cùng một host machine.

    • VM đang chạy trên một host machine thường được gọi là guest machine. Guest machine này chứa ứng dụng và cả những thứ khác nó cần để chạy ứng dụng đó. Nó chiếm hữu toàn bộ phần cứng được ảo hóa của riêng nó, bao gồm virtualized network adapters, storage, và CPU,… và nó cũng có một guest operating system của riêng nó. Nhìn từ bên trong, guest machine hoạt động riêng biệt với các tài nguyên chuyên dụng dành cho nó. Nhìn từ bên ngoài, nó là một máy ảo – chia sẻ tài nguyên được cung cấp bởi host machine.

    Như đã đề cập ở trên, một guest machine có thể chạy trên một hosted hypervisor hoặc trên một bare-metal hypervisor. Có một vài khác biệt quan trọng giữa chúng:

    • Đầu tiên, một hosted hypervisor chạy trên OS của một host machine. Lấy ví dụ, một máy tính đang chạy OSX có thể có một VM được cài đặt trên OS đó. VM không có quyền truy cập trực tiếp vào hardware, nó phải thông qua OS của host machine. Lợi ích của hosted hypervisor đó là underlying hardware đóng vai trò ít quan trọng. OS của máy chủ chịu trách nhiệm về các hardware drivers thay vì chính hypervisor, và do đó có khả năng tương thích phần cứng tốt. Mặc khác, tầng trung gian này (OS của máy chủ) giữa hardware và hypervisor tạo ra nhiều tài nguyên hơn, làm giảm performance của VM.

    • Một bare-metal hypervisor giải quyết vấn đề hiệu năng nói trên bằng cách cài đặt và chạy ngay trên hardware của host machine. Vì nó giao tiếp trực tiếp với phần cứng nên nó không cần OS của máy chủ để chạy. Trong trường hợp này, thứ đầu tiên được cài đặt trên máy chủ đó là hypervisor. Không giống như hosted hypervisor, một bare-metal hypervisor có device drivers của riêng nó và tương tác trực tiếp với từng thành phần cho bất kỳ tác vụ cụ thể nào. Điều này dẫn đến performance, scalability, và stability tốt hơn. Sự đánh đổi ở đây là khả năng tương thích phần cứng bị hạn chế bởi vì hypervisor chỉ có thể có rất nhiều device drivers được tích hợp trong đó.

    Sau tất cả những gì đã nói về hypervisor, bạn có thể sẽ hỏi rằng tại sao chúng ta lại cần thêm một layer "hypervisor" giữa VM và host machine ? Câu trả lời đó là vì VM có một virtual OS của riêng nó, hypervisor đóng vai trò thiết yếu trong việc cung cấp cho VMs một platform để quản lý để thực thi hệ điều hành khách này. Nó cho phép các host computers chia sẻ tài nguyên của chúng tới các VMs đang chạy với tư cách là guest trên chúng.

    Virtual machines

    Như bạn có thể thấy trên diagram, hypervisor đóng gói virtual hardware, kernel và user space cho mỗi VM mới.

    Containers

    Containers có một lịch sử lâu đời trong lĩnh vực điện toán. Không giống như hypervisor virtualization, nơi mà có một hoặc nhiều VMs độc lập chạy ảo trên physical hardware qua một layer trung gian; thay vào đó, containers chạy trong user space ở trên kernel của OS. Do đó, container virtualization thường được gọi là ảo hóa cấp OS. Công nghệ container cho phép nhiều phiên bản user space độc lập được chạy trên một máy chủ duy nhất.

    Do trạng thái của chúng là guest của OS, nên các containers đôi khi được xem là kém linh hoạt hơn: chúng thường chỉ có thể chạy cùng hệ điều hành hoặc hệ điều hành khách tương tự trên máy chủ. Lấy ví dụ: bạn có thể chạy Redhat Enterprise Linux trên một máy chủ Ubuntu, nhưng bạn không thể chạy Microsoft Windows trên máy chủ Ubuntu. Containers cũng được coi là kém an toàn hơn so với sự cô lập hoàn toàn của hypervisor virtualization.

    Bất chấp những hạn chế này, các containers đã được triển khai dưới nhiều user cases khác nhau. Chúng phổ biến cho việc triển khai hyperscale của các dịch vụ multi-tenant, cho lightweight sandboxing,… bất chấp những lo ngại về bảo mật của chúng.

    Các công nghệ container gần đây bao gồm OpenVZ, Solaris Zones và Linux containers như lxc. Sử dụng các công nghệ mới này, containers giờ đây có thể được xem như là một máy chủ hoàn chỉnh theo đúng nghĩa của chúng thay vì chỉ là môi trường thực thi. Trong trường hợp của Docker, vì có các features hiện đại của Linux kernel, như là control group và namespaces –> các containers có sự độc lập mạnh mẽ, network và storage stacks của riêng chúng, cũng như khả năng quản lý tài nguyên để cho phép sự tồn tại thân thiện của nhiều containers trên cùng một máy chủ.

    Mặc dù các containers trước đây đã không đạt được large-scale adoption. Một phần lớn của vấn đề này có thể nằm ở độ phức tạp của chúng: các containers có thể phức tạp, khó để set up, khó để quản lý và tự động hóa. Docker nhằm mục đích thay đổi điều đó.

    Containers

    Tóm lại, một khác biệt lớn giữa containers và VMs đó là các containers share kernel của máy chủ với các containers khác.

    Containers vs VMs

    Dưới đây là một sự so sánh những điểm khác biệt chính giữa VMs và Containers.

    Containers vs VMs

    Ở bên phải hình trên, trong trường hợp của Docker, ta có underlying hardware infrastructure, OS ở phía trên và Docker được cài đặt trên OS, Docker sau đó quản lý các containers – chúng hoạt động cùng với các libraries và dependencies.

    Trong trường hợp của VMs, ở phía bên trái, ta có Hypervisor ở trên hardware và sau đó là VMs ở trên chúng. Và như bạn nhìn thấy, mỗi VMs có OS riêng bên trong nó, sau đó là các libs và deps rồi đến Application –> việc sử dụng các tài nguyên phần cứng trở nên lớn hơn khi có nhiều virtual operating systems đang chạy. VMs cũng tiêu thụ không gian đĩa lớn hơn vì mỗi VM khá nặng – thường lên đến hàng GB, trong khi đó docker containers nhẹ hơn – thường chỉ đến hàng MB –> điều này cho phép Docker container khởi động nhanh hơn – thường chỉ trong vài giây, trong khi đó các VMs sẽ mất khoảng vài phút để khởi động vì nó cần khởi động toàn bộ cả Operating System.

    Một điều quan trọng cần lưu ý là Docker có ít sự cô lập (isolation) hơn vì có nhiều tài nguyên được chia sẻ giữa các containers, như Kernel. Trong khi đó, VMs có sự cô lập hoàn toàn với nhau vì chúng không dựa trên underlying os hay kernel.

    Mặc dù có sự khác biệt nhất định giữa Container và VM, nhưng sự kết hợp giữa chúng có thể mang lại sự hữu ích nếu biết cách phối hợp chúng hợp lý.

    Containers and VMs

    Khi bạn có môi trường lớn với hàng ngàn containers chạy trên hàng ngàn docker host, bạn sẽ thường thấy các containers được cung cấp trên các virtual docker host. Bằng cách này, chúng ta có thể tận dụng được ưu điểm của cả 2 công nghệ, chúng ta có thể sử dụng virtualization để dễ dàng kiểm soát các docker host theo nhu cầu, đồng thời tận dụng Docker để dễ dàng kiểm soát các ứng dụng và scale chúng theo nhu cầu.

    Giới thiệu về Docker

    Đến đây thì chắc hẳn nhiều bạn đọc đặt câu hỏi, vậy tóm lại Docker là gì? Tôi sẽ trả lời câu hỏi này ngay sau đây.

    Docker là một open-source engine, tự động hóa việc triển khai các ứng dụng vào các containers. Nó được viết bởi một team tại Docker, Inc và được họ phát hành theo giấy phép Apache 2.0.

    Vậy Docker có gì đặc biệt? Docker thêm một công cụ triển khai ứng dụng trên môi trường thực thi container đươc ảo hóa. Nó được thiết kế để cung cấp môi trường nhẹ và nhanh chóng để chạy code của bạn, cũng như workflow hiệu quả để đưa code từ laptop –> môi trường test –> môi trường production.

    Docker cực kỳ đơn giản. Thật vậy, bạn có thể bắt đầu với Docker trên một máy chủ minimal không chạy gì ngoài một Linux kernel tương thích và một Docker binary. Nhiệm vụ của Docker là cung cấp:

    Một cách dễ dàng và nhẹ nhàng để mô hình hóa thực tế:

    Docker rất nhanh, bạn có thể Dockerize ứng dụng của mình trong vài phút. Docker dựa trên mô hình copy-on-write nên việc thực hiện các thay đổi đối với ứng dụng của bạn cũng cực kỳ nhanh chóng.

    Sự phân chia logic giữa các tác vụ:

    Với Docker, các Developers quan tâm về các ứng dụng của họ chạy trong các containers và các Operations quan tâm đến việc quản lý các containers. Docker được thiết kế để tăng cường tính nhất quán bằng cách đảm bảo môi trường mà các developers viết code khớp với môi trường mà các ứng dụng được triển khai thực tế. Điều này làm giảm rủi ro: "worked in dev, now an ops problem".

    Vòng đời phát triển nhanh và hiệu quả:

    Docker nhằm mục đích giảm thời gian trong chu kỳ giữa code được viết, code được kiểm tra, code được triển khai và được sử dụng. Nó cũng làm cho các ứng dụng của bạn trở nên khả chuyển, dễ để build, và dễ cộng tác.

    Khuyến khích kiến trúc hướng dịch vụ (SOA):

    Docker cũng khuyến khích các kiến trúc service-oriented và microservices. Docker recommends rằng mỗi container nên chạy một process hoặc một application duy nhất. Điều này thúc đẩy mô hình ứng dụng phân tán, trong đó một ứng dụng hoặc dịch vụ được đại diện bởi một loạt các containers được kết nối với nhau. Điều này giúp dễ dàng distribute, scale, debug và introspect các ứng dụng.

    Các khái niệm cơ bản

    Tôi sẽ không nhắc lại khái niệm về VMs và Containers nữa; mà thay vào đó, tôi sẽ đề cập đến 3 khái niệm quan trọng khác mà bạn sẽ gặp thường xuyên khi làm việc với Docker.

    Docker image:

    Docker image giống như các blueprints, chúng là cá immutable master image được sử dụng để tạo ra các containers hoàn toàn giống nhau.

    Một docker image chứa Dockerfile, các libraries, và mã nguồn ứng dụng bạn cần chạy, tất cả chúng được bundled lại với nhau.

    Dockerfile:

    Dockerfile là một tệp chứa các lệnh chỉ dẫn cách Docker nên build image của bạn.

    Dockerfile đề cập đến một base image, đươc sử dụng để xây dựng initial image layer. Các base images phổ biến như python, ubuntu, redis…

    Các layers bổ sung sau đó có thể được xếp chồng lên các base image layers, theo các lệnh chỉ dẫn trong Dockerfile. Ví dụ, một Dockerfile cho một ứng dụng học máy có thể yêu cầu Docker thêm Numpy, Pandas, và Scikit-learn trong một layer trung gian.

    Cuối cùng, một thin layer có thể được xếp chồng lên trên các layers khác theo Dockerfile code.

    Container Registry:

    Nếu bạn muốn người khác có thể tạo các containers từ image của bạn tạo ra, bạn cần gửi image đó tới một container registry. Docker hub là registry lớn nhất và là mặc định.

    Một phép ẩn dụ

    Để khép lại phần 1, tôi đưa ra một phép ẩn dụ để minh họa các khái niệm vừa nói ở trên, bằng cách sử dụng hoạt động Nấu ăn, cụ thể là việc làm một chiếc bánh Pizza.

    Khi nấu một món ăn, ta cần có công thức cho món ăn đó, công thức giống như một Dockerfile. Nó cho bạn biết cần phải làm gì để đạt được mục tiêu. Các thành phần của món ăn giống như các layersa, bạn đã có vỏ bánh, nước sốt và pho-mát cho chiếc bánh pizza này.

    Hãy nghĩ về công thức và các thành phần được kết hợp lại thành một công cụ làm bánh pizza. Nó giống như Docker image.

    Công thức (Dockerfile) cho chúng ta biết những gì chúng ta sẽ làm. Dưới đây là kế hoạch:

    • Lớp vỏ được định dạng sẵn và immutable. Nó giống như một basic ubuntu parent image. Đây là bottom layer và được xây dựng đầu tiên.

    • Sau đó bạn sẽ thêm một ít pho mát. Thêm second layer này vào bánh pizza giống như cài đặt thêm một thư viện bên ngoài – ví dụ Numpy.

    • Sau đó bạn rắc thêm một ít húng quế. Nó giống như mã trong một tệp bạn viết để chạy ứng dụng.

    Được rồi, chúng ta hãy bắt đầu nấu ăn:

    • Lò nướng bánh pizza giống như Docker platform. Bạn đã lắp đặt lò nướng vào nhà khi chuyển đến để có thể chế biến mọi thứ với nó. Tương tự như vậy, bạn đã cài đặt Docker vào máy tính của mình để có thể "nấu" các containers.

    • Bạn khởi động lò nướng bằng cách xoay núm. Lệnh Docker run image_name giống như núm của bạn – nó tạo và khởi động container của bạn.

    • Bánh pizza đã chín giống như một Docker container đang chạy.

    • Ăn pizza giống như việc sử dụng ứng dụng.

    Giống như làm bánh pizza, tạo một ứng dụng trong một Docker container mất một số công việc, nhưng cuối cùng bạn đã có một thứ tuyệt vời!

    Lời kết: Bài viết đến đây cũng khá dài. Trong Phần 2, tôi sẽ đi sâu vào kiến trúc, các thành phần của Docker, và không phải chờ đợi lâu, ngay trong phần 2 tôi cũng sẽ giúp bạn đọc bắt đầu viết các lệnh đầu tiên với Docker.

    Tài liệu tham khảo

    [1]: James Turnbull, The Docker Book (2018)

    [2]: Preethi Kasireddy, A Beginner-Friendly Introduction to Containers, VMs and Docker (2016)

    [3]: Jeff Hale, Learn Enough Docker to be Useful (2019)

    [4]: Mumshad Mannambeth, Docker for the Absolute Beginner – Hands On – DevOps, Section 1 – Docker overview.

    Author

    Hà Hữu Linh

    [email protected]

  • 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.