🚀 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