0

🚀 Chapter 1 — Startup: Từ một Cloud VM đến lần Deploy đầu tiên

Bối cảnh: Một startup vừa ra mắt sản phẩm. Team nhỏ, ngân sách hạn chế, lượng traffic chưa lớn.

Mục tiêu: Đưa application lên Internet bằng một Cloud VM và Docker, đồng thời hiểu tại sao cách làm này chỉ phù hợp ở giai đoạn đầu.


1. Startup chưa cần Kubernetes

Hãy tưởng tượng chúng ta đang xây dựng ShopNow, một nền tảng e-commerce.

Team hiện tại chỉ có:

  • 3 Backend Developers
  • 2 Frontend Developers
  • 1 DevOps/Developer kiêm nhiệm
  • Traffic chưa lớn
  • Chỉ có một môi trường Production

Application là một hệ thống microservices gồm nhiều service.

                    Internet
                        │
                        ▼
                ┌──────────────┐
                │   Cloud VM   │
                │              │
                │ Docker       │
                │ Docker       │
                │ Docker       │
                │ Docker       │
                └──────────────┘
                        ▲
                        │ SSH
                        │
                ┌──────────────┐
                │  Developer   │
                │   Laptop     │
                └──────────────┘

Có một câu hỏi quan trọng:

Tại sao không dùng Kubernetes ngay từ đầu?

Vì ở thời điểm này, Kubernetes giải quyết một vấn đề mà startup chưa thực sự có.

Chúng ta chưa có:

  • hàng chục service cần quản lý
  • hàng chục server
  • autoscaling
  • rolling deployment phức tạp
  • nhiều environment
  • nhiều team cùng deploy
  • yêu cầu GitOps
  • workload cần scheduling phức tạp

Nếu đưa Kubernetes vào ngay từ ngày đầu, team sẽ phải học và vận hành thêm:

Kubernetes
├── Cluster
├── Node
├── Deployment
├── Service
├── Ingress
├── ConfigMap
├── Secret
├── RBAC
├── Monitoring
└── ...

Trong khi vấn đề hiện tại chỉ là:

"Làm sao đưa application lên Internet?"

Vì vậy, startup chọn giải pháp đơn giản nhất:

Một Cloud VM + Docker Compose.


2. Kiến trúc Phase 1

Kiến trúc ban đầu rất đơn giản:

Developer
    │
    │ git push
    ▼
  GitHub
    │
    │ SSH
    ▼
┌──────────────────────────── Cloud ────────────────────────────┐
│                                                               │
│                     Azure VM                                  │
│                                                               │
│                    ┌───────────┐                              │
│                    │   Nginx   │                              │
│                    └─────┬─────┘                              │
│                          │                                    │
│                    Docker Compose                             │
│                          │                                    │
│        ┌─────────────────┼─────────────────┐                  │
│        ▼                 ▼                 ▼                  │
│   Frontend           Backend            Other Services        │
│                                                               │
└───────────────────────────────────────────────────────────────┘

Ở đây chúng ta cố tình không có:

❌ Azure DevOps
❌ CI/CD
❌ Harbor
❌ Kubernetes
❌ ArgoCD
❌ GitOps

Không phải vì chúng không tốt.

Mà vì:

Architecture phải xuất hiện để giải quyết một problem thực tế.


3. Bước 1 — Chọn Cloud VM

Ở startup, chúng ta cần một server có Internet Public IP.

Ví dụ sử dụng Azure VM:

Azure
 └── Resource Group
      └── VM
           ├── Public IP
           ├── Ubuntu
           └── Docker

Có thể chọn một VM nhỏ để bắt đầu.

Điều quan trọng không phải là cấu hình VM cụ thể.

Điều quan trọng cần hiểu:

Cloud VM
   │
   ├── CPU
   ├── RAM
   ├── Disk
   └── Public IP

Đây chính là server Production đầu tiên của startup.


4. Bước 2 — SSH vào Production

Sau khi tạo VM:

ssh <user>@<PUBLIC_IP>

Kiểm tra server:

uname -a
lsb_release -a

Ta đang đứng trực tiếp trên Production server.

Đây là một điểm rất quan trọng.

Ở giai đoạn này:

Developer Laptop
       │
       │ SSH
       ▼
Production Server

Developer có quyền truy cập trực tiếp vào Production.

Điều này rất tiện.

Nhưng sau này nó sẽ trở thành một vấn đề lớn.


5. Bước 3 — Cài Docker

Trên VM:

docker --version

và:

docker compose version

Kiểm tra:

docker ps

Nếu Docker hoạt động:

CONTAINER ID   IMAGE   STATUS   PORTS

Server đã sẵn sàng để chạy application.


6. Bước 4 — Đưa source code lên server

Chúng ta clone repository:

git clone <repository>

Ví dụ:

git clone https://github.com/GoogleCloudPlatform/microservices-demo.git
cd microservices-demo

Điểm cần chú ý:

Đừng vội chạy application.

Một DevOps engineer trước tiên phải hiểu application mình sắp deploy.

Hãy nhìn repository:

microservices-demo/
│
├── src/
│   ├── frontend/
│   ├── cartservice/
│   ├── productcatalogservice/
│   ├── checkoutservice/
│   └── ...
│
├── kubernetes-manifests/
├── helm-chart/
├── kustomize/
└── ...

Ta thấy đây đã là một hệ thống nhiều service.

Nhưng Phase 1 chỉ quan tâm đến một câu hỏi:

"Làm sao chạy được application trên một server?"


7. Bước 5 — Đóng gói application bằng Docker

Thay vì cài Node.js, Python, Go, Java... trực tiếp lên server, chúng ta dùng container.

Source Code
     │
     ▼
 Dockerfile
     │
     ▼
 Docker Image
     │
     ▼
 Docker Container

Ví dụ:

docker build -t shopnow-frontend .

Sau đó:

docker images

Ta có:

REPOSITORY          TAG       IMAGE ID
shopnow-frontend    latest    abc123

Docker giải quyết một vấn đề rất cơ bản:

Application chạy với đúng dependency mà nó cần.

Thay vì Production server phải biết:

Node version ?
Python version ?
Java version ?
Library version ?
System dependency ?

ta đưa dependency vào container image.


8. Bước 6 — Chạy nhiều service bằng Docker Compose

Một microservices application không chỉ có một container.

Ví dụ:

                 Docker Compose
                       │
       ┌───────────────┼────────────────┐
       ▼               ▼                ▼
   Frontend         Backend           Redis
   Container        Container        Container

Docker Compose cho phép định nghĩa chúng trong một file:

services:

  frontend:
    image: shopnow-frontend

  backend:
    image: shopnow-backend

  redis:
    image: redis

Sau đó:

docker compose up -d

Kiểm tra:

docker compose ps

Kết quả:

NAME             STATUS
frontend         running
backend          running
redis            running

Đây chính là deployment đầu tiên của startup.


9. Bước 7 — Đưa application ra Internet

Cloud VM có Public IP:

Internet
    │
    │ HTTP :80
    ▼
Public IP
    │
    ▼
   Nginx
    │
    ▼
Frontend Container
    │
    ▼
Backend Services

Nginx đóng vai trò reverse proxy.

Ví dụ:

http://shopnow.com
        │
        ▼
      Nginx
        │
        ▼
   Frontend :8080

Từ máy cá nhân:

curl http://<PUBLIC_IP>

Hoặc mở:

http://<PUBLIC_IP>

Nếu application hiển thị:

ShopNow

🎉 Startup đã có Production đầu tiên.


10. Nhưng deploy lần thứ hai thì sao?

Ngày hôm sau developer sửa code:

Fix checkout bug

Developer push:

git push

Nhưng Production không tự thay đổi.

Developer phải SSH vào server:

ssh <user>@<PUBLIC_IP>

Sau đó:

cd microservices-demo
git pull

Build lại:

docker compose build

Deploy:

docker compose up -d

Kiểm tra:

docker compose ps

Quy trình hiện tại là:

Developer
    │
    │ git push
    ▼
 GitHub
    │
    │ SSH
    ▼
Production VM
    │
    ├── git pull
    ├── docker build
    └── docker compose up

Nó hoạt động.

Và đây chính là điều quan trọng.

Một hệ thống không cần phải "enterprise" mới được coi là tốt.

Ở startup, đơn giản đôi khi chính là thiết kế tốt.


11. Vấn đề bắt đầu xuất hiện

Sau vài tuần, startup phát triển.

Từ:

5 developers
1 server
1 deploy/day

thành:

20 developers
1 server
10 deploy/day

Lúc này quy trình:

ssh
git pull
docker build
docker compose up

bắt đầu gây ra vấn đề.

Problem 1 — Human Error

Developer có thể quên:

docker compose build

hoặc chạy nhầm:

docker compose down

Production có thể bị downtime.


Problem 2 — Không biết ai deploy

Production server có thể có lịch sử:

09:10  Thong
10:30  A
11:20  B
13:45  Thong

Nhưng không có một hệ thống deployment rõ ràng.


Problem 3 — Deploy không nhất quán

Developer A:

docker compose up -d

Developer B:

docker compose down
docker compose up -d

Developer C:

docker compose pull
docker compose up -d

Mỗi người có thể deploy theo một cách khác nhau.


Problem 4 — Không có Automated Test

Developer sửa code:

Code
 ↓
git push
 ↓
Production

Không có:

Test
Lint
Security Scan
Build Verification

Một bug hoàn toàn có thể đi thẳng vào Production.


Problem 5 — Rollback rất thủ công

Giả sử version hiện tại:

v1.5

Deploy version mới:

v1.6

Nhưng v1.6 bị lỗi.

Ta phải tự:

git checkout v1.5
docker compose build
docker compose up -d

Rollback cũng trở thành một công việc thủ công.


12. Hãy nhìn lại architecture

Architecture hiện tại:

Developer
    │
    ▼
  GitHub
    │
    │ SSH
    ▼
┌───────────────────┐
│     Cloud VM      │
│                   │
│ Docker Compose    │
│                   │
│ ┌───────────────┐ │
│ │ Application   │ │
│ └───────────────┘ │
└───────────────────┘

Nó có một ưu điểm cực lớn:

Đơn giản.

Nhưng đổi lại:

                    Manual
                       │
          ┌────────────┼────────────┐
          ▼            ▼            ▼
        Build         Test       Deploy
          │            │            │
          └────────────┼────────────┘
                       ▼
                    Human

Con người đang đứng giữa toàn bộ release process.

Và đây chính là bottleneck.


13. Senior Engineer sẽ hỏi gì?

Không phải:

"Chúng ta nên dùng Kubernetes chưa?"

Mà là:

"Vấn đề lớn nhất hiện tại là gì?"

Câu trả lời:

Code
 ↓
Manual Build
 ↓
Manual Test
 ↓
Manual Deploy

Vấn đề đầu tiên cần giải quyết là:

Automation.

  • Chưa cần Kubernetes.
  • Chưa cần ArgoCD.
  • Chưa cần Harbor.

Chỉ cần:

Developer
    │
    ▼
   Git
    │
    ▼
  CI/CD
    │
    ├── Build
    ├── Test
    └── Deploy
    │
    ▼
Cloud VM

Đây chính là lý do Phase 2 bắt đầu xuất hiện.


14. Architecture Evolution

Đây là tư duy quan trọng nhất của toàn bộ series.

Chúng ta không xây một hệ thống Production hoàn chỉnh ngay từ đầu.

Chúng ta tiến hóa theo vấn đề:

PHASE 1
Startup
Cloud VM + Docker Compose
        │
        │ Manual deployment becomes painful
        ▼
PHASE 2
Growing Team
Azure DevOps + CI
        │
        │ Build/deploy logic duplicated
        ▼
PHASE 3
Microservices Scale
Reusable Pipeline Templates
        │
        │ Images need governance
        ▼
PHASE 4
Production
Harbor + Security + Approval
        │
        │ Deployment becomes complex
        ▼
PHASE 5
Platform Scale
Kubernetes + GitOps + ArgoCD
        │
        │ Production failures & drift
        ▼
PHASE 6
Production Reality
Rollback + Observability + Reliability

Đây mới là cách một hệ thống DevOps thực tế thường tiến hóa.


15. Senior Thinking

Sau Phase 1, bạn không cần nhớ hàng chục câu lệnh Docker.

Bạn cần hiểu 5 điều:

① Tại sao bắt đầu bằng VM?

Vì startup cần sự đơn giản.

② Tại sao dùng Docker?

Để đóng gói application và dependency thành artifact có thể chạy nhất quán.

③ Tại sao dùng Docker Compose?

Vì application có nhiều container nhưng chưa cần một container orchestrator như Kubernetes.

④ Tại sao chưa dùng Kubernetes?

Vì complexity của Kubernetes chưa được justify bởi scale hiện tại.

⑤ Tại sao phải chuyển sang CI/CD?

Không phải vì CI/CD "hiện đại".

Mà vì:

Manual Process
      ↓
Human Error
      ↓
Slow Release
      ↓
Deployment Bottleneck
      ↓
Automation

Key Takeaways

Startup
   ↓
Cloud VM
   ↓
Docker
   ↓
Docker Compose
   ↓
Manual Deployment
   ↓
Team grows
   ↓
Manual deployment becomes bottleneck
   ↓
Need CI/CD

Phase 1 không nhằm dạy bạn Docker Compose.

Nó nhằm giúp bạn hiểu:

Tại sao một startup có thể bắt đầu rất đơn giản — và chính sự phát triển của business khiến architecture phải thay đổi.


Và câu hỏi của Phase 2 là...

"Nếu mỗi lần deploy đều phải SSH vào Production, build bằng tay và chạy Docker Compose bằng tay, chuyện gì xảy ra khi team có 20 developer và deploy 20 lần mỗi ngày?"

Lúc đó, chúng ta không cần thêm người.

Chúng ta cần automation.

Phase 2: Growing Team — Từ Manual Deployment đến CI/CD với Azure DevOps.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí