Sau bài này bạn làm được: vẽ được sơ đồ tối thiểu của một cluster (control plane + node); giải thích Pod là đơn vị scheduling chứ không phải container; tra cứu component nào chịu trách nhiệm khi pod không được lên lịch.
Kubernetes giải quyết vấn đề gì
Docker giúp bạn đóng gói app vào container. Nhưng khi có 50 container trên 10 máy:
- Container crash → ai restart?
- Deploy phiên bản mới → rolling update thế nào?
- Service A gọi Service B → tìm IP bằng cách nào?
- Node hết RAM → pod chuyển đi đâu?
Kubernetes là API + trạng thái hợp nhất trả lời tất cả câu hỏi trên. Bạn khai báo trạng thái mong muốn (desired state) bằng YAML, Kubernetes lo đưa thực tế về khớp (reconciliation loop).
Kiến trúc tổng quan
┌─────────────────────────────────────────────────────────┐
│ CONTROL PLANE │
│ │
│ ┌──────────────┐ ┌────────┐ ┌───────────────────┐ │
│ │ kube-apiserver│ │ etcd │ │ kube-scheduler │ │
│ └──────┬───────┘ └────────┘ └───────────────────┘ │
│ │ ┌───────────────────┐ │
│ │ │controller-manager │ │
│ │ └───────────────────┘ │
└─────────┼───────────────────────────────────────────────┘
│ API calls
┌─────────┼──────────────┐ ┌──────────────────────────┐
│ NODE 1 │ │ │ NODE 2 │
│ ┌──────▼─────┐ │ │ ┌───────────┐ │
│ │ kubelet │ │ │ │ kubelet │ │
│ └──────┬─────┘ │ │ └─────┬─────┘ │
│ ┌──────▼─────┐ │ │ ┌─────▼─────┐ │
│ │ kube-proxy │ │ │ │ kube-proxy │ │
│ └────────────┘ │ │ └───────────┘ │
│ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ │
│ │Pod A│ │Pod B│ │ │ │Pod C│ │Pod D│ │
│ └─────┘ └─────┘ │ │ └─────┘ └─────┘ │
└────────────────────────┘ └──────────────────────────┘
Control plane — bộ não
kube-apiserver
- Cổng vào duy nhất của cluster. Mọi thứ (kubectl, kubelet, controller) đều nói chuyện qua API server.
- Xác thực (authentication), phân quyền (authorization), admission control, rồi ghi vào etcd.
- Stateless — có thể chạy nhiều replica phía sau load balancer.
etcd
- Key-value store lưu toàn bộ trạng thái cluster: pod, service, configmap, secret…
- Nguồn sự thật duy nhất (single source of truth). Mất etcd = mất cluster.
- Chỉ API server nói chuyện trực tiếp với etcd.
kube-scheduler
- Theo dõi pod mới chưa có node (
.spec.nodeNametrống). - Chọn node phù hợp dựa trên: resource requests, affinity/anti-affinity, taint/toleration, topology.
- Chỉ gán node — không tạo container. Việc tạo container là của kubelet.
kube-controller-manager
- Chạy nhiều controller trong một process: Deployment controller, ReplicaSet controller, Node controller, Job controller…
- Mỗi controller watch một loại resource và reconcile trạng thái thực về trạng thái mong muốn.
- Ví dụ: Deployment controller thấy
replicas: 3nhưng chỉ có 2 pod → tạo thêm 1.
Node — nơi workload chạy
kubelet
- Agent chạy trên mỗi node. Nhận pod spec từ API server, gọi container runtime (containerd, CRI-O) để tạo/dừng container.
- Báo cáo trạng thái node và pod về API server.
- Chạy probe (liveness, readiness, startup) để kiểm tra container health.
kube-proxy
- Duy trì network rules trên node để Service hoạt động.
- Mode phổ biến: iptables (mặc định), IPVS (scale lớn), hoặc eBPF (Cilium thay thế hoàn toàn kube-proxy).
- Không proxy traffic trực tiếp — chỉ cấu hình kernel networking rules.
Container runtime
- Kubernetes không chạy container trực tiếp — giao cho runtime qua CRI (Container Runtime Interface).
- Phổ biến: containerd (mặc định từ K8s 1.24+, Docker shim đã bị loại bỏ), CRI-O.
- Runtime lo pull image, tạo cgroup, mount filesystem, start process.
Pod — đơn vị scheduling
Pod không phải container. Pod là:
- Một hoặc nhiều container cùng chia sẻ network namespace (cùng IP, cùng port space) và volume.
- Đơn vị scheduling — scheduler đặt cả pod lên một node, không tách container ra các node khác nhau.
- Có IP riêng trong cluster (do CNI cấp).
apiVersion: v1
kind: Pod
metadata:
name: my-app
namespace: default
spec:
containers:
- name: app
image: my-app:1.2.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
Thực tế: bạn hiếm khi tạo Pod trực tiếp. Bạn tạo Deployment (bài 04) — nó tạo ReplicaSet → ReplicaSet tạo Pod.
Request flow: từ kubectl apply đến container chạy
1. kubectl apply -f deploy.yaml
│
▼
2. kube-apiserver
- Authenticate (kubeconfig token/cert)
- Authorize (RBAC)
- Admission (mutating → validating webhooks)
- Persist Deployment object → etcd
│
▼
3. Deployment controller (trong controller-manager)
- Thấy Deployment mới → tạo ReplicaSet
- ReplicaSet controller → tạo Pod objects (chưa có nodeName)
│
▼
4. kube-scheduler
- Thấy Pod chưa có node → filter + score → gán nodeName
- Update Pod object trong etcd qua API server
│
▼
5. kubelet trên node được gán
- Watch thấy Pod mới cho node mình
- Gọi containerd: pull image, tạo container
- Báo cáo trạng thái: Running / Failed / Pending
│
▼
6. kube-proxy (hoặc CNI)
- Cập nhật network rules cho Service nếu Pod match selector
Điểm quan trọng: mỗi bước là asynchronous. Không có “transaction” từ đầu đến cuối. Controller A tạo object, Controller B watch và phản ứng — đây là mô hình level-triggered reconciliation.
Namespace — phân vùng logic
Namespace không phải cluster riêng. Nó là:
- Phân vùng tên: hai Service cùng tên
apicó thể tồn tại ở namespace khác nhau. - Ranh giới cho RBAC, ResourceQuota, NetworkPolicy.
- Không cách ly network mặc định — pod ở namespace A vẫn reach được pod ở namespace B (trừ khi có NetworkPolicy — bài 10).
# Namespace mặc định của cluster
kubectl get ns
# NAME STATUS AGE
# default Active 30d
# kube-system Active 30d ← control plane components
# kube-public Active 30d ← readable by all
# kube-node-lease Active 30d ← node heartbeat
# Tạo namespace
kubectl create ns staging
# Làm việc trong namespace
kubectl get pods -n staging
kubectl config set-context --current --namespace=staging
Object API — mọi thứ là resource
Kubernetes quản lý mọi thứ qua resource objects với cấu trúc chung:
apiVersion: apps/v1 # API group + version
kind: Deployment # Loại resource
metadata:
name: my-app # Tên (unique trong namespace)
namespace: default
labels: # Key-value để filter/select
app: my-app
version: v1
spec: # Trạng thái mong muốn (bạn khai báo)
replicas: 3
# ...
status: # Trạng thái thực (K8s cập nhật)
availableReplicas: 3
# ...
spec là cái bạn viết. status là cái K8s báo lại. Controller reconcile status → spec.
Labels và selectors
Labels là cơ chế kết nối giữa các objects:
- Deployment chọn Pod qua label selector.
- Service chọn Pod qua label selector.
- NetworkPolicy chọn Pod qua label selector.
# Deployment tạo Pod với label app=my-api
spec:
selector:
matchLabels:
app: my-api
template:
metadata:
labels:
app: my-api
# Service route traffic tới Pod có label app=my-api
spec:
selector:
app: my-api
Sai label = traffic không tới, scaling không hoạt động. Đây là nguồn lỗi phổ biến nhất cho người mới.
Lab nhanh: cluster local với kind
# Cài kind (Kubernetes IN Docker)
# macOS: brew install kind
# Linux: go install sigs.k8s.io/kind@latest
# Tạo cluster
kind create cluster --name dev
# Kiểm tra
kubectl cluster-info
kubectl get nodes
kubectl get pods -A # -A = all namespaces
# Xem components control plane
kubectl get pods -n kube-system
# Dọn dẹp
kind delete cluster --name dev
Tóm tắt
- Kubernetes = desired state + reconciliation loops. Bạn khai báo, controller lo hiện thực.
- Control plane (apiserver, etcd, scheduler, controller-manager) là bộ não; node (kubelet, kube-proxy, runtime) là tay chân.
- Pod là đơn vị scheduling, không phải container. Một pod có thể chứa nhiều container cùng network/volume.
- Mọi thứ là API object với spec (mong muốn) và status (thực tế).
- Labels + selectors kết nối objects với nhau — sai label là nguồn lỗi số 1.
Câu hỏi hay gặp
etcd mất dữ liệu thì cluster có chạy được không?
Trả lời: Pod đang chạy vẫn chạy (kubelet giữ container), nhưng bạn không thể tạo/sửa/xoá bất kỳ object nào, không thể schedule pod mới, Service không cập nhật. Thực tế cluster “đứng hình”. Backup etcd định kỳ là bắt buộc.
Có thể chạy control plane trên một node duy nhất không?
Trả lời: Có — đó là cách minikube, kind, k3s hoạt động. Production thường chạy 3+ control plane node cho HA: etcd cần quorum (2/3 hoặc 3/5), apiserver stateless nên scale ngang dễ dàng.
Docker đã bị loại khỏi Kubernetes?
Trả lời: Dockershim bị loại từ K8s 1.24 (2022). Container runtime giờ là containerd hoặc CRI-O. Image Docker (OCI format) vẫn hoạt động bình thường — chỉ runtime shim thay đổi, không ảnh hưởng Dockerfile hay image registry.
Bài tiếp theo (Giai đoạn I): kubectl, ngữ cảnh và namespace — pattern thao tác hằng ngày trên cluster.