Vấn Đề: Ứng Dụng Docker Chạy Tốt Trên Máy Cá Nhân, Nhưng Production Lại Hỗn Loạn
Bạn đã container hóa ứng dụng với Docker, chạy hoàn hảo trên laptop — nhưng khi cần chạy ở quy mô lớn, mọi thứ bắt đầu sụp đổ. Một container chết và không có gì khởi động lại nó. Traffic đột biến đổ vào một instance duy nhất. Rolling update làm service ngừng hoạt động. Bạn cần thứ gì đó để quản lý container cho mình.
Đó chính là vấn đề mà Kubernetes được tạo ra để giải quyết. Hầu hết các tutorial phản hồi bằng cách ném một đống YAML vào mặt bạn rồi coi như xong việc. Bài này thì không. Tôi sẽ giải thích ba khối xây dựng cốt lõi — Pod, Service và Deployment — và cho bạn thấy chính xác cách chúng kết nối với nhau.
Các Khái Niệm Cốt Lõi
Pod: Đơn Vị Nhỏ Nhất
Pod là đơn vị triển khai nhỏ nhất trong Kubernetes. Hãy nghĩ nó như một lớp bọc nhẹ xung quanh một hoặc nhiều container chia sẻ cùng network namespace và storage volume. Trong thực tế, hầu hết các Pod chỉ chạy một container duy nhất.
Đây là điều mà hầu hết mọi người bỏ lỡ ban đầu: Pod có tính tạm thời. Kubernetes không cố gắng phục hồi một Pod bị hỏng — nó loại bỏ Pod đó và tạo một Pod mới. Đừng bao giờ dựa vào địa chỉ IP hay storage local của Pod cho bất kỳ thứ gì cần bền vững.
Một Pod manifest tối giản trông như thế này:
# pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:1.25
ports:
- containerPort: 80
Áp dụng với lệnh:
kubectl apply -f pod.yaml
kubectl get pods
kubectl describe pod my-app-pod
Bạn sẽ thấy Pod đang chạy — nhưng chỉ điều này thôi không mang lại gì hữu ích trong production. Không có auto-restart, không có load balancing, không có rolling update.
Deployment: Quản Lý Pod ở Quy Mô Lớn
Deployment là thứ bạn thực sự sử dụng trong production. Nó bọc các Pod của bạn trong một controller xử lý ba việc:
- Duy trì số lượng replica mong muốn luôn chạy
- Rolling update với zero downtime
- Rollback khi có sự cố
Bên dưới, một Deployment tạo ra một ReplicaSet, thứ thực sự làm công việc tạo và giám sát Pod. Bạn không tương tác trực tiếp với ReplicaSet — Deployment quản lý chúng cho bạn.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-deployment
spec:
replicas: 3
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: nginx:1.25
ports:
- containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "250m"
memory: "256Mi"
Trường selector.matchLabels là phần quan trọng — đó là cách Deployment biết Pod nào thuộc về nó. Các label trên Pod template phải khớp chính xác, nếu không sẽ không có gì được quản lý.
Áp dụng và kiểm tra:
kubectl apply -f deployment.yaml
kubectl get deployments
kubectl get pods # Bạn sẽ thấy 3 pod với tên được tạo tự động
Service: Truy Cập Mạng Ổn Định Đến Pod Của Bạn
IP của Pod là tạm thời. Mỗi lần Pod khởi động lại, nó nhận một địa chỉ mới. Service giải quyết vấn đề này bằng một IP ảo ổn định tự động định tuyến traffic đến các Pod khỏe mạnh khớp với label selector.
Ba loại Service bao phủ hầu hết các tình huống:
- ClusterIP — chỉ truy cập nội bộ (mặc định, dùng cho giao tiếp giữa các service)
- NodePort — expose service trên một port tĩnh trên mọi node (hữu ích cho testing)
- LoadBalancer — tạo cloud load balancer (AWS ELB, GCP LB, v.v.)
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: ClusterIP
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 80
Trường selector khớp với cùng label (app: my-app) được sử dụng trong Pod template của Deployment. Định tuyến traffic không dựa trên tên hay IP của Pod — chỉ dựa trên label. Đó là điều làm cho hệ thống có khả năng phục hồi khi Pod khởi động lại và được lên lịch lại.
Thực Hành: Triển Khai Ứng Dụng Thực Tế Từ Đầu Đến Cuối
Yêu Cầu Cần Thiết
Để kiểm tra ở local, cài đặt Minikube và kubectl:
# Khởi động cluster local
minikube start
# Xác minh đang chạy
kubectl cluster-info
kubectl get nodes
Triển Khai Full Stack
Bạn có thể đặt cả ba tài nguyên trong một file, phân cách bằng ---:
# app-stack.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
spec:
replicas: 2
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.25-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 80
nodePort: 30080
kubectl apply -f app-stack.yaml
# Kiểm tra mọi thứ đang chạy
kubectl get pods,svc
# Trên Minikube, lấy URL truy cập
minikube service web-service --url
Kiểm Tra Khả Năng Tự Phục Hồi
Xóa một trong các Pod đang chạy và xem Deployment tạo ngay Pod thay thế:
# Lấy tên một pod
kubectl get pods
# Xóa nó
kubectl delete pod web-deployment-xxxxxxxxx-xxxxx
# Theo dõi Kubernetes tạo lại pod
kubectl get pods -w
Rolling Update Với Zero Downtime
Cập nhật image container — Kubernetes xử lý phần còn lại:
kubectl set image deployment/web-deployment web=nginx:1.26-alpine
# Theo dõi quá trình rollout
kubectl rollout status deployment/web-deployment
# Nếu có sự cố, rollback
kubectl rollout undo deployment/web-deployment
# Kiểm tra lịch sử rollout
kubectl rollout history deployment/web-deployment
Trong production, cấu hình này thực sự vững chắc. Với 2+ replica và maxUnavailable: 0 trong chiến lược rollout, Kubernetes sẽ không xóa Pod cũ cho đến khi Pod mới vượt qua readiness check. Zero downtime — ngay cả khi có traffic thực.
Cách Label Kết Nối Mọi Thứ Lại
Label là chất keo trong Kubernetes. Đây là cách kiểm tra các kết nối:
# Xem service đang target pod nào
kubectl describe service web-service
# Tìm: Selector: app=web
# và: Endpoints: (danh sách IP pod)
# Truy vấn pod theo label trực tiếp
kubectl get pods -l app=web
Nếu traffic không được định tuyến đúng, chín trên mười trường hợp là do label không khớp giữa Service selector và Pod label. Kiểm tra điều này trước tiên, trước bất kỳ thứ gì khác.
Những Gì Nên Tìm Hiểu Tiếp Theo
Ba tài nguyên này là nền tảng của bạn. Đây là nơi để tiến xa hơn:
- ConfigMap và Secret — inject cấu hình và thông tin xác thực mà không cần rebuild image
- Ingress — định tuyến traffic HTTP/HTTPS từ bên ngoài đến nhiều Service qua một load balancer
- PersistentVolume — cung cấp storage bền vững cho ứng dụng stateful, tồn tại qua các lần Pod khởi động lại
- Horizontal Pod Autoscaler (HPA) — tự động scale replica dựa trên CPU hoặc custom metric
Mọi đối tượng Kubernetes nâng cao đều tuân theo cùng một mẫu. StatefulSet, DaemonSet, Job — tất cả đều sử dụng Pod được gắn label, một controller quản lý vòng đời của chúng, và Service định tuyến traffic qua selector. Thuật ngữ mở rộng, nhưng logic vẫn như vậy.
Hãy chạy một Deployment ở local. Xóa một Pod và xem Kubernetes khôi phục nó. Kích hoạt một rolling update và theo dõi trực tiếp. Kinh nghiệm thực hành đó mới là thứ giúp các khái niệm nâng cao thực sự thấm sâu vào đầu.

