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).
Control plane và node đứng ở đâu
flowchart TB
subgraph CP["Control Plane"]
api[kube-apiserver]
etcd[etcd]
sched[kube-scheduler]
ctrl[controller-manager]
end
subgraph N1["Node 1"]
kubelet1[kubelet]
proxy1[kube-proxy]
podA[Pod A]
podB[Pod B]
end
subgraph N2["Node 2"]
kubelet2[kubelet]
proxy2[kube-proxy]
podC[Pod C]
podD[Pod D]
end
api --> kubelet1
kubelet1 --> proxy1
proxy1 --> podA
proxy1 --> podB
api --> kubelet2
kubelet2 --> proxy2
proxy2 --> podC
proxy2 --> podD
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
sequenceDiagram
participant K as kubectl
participant API as kube-apiserver
participant DC as Deployment Controller
participant Sched as kube-scheduler
participant KL as kubelet
participant KP as kube-proxy/CNI
K->>API: kubectl apply -f deploy.yaml
API->>API: Authenticate > Authorize > Admit
API->>API: Persist Deployment to etcd
API-->>DC: Watch: new Deployment
DC->>DC: Tạo ReplicaSet > Pod objects<br/>(chưa có nodeName)
DC-->>Sched: Watch: Pod chưa assigned
Sched->>Sched: Filter + score > gán nodeName
Sched-->>KL: Watch: Pod assigned to this node
KL->>KL: Pull image, tạo container<br/>báo cáo trạng thái
KL-->>KP: Pod ready
KP->>KP: Cập nhật network rules
Đ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
Điều cần giữ khi vận hành Kubernetes
- 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.