0

🚀 Chapter 3 — Scale: Biến CI/CD thành Internal Developer Platform

Bối cảnh: ShopNow đã phát triển từ vài developer lên hàng chục developer, application từ một service thành nhiều microservices. CI/CD đã tự động hóa deployment, nhưng mỗi team bắt đầu tự viết và copy pipeline của mình.

Mục tiêu: Thiết kế một CI/CD platform có thể tái sử dụng, chuẩn hóa cách Build → Test → Package → Deploy mà không bắt developer phải tự xây pipeline từ đầu.


1. Automation đã giải quyết được vấn đề gì?

Ở Phase 2, chúng ta đã có:

Developer
    │
    ▼
  GitHub
    │
    ▼
Azure DevOps
    │
    ├── Build
    ├── Test
    ├── Package
    └── Deploy
           │
           ▼
       Cloud VM

Điều này tốt hơn rất nhiều so với:

ssh
git pull
docker build
docker compose up

Nhưng công ty tiếp tục phát triển.


2. Từ 1 application đến 50 microservices

Ban đầu:

shopnow/
└── pipeline.yml

Sau đó:

shopnow/
├── frontend
├── checkout
├── cart
├── payment
├── product
├── recommendation
├── shipping
├── email
└── ...

Giả sử công ty có:

20 teams
100 microservices

Nếu mỗi team tự viết pipeline:

Service A → pipeline-a.yml
Service B → pipeline-b.yml
Service C → pipeline-c.yml
...
Service Z → pipeline-z.yml

sẽ nhanh chóng xuất hiện vấn đề.


3. Copy-paste YAML là một cái bẫy

Giả sử mọi service đều có:

steps:
  - Build
  - Test
  - Docker Build
  - Security Scan
  - Push
  - Deploy

Developer A copy pipeline:

pipeline-a.yml

Developer B copy:

pipeline-b.yml

Sau vài tháng:

pipeline-a → version 1
pipeline-b → version 2
pipeline-c → version 1
pipeline-d → version 3

Một thay đổi security mới xuất hiện.

Ví dụ:

"Tất cả Docker image phải được scan trước khi release."

Platform team phải sửa:

100 pipelines

Đây là maintenance nightmare.


4. Vấn đề thực sự là gì?

Không còn là:

"Làm sao chạy CI/CD?"

Mà là:

"Làm sao đảm bảo 100 service đều có một CI/CD process nhất quán?"

Đây là lúc chúng ta cần:

Reusable Pipeline
        +
Standardization
        +
Self-service

Hay nói cách khác:

Internal Developer Platform


5. Kiến trúc Platform mới

Thay vì:

Developer
   │
   ▼
Tự viết Pipeline

ta chuyển thành:

                    Platform Team
                         │
                         ▼
              ┌────────────────────┐
              │  CI/CD Templates   │
              │                    │
              │ Build              │
              │ Test               │
              │ Docker             │
              │ Security Scan      │
              │ Deploy             │
              └─────────┬──────────┘
                        │
             ┌──────────┼──────────┐
             ▼          ▼          ▼
          Team A      Team B      Team C
             │          │          │
             ▼          ▼          ▼
          Service A   Service B   Service C

Platform team xây paved road.

Developer chỉ cần đi trên con đường đã được chuẩn hóa.


6. "Paved Road" là gì?

Hãy tưởng tượng developer cần tạo một service mới.

Thay vì phải tự suy nghĩ:

Docker build thế nào?
Test thế nào?
Scan thế nào?
Push image thế nào?
Deploy thế nào?

Platform cung cấp sẵn:

Create Service
      │
      ▼
Choose Template
      │
      ▼
Node.js / Java / Go
      │
      ▼
Standard Pipeline
      │
      ▼
Ready

Developer chỉ cần cung cấp:

service:
  name: checkout

runtime:
  language: node

deployment:
  environment: production

Platform xử lý phần còn lại.


7. Step 1 — Xác định phần nào nên Reuse

Không phải mọi thứ đều cần template.

Hãy tìm những phần lặp lại.

Ví dụ 100 service đều có:

Checkout
    ↓
Install
    ↓
Build
    ↓
Test
    ↓
Docker Build
    ↓
Scan

Ta có thể chuẩn hóa:

                 CI Template
                     │
       ┌─────────────┼─────────────┐
       ▼             ▼             ▼
    Install         Test        Docker
                                  Build

Trong khi những thứ đặc thù application vẫn để team tự định nghĩa.

Ví dụ:

Standard:
    Build
    Test
    Docker
    Scan

Custom:
    Integration Test
    Database Migration
    Special Deployment

Đây là một nguyên tắc quan trọng:

Standardize the common, customize the exceptional.


8. Step 2 — Tạo Repository cho Platform

Thay vì để template nằm rải rác:

service-a/
service-b/
service-c/

chúng ta tạo repository riêng:

platform-pipelines/
│
├── templates/
│   ├── node-ci.yml
│   ├── java-ci.yml
│   ├── docker-build.yml
│   ├── security-scan.yml
│   └── deploy.yml
│
├── stages/
│   ├── ci.yml
│   └── cd.yml
│
└── README.md

Architecture:

                  Platform Repository
                         │
                         │ templates
                         ▼
              ┌────────────────────┐
              │ Azure DevOps       │
              │ Pipeline Templates │
              └─────────┬──────────┘
                        │
           ┌────────────┼────────────┐
           ▼            ▼            ▼
        Service A    Service B    Service C

Đây là bước chuyển từ:

Pipeline as Code

sang:

Pipeline Platform

9. Step 3 — Service chỉ cần gọi Template

Service không cần copy toàn bộ pipeline.

Ví dụ:

extends:
  template: templates/node-ci.yml
  parameters:
    serviceName: checkout

Hoặc conceptually:

Service Repository
       │
       │ uses
       ▼
Platform Template
       │
       ├── Build
       ├── Test
       ├── Docker
       └── Scan

Developer chỉ cần biết:

"Tôi sử dụng standard pipeline nào?"

thay vì:

"Tôi phải viết 300 dòng YAML như thế nào?"


10. Một pipeline chuẩn

Platform team định nghĩa standard pipeline:

                    CI
                     │
        ┌────────────┼────────────┐
        ▼            ▼            ▼
      Build         Test         Lint
        │            │            │
        └────────────┼────────────┘
                     ▼
                Docker Build
                     │
                     ▼
                Security Scan
                     │
                     ▼
                   PASS
                     │
                     ▼
                 Artifact

Mọi service đều đi qua flow này.

Ví dụ:

Service A ──┐
Service B ──┤
Service C ──┼──► Standard CI
Service D ──┤
Service E ──┘

11. Nhưng Platform không có nghĩa là ép mọi thứ giống nhau

Đây là lỗi thường gặp khi thiết kế Internal Platform.

Ví dụ:

Frontend
Backend
Worker
Batch Job
ML Service

không nhất thiết có cùng deployment process.

Có thể chia thành:

Platform
│
├── Node.js Template
├── Java Template
├── Go Template
├── Docker Template
└── Generic Template

Mỗi template có một contract rõ ràng.

Ví dụ:

Node Template
    Input:
      source
      testCommand

    Output:
      Docker Image

Platform cung cấp abstraction.

Developer không cần biết implementation bên trong.


12. Step 4 — Versioning Template

Đây là một vấn đề rất quan trọng.

Giả sử hôm nay platform có:

node-ci@v1

100 service đang sử dụng.

Platform team thay đổi template.

Nếu thay đổi trực tiếp:

v1 → modified

100 service có thể bị ảnh hưởng.

Vì vậy template cần version:

node-ci@v1
node-ci@v2
node-ci@v3

Ví dụ:

Service A → v1
Service B → v1
Service C → v2

Sau đó platform team có thể migration từng service.


13. Platform có API

Hãy nhìn template như một API.

Ví dụ:

Pipeline Template

có:

Input
    │
    ├── language
    ├── serviceName
    ├── testCommand
    └── deployTarget

và tạo ra:

Output
    │
    ├── Build Result
    ├── Test Result
    └── Docker Image

Do đó:

Pipeline template cũng cần contract và versioning giống một software library.

Đây là một tư duy Platform Engineer rất quan trọng.


14. Step 5 — Chuẩn hóa Artifact

Bây giờ 100 service đều build Docker image.

Nếu mỗi team đặt tên một kiểu:

checkout:v1
payment:latest
cart:release
frontend:prod

sẽ rất khó quản lý.

Platform đưa ra convention:

<registry>/<team>/<service>:<version>

Ví dụ:

registry.shopnow.io/
    ecommerce/
        checkout:a81f32c

Hoặc:

registry.shopnow.io/ecommerce/checkout:2026.09.04

Điểm quan trọng:

Source
   │
   ▼
Git Commit
   │
   ▼
Docker Image
   │
   ▼
Deployment

Phải trace được toàn bộ lifecycle.


15. Step 6 — Chuẩn hóa Pipeline Output

Platform không chỉ chuẩn hóa input.

Nó cũng cần chuẩn hóa output.

Ví dụ mỗi pipeline phải trả về:

Build Status
Test Status
Image Tag
Git Commit
Security Result
Deployment Version

Khi đó platform team có thể biết:

checkout
   │
   ├── commit: a81f32c
   ├── image: checkout:a81f32c
   ├── test: PASS
   ├── scan: PASS
   └── deployment: staging

Đây là nền tảng cho observability của delivery process.


16. Step 7 — Tách CI khỏi Environment

Một sai lầm phổ biến:

Build
   ↓
Deploy Production

Platform tốt hơn sẽ nghĩ theo environment:

                Artifact
                   │
                   ▼
                Dev
                   │
                   ▼
               Staging
                   │
                   ▼
              Production

Điểm quan trọng:

Build một lần, promote nhiều lần.

Không nên:

Build Dev Image
Build Staging Image
Build Production Image

vì như vậy có thể tạo ra các artifact khác nhau.

Thay vào đó:

Source
  │
  ▼
Build ONCE
  │
  ▼
Image v1.5
  │
  ├────► Dev
  │
  ├────► Staging
  │
  └────► Production

Cùng một artifact đi xuyên suốt các environment.


17. Step 8 — Environment Configuration

Application cần những config khác nhau:

Dev
 ├── Database: dev-db
 └── API: dev-api

Staging
 ├── Database: staging-db
 └── API: staging-api

Production
 ├── Database: prod-db
 └── API: prod-api

Nhưng Docker image phải giống nhau:

checkout:a81f32c

Architecture:

                  Same Artifact
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
         Dev        Staging       Prod
          │            │            │
       Config A      Config B      Config C

Đây là separation giữa:

Application Artifact
        ≠
Environment Configuration

18. Step 9 — Pipeline Security

Khi platform trở thành hệ thống trung tâm, security trở nên rất quan trọng.

Không phải pipeline nào cũng nên có quyền:

Deploy Production
Delete Artifact
Modify Infrastructure
Access Database

Ta bắt đầu phân quyền:

Developer
   │
   ├── Run CI
   └── Deploy Dev

Release Manager
   │
   └── Approve Production

Platform Team
   │
   ├── Manage Templates
   └── Manage Connections

Nguyên tắc:

Least Privilege

Mỗi pipeline chỉ có quyền cần thiết.


19. Platform Team và Application Team

Bây giờ tổ chức cũng bắt đầu thay đổi.

                    Engineering
                         │
          ┌──────────────┴──────────────┐
          │                             │
          ▼                             ▼
 Application Teams               Platform Team
          │                             │
          │                             ├── CI/CD
          │                             ├── Templates
          │                             ├── Infrastructure
          │                             └── Security
          │
          └─────── use platform ─────────┘

Application team tập trung:

Business Logic
Features
Application
Tests

Platform team tập trung:

Developer Experience
Automation
Infrastructure
Security
Delivery Platform

Đây là bước đầu tiên để hình thành Platform Engineering.


20. Nhưng Platform cũng có một cái bẫy

Platform team rất dễ biến thành:

"Team chuyên bắt developer phải làm theo platform."

Đó không phải Platform Engineering tốt.

Một platform tốt phải làm developer:

Before:

Developer
   │
   ├── Learn CI/CD
   ├── Write YAML
   ├── Manage Credentials
   ├── Configure Docker
   ├── Configure Scan
   └── Configure Deploy


After:

Developer
   │
   ▼
git push
   │
   ▼
Standard Platform

Platform phải giảm cognitive load cho developer.


21. Platform nên đo bằng gì?

Không chỉ đo:

Pipeline chạy thành công bao nhiêu %

Mà cần hỏi:

Developer mất bao lâu để tạo service mới?

Before: 2 days
After: 30 minutes

Developer mất bao lâu để có pipeline?

Before: 1 day
After: 5 minutes

Bao nhiêu service sử dụng standard pipeline?

20%
50%
90%

Bao nhiêu deployment cần manual intervention?

High → Bad
Low  → Better

Platform cuối cùng phục vụ Developer Experience.


22. Architecture cuối Phase 3

Sau Phase 3:

                           Developers
                               │
                         git push / PR
                               │
                               ▼
                         ┌───────────┐
                         │  GitHub   │
                         └─────┬─────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │    Azure DevOps     │
                    │                     │
                    │  Internal Platform  │
                    │                     │
                    │ ┌─────────────────┐ │
                    │ │ Pipeline        │ │
                    │ │ Templates       │ │
                    │ ├─────────────────┤ │
                    │ │ Build           │ │
                    │ │ Test            │ │
                    │ │ Scan            │ │
                    │ │ Package         │ │
                    │ │ Deploy          │ │
                    │ └─────────────────┘ │
                    └──────────┬──────────┘
                               │
                               ▼
                         Docker Image
                               │
                               ▼
                         Container Registry
                               │
                   ┌───────────┼───────────┐
                   ▼           ▼           ▼
                  Dev       Staging       Prod

Một platform duy nhất phục vụ nhiều team:

                 CI/CD Platform
                      │
       ┌──────────────┼──────────────┐
       ▼              ▼              ▼
   Team A          Team B          Team C
       │              │              │
   Service 1       Service 10      Service 50
   Service 2       Service 11      Service 51

23. Architecture Evolution

Hãy nhìn lại toàn bộ journey.

PHASE 1 — STARTUP
────────────────────────────

Developer
    ↓
GitHub
    ↓
SSH
    ↓
Cloud VM
    ↓
Docker Compose

Problem:
Manual deployment


             ↓


PHASE 2 — AUTOMATION
────────────────────────────

Developer
    ↓
GitHub
    ↓
Azure DevOps
    ↓
Build → Test → Deploy
    ↓
Cloud VM

Problem:
Many pipelines
Many images
Many teams


             ↓


PHASE 3 — PLATFORM
────────────────────────────

                    Platform Team
                         │
                         ▼
                Reusable Templates
                         │
           ┌─────────────┼─────────────┐
           ▼             ▼             ▼
        Team A         Team B        Team C
           │             │             │
           ▼             ▼             ▼
        Services       Services      Services

Problem:
Images need centralized
storage, security and governance.


             ↓


PHASE 4 — PRODUCTION
────────────────────────────

              CI/CD Platform
                    │
                    ▼
                  Harbor
                    │
              ┌─────┼─────┐
              ▼     ▼     ▼
             Dev  Staging Prod
                    │
                 Approval
                    │
                    ▼
               Production

Và đây chính là lý do Phase 4 xuất hiện.


24. Senior Thinking

Ở Phase này, đừng nghĩ:

"Tôi cần học Azure DevOps Template."

Hãy nghĩ:

"Tôi đang xây một platform để 100 developer có thể deploy 100 service mà không cần 100 DevOps engineer."

Đó mới là vấn đề.

Một Platform Engineer cần suy nghĩ theo 6 tầng:

1. Standardization
       ↓
2. Reusability
       ↓
3. Self-Service
       ↓
4. Security
       ↓
5. Governance
       ↓
6. Developer Experience

25. 5 câu hỏi Senior cần trả lời

① Cái gì nên được Standardize?

Build
Test
Docker
Security
Deployment

② Cái gì nên được Customize?

Business-specific test
Special deployment
Special runtime

③ Template thay đổi thì xử lý thế nào?

Versioning
Backward Compatibility
Migration

④ Platform có quyền gì?

Least Privilege
Service Connections
Secrets
RBAC

⑤ Developer có thực sự muốn dùng Platform không?

Nếu:

Platform = khó hơn tự làm

thì platform thất bại.

Nếu:

Platform = con đường dễ nhất để deploy

thì platform thành công.


Key Takeaways

Many Services
     ↓
Many Pipelines
     ↓
Copy/Paste
     ↓
Inconsistency
     ↓
Platform
     ↓
Reusable Templates
     ↓
Standardization
     ↓
Self-Service

Phase 3 không đơn thuần là học Azure DevOps YAML Templates.

Mục tiêu là hiểu một nguyên tắc lớn hơn:

Khi organization scale, DevOps cũng phải scale bằng Platform chứ không phải bằng cách tăng số lượng DevOps Engineer.

Nhưng Platform bây giờ đang build ra hàng trăm Docker Image.

Chúng ta cần một nơi để:

Store
Scan
Sign
Version
Control Access
Retain
Promote

các image đó.

Và lúc này câu hỏi tiếp theo xuất hiện:

"Docker Image của toàn công ty nên được lưu và quản lý ở đâu?"

Đó là lý do chúng ta bước sang:

Phase 4 — Production: Harbor, Security & Release Governance

Từ đây, câu chuyện không còn chỉ là "deploy được".

Mà bắt đầu chuyển sang:

"Làm sao đảm bảo artifact được tin cậy, có thể audit và chỉ được phép đi vào Production khi đáp ứng các policy?"


All Rights Reserved

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