0

🚀 Chapter 3 — Scale: Phần B — Reusable Workflow

Chapter 3A, chúng ta đã triển khai Google Online Boutique với nhiều microservices và tạo một CI/CD pipeline riêng cho từng service.

Kết quả hiện tại:

GitHub
   │
   ├── frontend
   │      ↓
   │   frontend-ci-cd.yml
   │
   ├── cartservice
   │      ↓
   │   cartservice-ci-cd.yml
   │
   ├── productcatalogservice
   │      ↓
   │   productcatalog-ci-cd.yml
   │
   └── checkoutservice
          ↓
      checkoutservice-ci-cd.yml

Các workflow đều có logic gần giống nhau:

Checkout
   ↓
Docker Build
   ↓
SSH EC2
   ↓
Docker Compose Build
   ↓
Docker Compose Up

Điều này tạo ra vấn đề:

4 services
    ↓
4 workflows
    ↓
Copy / Paste
    ↓
Pipeline Drift

Nếu Online Boutique có:

4 services
   ↓
10 services
   ↓
30 services
   ↓
50 services

thì việc duy trì workflow sẽ ngày càng khó.

Trong Chapter 3B, chúng ta sẽ giải quyết vấn đề này bằng GitHub Actions Reusable Workflow.


1. Mục tiêu

Từ:

Service A → Pipeline A
Service B → Pipeline B
Service C → Pipeline C
Service D → Pipeline D

chuyển thành:

Service A ──┐
Service B ──┤
Service C ──┼──→ Reusable Workflow
Service D ──┘
                    ↓
               CI/CD logic
                    ↓
                   EC2

Sau Chapter 3B:

.github/workflows/

├── reusable-ci-cd.yml        ← Logic CI/CD dùng chung
│
├── frontend.yml              ← Gọi reusable workflow
├── cartservice.yml           ← Gọi reusable workflow
├── productcatalogservice.yml ← Gọi reusable workflow
└── checkoutservice.yml       ← Gọi reusable workflow

Điểm quan trọng:

Service workflow chỉ khai báo service nào cần deploykhi nào chạy. Logic CI/CD được đặt tập trung trong reusable-ci-cd.yml.


2. Kiểm tra trạng thái từ Chapter 3A

Trên máy local:

cd online-boutique-cicd

Kiểm tra:

git status

Kiểm tra workflow:

ls .github/workflows

Bạn hiện sẽ có:

frontend-ci-cd.yml
cartservice-ci-cd.yml
productcatalog-ci-cd.yml
checkoutservice-ci-cd.yml

Đây chính là trạng thái cuối của Chapter 3A.


3. Kiểm tra Online Boutique trên EC2

SSH vào EC2:

ssh -i ./chapter3-key.pem ubuntu@<EC2_PUBLIC_IP>

Đi tới project:

cd ~/online-boutique

Kiểm tra:

docker compose ps

Các container cần thiết phải đang chạy.

Kiểm tra frontend:

docker ps | grep frontend

Sau đó mở:

http://<EC2_PUBLIC_IP>

Nếu Online Boutique vẫn hoạt động, chúng ta có thể bắt đầu refactor CI/CD.


4. Ý tưởng của Reusable Workflow

Hiện tại frontend có:

steps:
  - checkout

  - docker build

  - ssh ec2

  - docker compose build frontend

  - docker compose up frontend

Cartservice cũng có:

steps:
  - checkout

  - docker build

  - ssh ec2

  - docker compose build cartservice

  - docker compose up cartservice

Khác nhau chủ yếu ở:

frontend
cartservice
productcatalogservice
checkoutservice

Vì vậy chúng ta biến service thành một input:

service = frontend

hoặc:

service = cartservice

Reusable workflow sẽ nhận input này và sử dụng nó.


5. Xóa 4 workflow cũ

Trên local:

rm .github/workflows/frontend-ci-cd.yml
rm .github/workflows/cartservice-ci-cd.yml
rm .github/workflows/productcatalog-ci-cd.yml
rm .github/workflows/checkoutservice-ci-cd.yml

Kiểm tra:

ls .github/workflows

Nếu thư mục trống thì đúng.


6. Tạo Reusable Workflow

Tạo file:

touch .github/workflows/reusable-ci-cd.yml

Mở file:

nano .github/workflows/reusable-ci-cd.yml

Thêm:

name: Reusable CI/CD

on:
  workflow_call:
    inputs:
      service:
        required: true
        type: string

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Build Docker image
        run: |
          docker build \
            -t online-boutique-${{ inputs.service }} \
            src/${{ inputs.service }}

      - name: Deploy to EC2
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.EC2_HOST }}
          username: ubuntu
          key: ${{ secrets.EC2_SSH_KEY }}
          script: |
            cd ~/online-boutique
            git pull origin main
            docker compose build ${{ inputs.service }}
            docker compose up -d ${{ inputs.service }}

Lưu file.


7. Hiểu cấu trúc Reusable Workflow

Phần quan trọng nhất là:

on:
  workflow_call:

Nó có nghĩa:

Workflow này
      ↓
không tự chạy trực tiếp
      ↓
workflow khác sẽ gọi nó

GitHub Actions hỗ trợ reusable workflow thông qua workflow_call.


8. Tạo input service

Trong workflow:

inputs:
  service:
    required: true
    type: string

Workflow yêu cầu caller truyền vào:

frontend

hoặc:

cartservice

hoặc:

productcatalogservice

Ví dụ:

service = frontend

thì:

src/${{ inputs.service }}

trở thành:

src/frontend

Và:

docker compose build ${{ inputs.service }}

trở thành:

docker compose build frontend

9. Tạo workflow cho Frontend

Tạo:

touch .github/workflows/frontend.yml

Mở:

nano .github/workflows/frontend.yml

Thêm:

name: Frontend CI/CD

on:
  push:
    branches:
      - main
    paths:
      - "src/frontend/**"
      - ".github/workflows/frontend.yml"

jobs:
  deploy:
    uses: ./.github/workflows/reusable-ci-cd.yml

    with:
      service: frontend

    secrets: inherit

Lưu lại.

Workflow này bây giờ rất ngắn.

Nó chỉ nói:

Nếu frontend thay đổi
        ↓
Gọi reusable workflow
        ↓
service = frontend

10. Tạo workflow cho Cartservice

Tạo:

touch .github/workflows/cartservice.yml

Mở:

nano .github/workflows/cartservice.yml

Thêm:

name: Cartservice CI/CD

on:
  push:
    branches:
      - main
    paths:
      - "src/cartservice/**"
      - ".github/workflows/cartservice.yml"

jobs:
  deploy:
    uses: ./.github/workflows/reusable-ci-cd.yml

    with:
      service: cartservice

    secrets: inherit

11. Tạo workflow cho Product Catalog

Tạo:

touch .github/workflows/productcatalogservice.yml

Mở:

nano .github/workflows/productcatalogservice.yml

Thêm:

name: Product Catalog CI/CD

on:
  push:
    branches:
      - main
    paths:
      - "src/productcatalogservice/**"
      - ".github/workflows/productcatalogservice.yml"

jobs:
  deploy:
    uses: ./.github/workflows/reusable-ci-cd.yml

    with:
      service: productcatalogservice

    secrets: inherit

12. Tạo workflow cho Checkout

Tạo:

touch .github/workflows/checkoutservice.yml

Mở:

nano .github/workflows/checkoutservice.yml

Thêm:

name: Checkoutservice CI/CD

on:
  push:
    branches:
      - main
    paths:
      - "src/checkoutservice/**"
      - ".github/workflows/checkoutservice.yml"

jobs:
  deploy:
    uses: ./.github/workflows/reusable-ci-cd.yml

    with:
      service: checkoutservice

    secrets: inherit

13. Kiểm tra cấu trúc

Chạy:

find .github/workflows -type f

Kết quả:

.github/workflows/reusable-ci-cd.yml
.github/workflows/frontend.yml
.github/workflows/cartservice.yml
.github/workflows/productcatalogservice.yml
.github/workflows/checkoutservice.yml

Bây giờ architecture đã thay đổi thành:

                     GitHub
                        │
          ┌─────────────┼─────────────┐
          ↓             ↓             ↓
      frontend         cart       productcatalog
          │             │             │
          └─────────────┼─────────────┘
                        ↓
              reusable-ci-cd.yml
                        ↓
                Build + Deploy
                        ↓
                       EC2

14. Kiểm tra Git diff

Chạy:

git diff

Bạn sẽ thấy một thay đổi rất quan trọng:

Trước

Mỗi workflow chứa:

Checkout
Docker Build
SSH
git pull
Docker Compose Build
Docker Compose Up

Sau

Chỉ reusable-ci-cd.yml chứa logic:

Checkout
Docker Build
SSH
git pull
Docker Compose Build
Docker Compose Up

Các workflow service chỉ còn:

Trigger
   ↓
service
   ↓
Reusable Workflow

15. Commit thay đổi

Chạy:

git add .github/workflows

Sau đó:

git commit -m "refactor ci cd with reusable workflow"

Push:

git push

16. Kiểm tra GitHub Actions

Vào:

GitHub
→ Repository
→ Actions

Bạn sẽ thấy các workflow:

Frontend CI/CD
Cartservice CI/CD
Product Catalog CI/CD
Checkoutservice CI/CD

Nhưng phía dưới chúng đều sử dụng:

Reusable CI/CD

17. Test Frontend

Sửa một file frontend:

echo "Chapter 3B" >> src/frontend/README.md

Commit:

git add src/frontend/README.md
git commit -m "test reusable workflow frontend"
git push

Flow:

git push
   ↓
src/frontend/**
   ↓
frontend.yml
   ↓
reusable-ci-cd.yml
   ↓
service = frontend
   ↓
Docker Build
   ↓
SSH EC2
   ↓
docker compose build frontend
   ↓
docker compose up -d frontend

18. Kiểm tra EC2

SSH:

ssh -i ./chapter3-key.pem ubuntu@<EC2_PUBLIC_IP>

Đi tới:

cd ~/online-boutique

Kiểm tra:

docker compose ps

Kiểm tra frontend:

docker ps | grep frontend

19. Test Product Catalog

Sửa:

nano src/productcatalogservice/products/products.json

Thay đổi một tên sản phẩm.

Ví dụ:

Vintage Camera

thành:

Vintage Camera - Chapter 3B

Commit:

git add .
git commit -m "test reusable workflow product catalog"
git push

Flow:

git push
   ↓
productcatalogservice/**
   ↓
productcatalogservice.yml
   ↓
reusable-ci-cd.yml
   ↓
service = productcatalogservice
   ↓
Build
   ↓
Deploy

Refresh Online Boutique.

Bạn sẽ thấy product đã thay đổi.


20. Test Cartservice

Thực hiện một thay đổi nhỏ:

nano src/cartservice/README.md

Hoặc:

echo "Chapter 3B" >> src/cartservice/README.md

Commit:

git add .
git commit -m "test reusable workflow cart"
git push

GitHub Actions sẽ gọi:

cartservice.yml
       ↓
reusable-ci-cd.yml
       ↓
service = cartservice

21. Test Checkoutservice

Tương tự:

echo "Chapter 3B" >> src/checkoutservice/README.md

Commit:

git add .
git commit -m "test reusable workflow checkout"
git push

Flow:

checkoutservice.yml
        ↓
reusable-ci-cd.yml
        ↓
service = checkoutservice
        ↓
EC2

22. Kiểm tra điểm quan trọng nhất

Bây giờ hãy mở:

.github/workflows/reusable-ci-cd.yml

Bạn sẽ thấy toàn bộ logic CI/CD tập trung ở đây.

Nếu muốn thay đổi:

Docker Build

hoặc:

SSH

hoặc:

docker compose build

hoặc:

docker compose up

chỉ cần sửa:

reusable-ci-cd.yml

Không cần sửa 4 workflow.


23. So sánh Chapter 3A và 3B

Chapter 3A

frontend
    ↓
frontend-ci-cd.yml
    ↓
Checkout
Build
Deploy
cartservice
    ↓
cartservice-ci-cd.yml
    ↓
Checkout
Build
Deploy
productcatalog
    ↓
productcatalog-ci-cd.yml
    ↓
Checkout
Build
Deploy

Logic bị duplicate.


Chapter 3B

frontend ──────────┐
cartservice ───────┤
productcatalog ────┼──→ reusable-ci-cd.yml
checkoutservice ───┘
                         ↓
                    Checkout
                         ↓
                       Build
                         ↓
                      Deploy

Logic được centralize.


24. Thử mô phỏng thêm service

Đây là phần quan trọng để thấy Scale thực sự hoạt động.

Giả sử muốn thêm:

paymentservice

Không cần copy toàn bộ CI/CD workflow.

Chỉ cần tạo:

touch .github/workflows/paymentservice.yml

Nội dung:

name: Paymentservice CI/CD

on:
  push:
    branches:
      - main
    paths:
      - "src/paymentservice/**"
      - ".github/workflows/paymentservice.yml"

jobs:
  deploy:
    uses: ./.github/workflows/reusable-ci-cd.yml

    with:
      service: paymentservice

    secrets: inherit

Đây chính là điểm khác biệt lớn.

Chapter 3A

Thêm service:

New Service
    ↓
Copy workflow cũ
    ↓
Sửa tên
    ↓
Sửa path
    ↓
Sửa Docker command
    ↓
Hy vọng không quên gì

Chapter 3B

Thêm service:

New Service
    ↓
Tạo caller workflow
    ↓
service: paymentservice
    ↓
Done

25. Kiến trúc cuối Chapter 3B

                         GitHub
                            │
          ┌─────────────────┼─────────────────┐
          │                 │                 │
          ↓                 ↓                 ↓
      frontend        cartservice      productcatalog
          │                 │                 │
          ↓                 ↓                 ↓
     frontend.yml     cartservice.yml    productcatalog.yml
          │                 │                 │
          └─────────────────┼─────────────────┘
                            ↓
                  reusable-ci-cd.yml
                            │
                  ┌─────────┴─────────┐
                  ↓                   ↓
               Docker                SSH
                Build                 │
                                      ↓
                                     EC2
                                      │
                                Docker Compose
                                      │
                                Online Boutique

26. Kết quả đạt được

Trước Chapter 3B

4 services
     ↓
4 pipelines
     ↓
4 copies of CI/CD logic

Sau Chapter 3B

4 services
     ↓
4 thin caller workflows
     ↓
1 reusable workflow
     ↓
1 source of truth

Và khi tăng lên:

4 services
     ↓
10 services
     ↓
30 services
     ↓
50 services

CI/CD logic vẫn nằm ở:

reusable-ci-cd.yml

Đây chính là bước đầu tiên biến GitHub Actions từ “pipeline cho từng application” thành một CI/CD pattern có thể tái sử dụng.


27. Vấn đề mới xuất hiện

Reusable Workflow đã giải quyết:

❌ Copy-paste CI/CD logic
❌ Pipeline drift
❌ Khó maintain nhiều workflow

Nhưng vẫn còn:

4 services
     ↓
4 caller workflows
     ↓
Nhiều service vẫn phải khai báo thủ công

Ví dụ:

frontend
cartservice
productcatalogservice
checkoutservice
paymentservice
shippingservice
...

Chúng ta vẫn phải tạo:

frontend.yml
cartservice.yml
productcatalogservice.yml
checkoutservice.yml
paymentservice.yml
...

Đây chính là vấn đề tiếp theo.

Chapter 3C, chúng ta có thể sử dụng Matrix Strategy:

                     GitHub
                        ↓
                    Matrix
                        ↓
       ┌────────────────┼────────────────┐
       ↓                ↓                ↓
   frontend           cart           payment
       ↓                ↓                ↓
       └────────────────┼────────────────┘
                        ↓
               Reusable Workflow
                        ↓
                  Build / Deploy

Khi đó:

Một workflow có thể xử lý nhiều microservices thay vì phải tạo một caller workflow cho từng service.

Đây sẽ là bước tiếp theo từ Reusable Workflow → Scalable CI/CD Platform.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.