Xây dựng CI/CD dùng AWS bằng CodePipeline, ECS, Fargate, CodeBuild, CodeDeploy, Load Balancing sử dụng Github (Phần 1)

09 tháng 04, 2023 - 2529 lượt xem

CI/CD là viết tắt của Continuous Integration/Continuous Delivery hoặc Continuous Deployment. Nó là một phương pháp tự động hóa quy trình phát triển phần mềm, giúp đảm bảo rằng mã nguồn được kiểm tra, xây dựng và triển khai một cách liên tục. Trong bài viết này, chúng ta sẽ tìm hiểu về cách xây dựng CI/CD tự động bằng AWS CodePipeline, ECS, Fargate, CodeBuild, CodeDeploy và Github.

picture1

Sơ lược về luồng hoạt động của mô hình này :

Đầu tiên khi developer push code lên repository trên GitCommit (1) (trong bài thực hành này mình sẽ dùng Github) -> CodeBuild sẽ tạo một bản build mới nhất (Image) (2) -> Push Image mới nhất sang Elastic Container Registry (ECR) để lưu lại (3) -> CodeDeploy sẽ trigger để build Image Container chạy trên ECS (4). Ở đây, mình sử dụng thêm Load Balancing để nhận lượng request từ client gửi đến, và phân tải điều ra các Task của Service trong ECS.


Giới thiệu sơ lược về các dịch vụ AWS được sử dụng trong bài thực hành

1. AWS CodePipeline
AWS CodePipeline là một dịch vụ quản lý quy trình phát triển liên tục (CD). Nó cho phép bạn tự động hóa quy trình phát triển và triển khai của mình, từ khi bạn tạo mã nguồn đến khi ứng dụng của bạn được triển khai trên môi trường sản xuất.

2. AWS Elastic Container Service (ECS)
AWS Elastic Container Service (ECS) là một dịch vụ quản lý Docker container. Nó cho phép bạn dễ dàng triển khai và quản lý các ứng dụng của mình bằng cách sử dụng các container Docker trên AWS.

3. AWS Fargate
AWS Fargate là một dịch vụ quản lý container trên AWS. Nó cho phép bạn triển khai các container mà không cần quản lý các máy chủ hoặc nhóm máy chủ.

4. AWS CodeBuild
AWS CodeBuild là một dịch vụ xây dựng kiểm tra mã nguồn tự động. Nó cho phép bạn xây dựng, kiểm tra và đóng gói ứng dụng của mình trong các môi trường xây dựng khác nhau.

5. AWS CodeDeploy
AWS CodeDeploy là một dịch vụ triển khai tự động. Nó cho phép bạn triển khai các ứng dụng của mình trên các máy chủ Amazon EC2, các dịch vụ như AWS Elastic Beanstalk, hoặc các container trên Amazon ECS hoặc AWS Fargate.

6. GitHub
Github là một nền tảng quản lý mã nguồn. Nó cung cấp một số công cụ cho phép bạn quản lý mã nguồn của mình và làm việc cùng với các nhà phát triển khác trên các dự án.

7. Application Load Balancer
Application Load Balancer (ALB) là một loại load balancer được cung cấp bởi Amazon Web Services (AWS). Nó cho phép phân phối tải trên các EC2 instances hoặc các microservices trong một service hoặc một group của các service trên AWS ECS hoặc Kubernetes. Nó là một giải pháp tốt để quản lý các ứng dụng web phức tạp và đáp ứng nhanh với các yêu cầu tải trọng cao.

8. Elastic Container Registry
Đây là một dịch vụ của Amazon Web Services (AWS) được sử dụng để lưu trữ, quản lý và triển khai các Docker container images. ECR là một phần của AWS Container Services và cung cấp tính năng tương tự như các dịch vụ tương tự như Docker Hub, Google Container Registry hoặc quản lý container images trên các môi trường cloud khác.


Các bước xây dựng CI/CD tự động bằng AWS

1. Tạo một Application Load Balancer trên AWS

  1. Đăng nhập vào tài khoản AWS của bạn.
  2. Vào phần “EC2 Dashboard”.
  3. Chọn “Load Balancers” từ menu bên trái.
  4. Chọn “Create Load Balancer” và chọn loại Load Balancer bạn muốn tạo, trong trường hợp này là Application Load Balancer.
  5. Bước tiếp theo là cấu hình Load Balancer. Bạn sẽ cần chỉ định tên cho Load Balancer,chọn các Availability Zones
    để triển khai Load Balancer (khuyến nghị nên chọn ít nhất 2 AZs để tăng tính High Avibility của ứng dụng mình).
  6. Sau đó, bạn sẽ cần cấu hình Target Group cho Load Balancer. Các yêu cầu truy cập sử dụng port 8080 sẽ được chuyển tiếp đến lớpTarget Group dựa trên các điều kiện nhất định. ( ở đây mình sẽ tạo một Target Group sử dụng port 8080 cho ứng dụng NodeJS)
    picture7
  7. Cuối cùng, bạn sẽ cần xác nhận các cấu hình của bạn và tạo Load Balancer. Ở đây mình đi nhanh qua, vì nó không phải phần chính mình tập trung vào, các bạn có thể cấu hình nâng cao thêm cho ALB của mình nhé.
    picture2

2. Source code dùng để thực hành

Ở đây mình đã tạo một project source code Nodejs, sử dụng framework Express chạy node version: 18.15.0, có một file index.js trả về thông tin json, mình chủ yếu sẽ tương tác thay đổi trên file này. Ứng dụng mình chạy cổng 8080 nhé. (sẽ mapping với Target Group khi tạo Application Load Balancer ở trên). Các bạn có thể clone project của mình tại đây

picture1

File Dockerfile dùng để định nghĩa các bước build một images.

image1

File buildspec.yml này sẽ bao gồm các phần sau:

  • Phần install: Cài đặt các phần mềm và công cụ cần thiết cho quá trình xây dựng.
  • Phần pre_build: Thiết lập các biến môi trường và kết nối đến AWS ECR để đăng nhập và lấy ảnh Docker.
  • Phần build: Xây dựng ứng dụng của chúng ta và lưu trữ ảnh Docker được tạo trong ECR.
  • Phần post_build: Đăng ký và triển khai ứng dụng của chúng ta.
version: 0.2
phases:
  pre_build:
    commands:
      - echo "Logging in to Amazon ECR..."
      - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
  build:
    commands:
      - echo Build started on `date`
      - echo Building the Docker image...
      - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
      - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG    
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker image...
      - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
      - printf '[{"name":"%s","imageUri":"%s"}]' $CONTAINER_NAME $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imagedefinition.json
      - cat imagedefinition.json
artifacts:
  files: imagedefinition.json

3. Tạo một Elastic Container Registry

  1. Đăng nhập vào console của AWS.
  2. Chọn dịch vụ ECR từ danh sách các dịch vụ AWS.
  3. Nhấp vào nút Create repository để tạo một repository mới.
  4. Đặt tên cho repository.
  5. Chọn thư mục để lưu trữ image của bạn: public hoặc private.
  6. Nếu bạn chọn private, hãy xác định các đối tượng IAM cho phép truy cập vào repository.
  7. Ở đây mình dùng private, nhấp vào nút Create repository để tạo repository.

picture5
picture3

4. Tạo một CodeBuild

  1. Đăng nhập vào console của AWS.
  2. Chọn dịch vụ CodeBuild từ danh sách các dịch vụ AWS.
  3. Nhấp vào nút Create project để tạo một project mới.
  4. Đặt tên cho project.
  5. Cấu hình thông tin về nguồn dữ liệu của project, bao gồm thông tin về kho lưu trữ mã nguồn và phiên bản mã nguồn để sử dụng.
    picture6
  6. Cấu hình thông tin về môi trường build, bao gồm hệ điều hành, kiến trúc, Docker image và các biến môi trường. Ở phần Source, các bạn chọn Source provider là Github. AWS sẽ yêu cầu bạn xác thực, bạn chỉ cần đăng nhập tài khoản Github của mình là được. Khá đơn giản. Do mình đăng nhập từ trước, nên không cần đăng nhập lại. Ở mục GitHub repository, các bạn chọn repo mà các bạn muốn deploy ( hoặc nếu chưa có các bạn có thể clone project của mình về tại đây).
    picture7
  7. Tiếp theo phần Primary source webhook events, các bạn chọn vào mục Webhook và Build type là Single build. Event type chọn PUSH. Nghĩa là khi mình thay đổi source code và push code, thì một trigger sẽ được bắn ra và báo cho CodeBuild, CodeBuild sẽ tự động build lại và cập nhật những thay đổi mới.
    picture7
  8. Ở mục Enviroment, các bạn chọn Managed image, Operating system là Amazon Linux 2, Runtime là Standard, Image là amazonlinux-86_64-standard:4.0 ( dành cho build image trên môi trường Linux). Và quan trọng là phải chọn Privileged. Service role thì các bạn chọn New service role nếu chưa có.
  9. Ở mục Buildspec, các bạn chọn Use a buildspec file. AWS mặc định sẽ tìm đúng với tên file buildspec.yml trong source code root directory của bạn để chạy. Trường hợp các bạn đặt tên file khác hoặc đặt file trong thư mục con khác thì phải điền Buildspec name - optional nhé.
    picture9
  10. Ở mục Artifacts, phần Logs các bạn tạo một folder dùng để logs lại các thông tin trong quá trình build code nhé. Sau đó nhấn nút Create build project
    picture1
  11. Sau khi tạo xong, các bạn có thể thấy project CodeBuild vừa tạo. Các bạn cần
    picture
  12. Để tăng tính chuyên nghiệp, và tốc độ build code, các bạn nên cấu hình thêm các biến môi trường trong quá trình build code; chọn vào Edit -> Enviroment
  13. Tiếp theo, các bạn nhấn vào Additional configuration
    picture2
  14. Các bạn cấu hình tên các biến môi trường trong file buildspec.yml đã khai báo trước đó nhé. Phần compute các bạn có thể thay đổi, memory càng lớn thì tốc độ build code càng nhanh nhưng đồng nghĩa giá càng cao đấy nhé. Sau cùng là nhấn nút Update enviroment
    picture2
  15. Lưu ý, để CodeBuild có thể truy cập và lấy images mới nhất từ Elastic Container Registry, bạn phải gắn thêm quyền policy cho CodeBuild nhé. Ở đây, mình demo chọn quyền AmazonEC2ContainerRegistryFullAccess cho dễ, trên thực tế các bạn nên giới hạn quyền lại cho phù hợp nhé.
    pcitrue3

5. Tạo Elastic Container Service để chạy ứng dụng NodeJS

Bước 1: Tạo Cluster

  • Chọn dịch vụ Amazon ECS
  • Trên trang quản lý Amazon ECS, chọn tạo mới một cluster
  • Chọn loại cluster (ví dụ: Mình sẽ để mặc định Infrastructure là AWS Fargate nhé + Networking các bạn chọn VPC của mình, subnet các bạn đặt trong subnet public nhé.
  • Chú ý, nếu đặt trong subnet private thì các bạn phải cấu hình thêm NAT Gateway bên trong route table của nhóm subnet để cho phép các service download các package trong file Dockerfile về nhé.

picture2

  • Sau đó nhấp vào nút “Create”

Bước 2: Tạo Task Definition

  • Trong trang quản lý Amazon ECS, chọn tạo mới một Task Definition
  • Đặt tên cho Task Definition .
  • Điền thông tin cho Container. Chú ý, Name container phải giống với tên $CONTAINER_NAME mà bạn đã đặt ở phần cấu hình Enviroment trên CodeBuild nhé. Ở trên mình đặt là simple-app nên tên Container mình là simple-app. Nếu không mapping sẽ không chạy được đâu nhé.
  • Tiếp theo, Image URI các bạn copy URI repo bên dịch vụ Elastic Container Registry đã tạo ở trước đó vào nhé. Nhớ thêm tag là lastest (ví dụ: 012345789.dkr.ecr.ap-southeast-1.amazonaws.com/demo-codebuild:latest). Mặc định CodeBuild sẽ lấy images có tags là latest mới nhất để chạy nhé.
  • Tiếp theo nhấn nút “Next”

picture1

  • Ở phần Configure environment, storage, monitoring, and tags: Chọn môi trường làAWS Fargate, hệ điều hành Linux/X86_64. Task size ở đây mình để minimum để tiếp kiệm chi phí nhé. Ở phần Task execution role các bạn chọn Create new role nếu chưa có nhé, mình có tạo trước đó rồi nên sử dụng lại.
  • Bước cuối cùng là các bạn nhấn Next, xem lại các thông tin cấu hình và nhấn Create nhé.

Bước 3: Tạo Service

  • Chọn cluster đã tạo trong Bước 1
  • Chọn Create Service

picture2

  • Mục Enviroment, các bạn chọn Lauch type là FARGATE nhé. (các bạn có thể sử dụng EC2 Instance cũng được, nhưng cần phải cài nhiều config trên EC2 để chạy dịch vụ, trong bài demo này mình dùng Fargate để đơn giản hóa hạ tầng)
  • Mục Deployment configuration, các bạn chọn là Service, Family thì các bạn chọn tên Task Definition đã khởi tạo ở bước 1 nhé. Service name thì các bạn đặt tên tùy ý cho dịch vụ của mình. Desired tasks là số task mà các bạn muốn dịch vụ của mình chạy, ở đây mình để là 1 task nhé.

picture1

  • Mục Networking, các bạn chọn VPC của mình, Sunet thì các bạn chọn Subnet Public nhé. Security group thì các bạn chọn security group của các bạn nếu đã tồn tại, hoặc tạo mới nếu chưa có. Nhớ mở port 8080 chạy NodeJS cho dịch vụ của mình nhé.
  • Ở đây, không cần bật Public IP vì sẽ truy xuất thông qua Application Load Balancer đã tạo trước đó.

picture2

  • Ở mục Load balancing, các bạn chọn loại Application, và chọn Application balancing trước đó các bạn đã tạo nhé. Port là 8080, Target group đã tạo trước đó.Health check mình để 15s cho nhanh nhé. Sau đó nhấn nút Create.

Note: Ở đây chúng ta có thể thiết lập cấu hình nâng cao như tự động mở rộng, giao tiếp giữa nhiều Service trong hệ thống như thế nào ( Auto Scale, Service Discovery…). Đây là chủ đề Advance rất thú vị, luôn được sử dụng nhiều trong dự án thực tế, có thời gian mình sẽ chia sẻ tiếp ở một bài khác nhé.

picture1

  • Sau khi đợi Service chạy xong, các bạn có thể thấy task của mình đã được tạo ra,Container tên là simple-app
    và một số thông tin cấu hình cơ bản bên dưới:

picture2

  • Thử truy cập trên web nhé, các bạn quay lại dịch vụ EC2, chọn Load Balancers, sau đó copy DNS name và dán vào Browers nhé, lưu ý nhớ thêm port 8080 nhé.

picture2

  • Như vậy là chúng ta đã delop thành công website NodeJS của mình lên ECS rồi.

picture

  • Để kiểm tra CodeBuild chúng ta đã hoạt động tốt không, các bạn thử thay đổi source code rồi commit và push lên lại nhé.
  • Ở đây mình sẽ sửa nội dung là Version 3 và commit và push lên lại. CodeBuild sẽ tự động build lại những thay đổi đó. Và lưu images mới nhất vào ECR.

picture2
picture3
picture3


  • Bài viết đến đây cũng khá dài rồi, hẹn các bạn tiếp ở phần 2.
  • Trong phần 2, mình sẽ hướng dẫn các bạn sử dụng CodePipeline để tự động hóa khi có sự thay đổi source code dưới local (ví dụ như team DEV hoàn thành tính năng mới và muốn releases), thì website chúng ta sẽ tự động cập nhật những thay đổi đó như thế nào.
  • Chúc các bạn thành công!

>> Phần 2

Bình luận

avatar
Trịnh Minh Cường 2023-04-10 07:57:20.504537 +0000 UTC

Một bài siêu dài, và nhiều thông tin. Cảm ơn tác giả

Huỳnh Nhật Minh
Huỳnh Nhật Minh 2023-04-10 14:57:27.117159 +0000 UTC

Cảm ơn thầy ạ

Avatar
avatar
Quang Nguyễn Văn 2023-04-10 09:59:01.761073 +0000 UTC

Xịn xò quá

Huỳnh Nhật Minh
Huỳnh Nhật Minh 2023-04-10 14:57:57.867057 +0000 UTC

Cảm ơn thầy ạ, em còn nghiệp dư lắm ạ 

Avatar
* Vui lòng trước khi bình luận.
Ảnh đại diện
  +5 Thích
+5