Bài 01
Bài 01 — Kubernetes: Compose ở quy mô cluster
Chặng trước bạn kết thúc bằng 1 câu docker compose up dựng cả LEMP stack trong 30 giây. Đẹp. Nhưng tôi đã gài sẵn 1 câu ở cuối chặng đó:
"K8s là Compose ở cluster scale. Service = service, Volume = PersistentVolume, Network = NetworkPolicy."
Đây là lúc trả nợ câu nói đó. Cả chặng Docker bạn học cách đóng gói và chạy container trên 1 máy. Chặng này bạn học cách chạy container trên một dàn máy — tự scale, tự phục hồi, tự cập nhật không downtime.
Mục tiêu Bài 01: hiểu K8s là gì, vì sao nó tồn tại, và bên trong nó có gì (kiến trúc). Chưa cài cluster thật vội — đó là capstone Bài 05. Bài này xây nền tảng tư duy: nhìn vào 1 cluster, bạn biết "ai làm gì".
Vấn đề: Compose chạm trần ở 1 host
Quay lại LEMP stack chặng trước. Nó chạy ngon — trên 1 server. Giờ thử đặt vài câu hỏi production thật:
❓ 3 giờ sáng, server đó cháy nguồn (hoặc kernel panic).
→ Toàn bộ stack sập. nginx + php + db + redis chết cùng lúc.
→ Ai restart? Bạn. Lúc 3 giờ sáng.
❓ Black Friday, traffic gấp 50 lần.
→ docker compose up --scale php=10? Vẫn nhồi 10 container vào
1 con CPU. Hết RAM là hết. Không thêm được máy thứ 2.
❓ Deploy version mới giữa giờ cao điểm.
→ docker compose up -d --build → container cũ chết, container
mới đang khởi động → vài giây downtime, khách thấy 502.
❓ 1 trong 4 container crash lúc bạn đang ngủ.
→ restart: unless-stopped cứu được container đó. Nhưng nếu
CẢ MÁY chết thì restart policy vô dụng — không có máy để restart.Nhìn kỹ: mọi giới hạn của Compose đều quy về 1 từ — "1 host".
Compose: tất cả trứng trong 1 giỏ
┌───────────── 1 SERVER ─────────────┐
│ nginx php mariadb redis │
│ 🥚 🥚 🥚 🥚 │
└─────────────────┬───────────────────┘
│
💥 máy chết
│
▼
Toàn bộ app offline. Hết.Compose không sai — nó tuyệt cho dev, CI, app nhỏ 1 server (đúng như chặng trước kết luận). Vấn đề là khi app của bạn cần: nhiều máy, không downtime, tự co giãn, tự phục hồi cả khi cả máy chết — Compose hết đất diễn.
Đây là lúc cần một thứ đứng trên nhiều máy, điều phối container giữa chúng. Đó là Kubernetes.
Kubernetes là gì
Kubernetes (viết tắt K8s — đếm 8 chữ giữa K và s) là một nền tảng mã nguồn mở để tự động triển khai, mở rộng và quản lý ứng dụng container trên một cụm nhiều máy. Google viết ra (từ kinh nghiệm chạy container nội bộ hàng chục năm), rồi hiến cho Cloud Native Computing Foundation (CNCF) duy trì.
Từ khóa quan trọng nhất: orchestration — "điều phối". Compose chỉ chạy container. K8s điều phối chúng: đặt container nào lên máy nào, theo dõi sức khỏe, dời chỗ khi máy chết, thêm bản copy khi đông khách.
Compose (chạy): K8s (điều phối):
docker-compose.yml ┌──────────────────────┐
│ │ Bạn khai báo: │
▼ │ "Tôi muốn 3 bản │
chạy container │ nginx luôn sống" │
trên MÁY NÀY └──────────┬───────────┘
│
Hết. Bạn tự lo ▼
phần còn lại. K8s tự lo PHẦN CÒN LẠI:
• đặt 3 bản lên 3 máy khác nhau
• 1 bản chết → tạo bản mới
• 1 máy chết → dời sang máy khác
• đông khách → thêm bản thứ 4, 5...Đây là điểm thay đổi tư duy lớn nhất khi từ Compose sang K8s:
Compose = mệnh lệnh (imperative): "chạy 3 container này đi."
K8s = khai báo (declarative): "tôi muốn luôn có 3 bản. Bằng cách nào là việc của anh."
Bạn nói trạng thái mong muốn, K8s liên tục so sánh "thực tế vs mong muốn" và tự sửa cho khớp. Đây gọi là reconciliation loop — vòng lặp đối chiếu — và nó là linh hồn của K8s. Ghi nhớ từ này, ta sẽ gặp lại nó ở mọi bài sau.
K8s giải quyết gì — 8 siêu năng lực
Nếu phải thuyết phục sếp "vì sao trả tiền học cái khó này", đây là 8 thứ Compose không làm được:
- Tự triển khai & quản lý — không bật container bằng tay; K8s chạy đúng số lượng bạn khai báo, sai thì tự sửa.
- Tự cân bằng tải (Load Balancing) — request được rải đều cho các Pod còn sống. Không cần dựng HAProxy thủ công.
- Tự co giãn (Auto-scaling) —
HPA(Horizontal Pod Autoscaler) thêm/bớt Pod theo CPU/RAM;Cluster Autoscalerthêm/bớt cả máy. - Tự phục hồi (Self-healing) — Pod chết → tạo lại; cả node chết → dời Pod sang node khác. Đây là thứ Compose không bao giờ làm được.
- Cập nhật không downtime — Rolling Update thay từng Pod một; Blue-Green / Canary để test bản mới trước khi mở cho 100% khách.
- Tích hợp lưu trữ & mạng — gắn NFS, AWS EBS, Ceph...; điều khiển traffic nội bộ bằng Network Policy.
- Quản lý cấu hình & bảo mật —
ConfigMapcho config thường,Secretcho dữ liệu nhạy cảm,RBACđể phân quyền — không hardcode mật khẩu vào code. - Chạy mọi nơi — AWS, GCP, Azure, on-prem, hybrid. Cùng 1 bộ YAML, đổi chỗ chạy mà gần như không sửa.
⚠️ Đừng học thuộc 8 cái này như vẹt. Mỗi cái là 1 chủ đề ta sẽ mổ xẻ ở các bài sau (self-healing & scale ở Bài 03, Service & load balancing ở Bài 04, ConfigMap/Secret ở Bài 05). Giờ chỉ cần biết: đây là menu món ăn, bài sau ta nấu từng món.
K8s đứng ở đâu — Compose vs K8s
Để định vị rõ, đặt cạnh nhau "người tiền nhiệm" bạn vừa học xong:
Docker Compose Kubernetes
────────────── ──────────
Phạm vi: 1 host Cluster (nhiều máy)
Server chết: Toàn bộ app sập Pod tự dời sang node khác
Scale: Thủ công (--scale) Tự động (HPA + Cluster Autoscaler)
Self-healing: Cơ bản (restart) Nâng cao (reschedule cả node)
Update: Thường có downtime Rolling update, zero-downtime
Load balance: Không có sẵn Service tích hợp sẵn
Secret: .env (plain text) Secret object + RBAC
Học: Dễ (≈ 1 ngày) Khó (nhiều tuần)
Hợp với: Dev, CI, app nhỏ 1 máy Production quy mô lớn→ Không phải K8s "tốt hơn" Compose. Chúng giải bài toán khác cỡ. App nhỏ 1 server mà dựng K8s là lấy dao mổ trâu giết gà — tốn 3 máy, tốn công vận hành, chẳng được gì. Compose vẫn là lựa chọn đúng cho dev/CI. K8s chỉ xứng đáng khi bạn thật sự cần nhiều máy + không downtime + tự co giãn.
Tin tốt: bạn học Compose rồi nên K8s đã quen 50%. Service vẫn là service, volume vẫn là volume, mạng nội bộ vẫn resolve theo tên. Khác biệt chỉ là "1 máy" thành "cụm máy" — và một bộ vài thực thể (Pod, ReplicaSet, Deployment) làm trung gian.
Kiến trúc K8s — Bộ não & Tay chân
Một cluster K8s chia làm 2 loại node:
- Control Plane (còn gọi Master node) — bộ não, ra quyết định, không chạy app của bạn.
- Worker Node (data plane) — tay chân, nơi container của bạn thật sự chạy.
┌──────────────────────── CLUSTER ────────────────────────┐
│ │
│ ┌────────────────────┐ │
│ │ CONTROL PLANE │ ← Bộ não: quyết định mọi thứ │
│ │ (Master node) │ │
│ │ ┌───────────────┐ │ │
│ │ │ API Server │ │ cửa ngõ duy nhất │
│ │ │ etcd │ │ trí nhớ (DB) │
│ │ │ Scheduler │ │ xếp Pod vào node │
│ │ │ Controller Mgr│ │ giữ "mong muốn = thực tế" │
│ │ └───────┬───────┘ │ │
│ └──────────┼──────────┘ │
│ │ ra lệnh │
│ ┌────────┼─────────────┬──────────────┐ │
│ ▼ ▼ ▼ ▼ │
│ ┌────────┐┌────────┐ ┌────────┐ (hàng trăm node...) │
│ │WORKER 1││WORKER 2│ │WORKER 3│ ← Tay chân: chạy app │
│ │ Pod Pod││ Pod │ │ Pod Pod│ │
│ └────────┘└────────┘ └────────┘ │
└──────────────────────────────────────────────────────────┘Control Plane — bộ não
Bốn thành phần, mỗi cái một vai:
API Server (kube-apiserver) — cửa ngõ.
Mọi thứ đi qua đây. kubectl, dashboard, các controller, kubelet trên worker — tất cả nói chuyện với cluster qua API Server. Đây là cổng vào duy nhất. Nhớ kỹ điều này, nó là chìa khóa hiểu cả luồng bên dưới.
etcd — trí nhớ của cluster.
Một database dạng key-value, lưu toàn bộ trạng thái cluster: có bao nhiêu Pod, đang ở node nào, config gì, secret gì. Đây là "nguồn sự thật duy nhất". ⚠️ Mất etcd = mất cả cluster — production phải backup etcd định kỳ. Và chỉ API Server được nói chuyện trực tiếp với etcd — không component nào khác chạm vào.
Scheduler (kube-scheduler) — người xếp chỗ.
Quyết định Pod mới sẽ chạy trên node nào, dựa trên tài nguyên còn trống (CPU, RAM), taints, affinity... Ví dụ: Node A còn 4GB RAM trống, Pod cần 1GB → Scheduler đặt Pod vào A. Scheduler không tự đi chạy Pod — nó chỉ quyết định chỗ, rồi báo lại API Server.
Controller Manager (kube-controller-manager) — người giữ lời hứa.
Gồm nhiều controller nhỏ, mỗi cái chạy 1 vòng lặp đối chiếu (reconciliation loop): liên tục so sánh "bạn muốn 3 Pod" với "thực tế đang có mấy Pod", thiếu thì tạo, thừa thì xóa. Đây chính là cái máy biến lời khai báo của bạn thành hiện thực.
Cloud Controller Manager (cloud-controller-manager) — cầu nối với cloud (chỉ có khi chạy trên cloud).
Khi cluster chạy trên AWS/GCP/Azure, đây là thành phần nói chuyện với API của nhà cung cấp: tạo LoadBalancer thật, gắn ổ đĩa cloud (EBS, Persistent Disk), cập nhật route. Chạy on-prem (như capstone Bài 05) thì không có thằng này — và đó chính là lý do on-prem phải tự cài MetalLB để có LoadBalancer (ta sẽ gặp ở Bài 05).
Worker Node — tay chân
Nơi app của bạn thật sự chạy. Ba thành phần:
Kubelet — quản đốc trên mỗi máy.
Agent chạy trên mọi worker. Nhận lệnh từ API Server ("chạy Pod này đi"), rồi đảm bảo container đúng như yêu cầu đang sống. Báo trạng thái ngược lại API Server.
Kube Proxy — người gác mạng.
Lo networking: giúp Pod gọi nhau trong cùng node và giữa các node, điều phối traffic theo Service (ClusterIP, NodePort, LoadBalancer). Ta sẽ đào sâu ở Bài 04.
Container Runtime — động cơ chạy container.
Phần thật sự chạy container: containerd, CRI-O, hoặc runtime bất kỳ tuân theo chuẩn CRI (Container Runtime Interface).
⚠️ Điểm hay gây hiểu nhầm: K8s KHÔNG dùng Docker. Từ K8s 1.24+, Docker bị bỏ khỏi runtime trực tiếp. K8s dùng containerd — đúng cái "phần ruột" chạy container nằm bên trong Docker. Nghĩ vậy: Docker = containerd + CLI + build + nhiều thứ tiện cho người. K8s chỉ cần phần containerd. Image bạn build bằng Docker ở chặng trước vẫn chạy ngon trên K8s — vì cùng chuẩn OCI. (Ta cài containerd thật trong capstone Bài 05.)
Addon — thứ cluster cần thêm để thật sự "sống"
Control plane + worker dựng xong vẫn chưa đủ chạy. Hai addon gần như bắt buộc:
- CNI (Container Network Interface) — plugin mạng (Flannel, Calico, Cilium). Chưa cài CNI thì các Pod ở khác node không nói chuyện được với nhau, và node sẽ kẹt ở trạng thái
NotReady. Đây là lý do ở capstone, ngay sau khi dựng cluster bạn sẽ thấy mọi nodeNotReadycho tới khikubectl applyCNI. K8s không kèm sẵn CNI — bạn tự chọn và cài. - CoreDNS — DNS nội bộ của cluster. Đây là thứ biến
mysql-servicethành một cái tên gọi được thay vì phải nhớ IP. Nhớ "DNS auto giữa các service" ở chặng Compose chứ? CoreDNS chính là phiên bản cluster của nó. Thường được kèm sẵn khikubeadm init.
→ Tạm ghi nhớ: node NotReady ngay sau khi dựng là bình thường — chờ cài CNI. Chi tiết ở Bài 05.
Một request đi qua cluster thế nào
Đây là sơ đồ tôi muốn bạn nhớ nhất cả bài. Khi bạn gõ kubectl apply, chuyện gì xảy ra bên trong:
1. Admin gõ: kubectl apply -f app.yaml ("tôi muốn 1 Pod nginx")
│
▼
2. API Server nhận, GHI "mong muốn" vào etcd
│
▼
3. Scheduler thấy có Pod chưa được xếp chỗ.
Hỏi: "đặt vào node nào?"
→ KHÔNG đi hỏi từng worker (cluster có thể hàng trăm node!)
→ Đọc trạng thái cluster QUA API Server (← etcd) xem node nào còn trống
→ Chọn: "Worker 2" → báo lại API Server
│
▼
4. API Server gọi kubelet trên Worker 2: "chạy Pod này"
│
▼
5. Kubelet sai container runtime (containerd) khởi chạy container → Pod UP
│
▼
6. Kubelet báo trạng thái "đã chạy" ngược về API Server → ghi vào etcd
│
▼
Thực tế giờ KHỚP mong muốn. Vòng lặp đối chiếu hài lòng. ✅💡 Bài học vàng từ sơ đồ này: Mọi đường đều đi qua API Server, và chỉ API Server chạm etcd. Scheduler, controller, kubelet — không ai nói chuyện trực tiếp với nhau hay với etcd. Tất cả qua "cửa ngõ" API Server. Hiểu điều này thì sau này debug bạn biết đi soi đúng chỗ.
(Tài liệu nguồn có ghi "scheduler lấy dữ liệu từ etcd" — nói cho gọn thì hiểu được, nhưng chính xác là scheduler đọc qua API Server, còn API Server mới là cái duy nhất đọc/ghi etcd. Phân biệt nhỏ này quan trọng khi bạn lên level.)
Cài đặt K8s — 2 con đường
Dựng một cluster thật khó hơn apt install nhiều — phải lo containerd, mạng CNI, certificate TLS, join node... Có 2 con đường phổ biến:
kubeadm Kubespray
─────── ─────────
Là gì: Tool CHÍNH THỨC của K8s Bộ playbook Ansible
Cách dùng: Gõ lệnh từng bước thủ công Khai báo inventory, chạy 1 phát
Học được: Hiểu RÕ từng mảnh ghép Nhanh, nhưng "hộp đen" hơn
Hợp với: Học, cluster nhỏ-vừa Nhiều cluster, nhiều môi trường- kubeadm — công cụ chính thức, dựng cluster tối giản nhưng chạy được: tạo control plane (API Server, Controller, Scheduler), join worker, lo certificate & token, dựng networking cơ bản. Đây là cách nên học đầu tiên vì bạn thấy rõ từng bước.
- Kubespray — dùng Ansible tự động hóa toàn bộ, chạy được trên bare-metal/cloud/VM. Nhanh và lặp lại được, nhưng giấu bớt chi tiết — hợp khi bạn đã hiểu nền tảng và cần dựng nhiều cluster.
→ Lời khuyên: học bằng kubeadm trước. Hiểu rồi mới dùng Kubespray cho tiện. Bản hướng dẫn dựng cluster on-prem hoàn chỉnh bằng kubeadm (containerd → CNI → MetalLB → Ingress → Storage) là capstone Bài 05 của chặng này — đừng vội, ta sẽ làm tới nơi tới chốn.
Một lối thứ ba: managed K8s
Ngoài tự dựng (kubeadm/Kubespray), trên cloud có managed K8s — nhà cung cấp lo hộ phần control plane:
Tự dựng (on-prem) Managed (cloud)
───────────────── ───────────────
Control plane: Bạn tự cài & vá Nhà cung cấp lo, ẩn đi
Ví dụ: kubeadm trên VM EKS (AWS), GKE (GCP), AKS (Azure)
Bạn quản: Mọi thứ Chỉ worker node + app
Hợp với: Học, on-prem, kiểm soát hoàn toàn Lên prod nhanh, đỡ vận hành→ Managed nhanh và đỡ đau đầu, nhưng giấu mất phần hay nhất để học. Vì vậy chặng này ta tự dựng để hiểu tận ruột; ngoài đời, production thật nhiều team chọn managed cho nhẹ gánh vận hành.
kubectl & kubeconfig — cây gậy điều khiển
kubectl là công cụ dòng lệnh bạn dùng để ra lệnh cho cluster. Nhưng nó biết "nói chuyện với cluster nào, bằng danh tính gì" nhờ một file: kubeconfig, mặc định ở ~/.kube/config.
~/.kube/config chứa 3 thứ:
clusters → địa chỉ API Server + chứng chỉ CA (cluster nào)
users → danh tính của bạn (cert/token để xác thực)
contexts → ghép (cluster + user + namespace) thành 1 "ngữ cảnh"Một context = "tôi đang trỏ vào cluster nào, với tư cách ai, namespace mặc định nào". Ai làm việc với nhiều cluster (dev/staging/prod) sẽ chuyển context liên tục:
kubectl config get-contexts # liệt kê các context đang có
kubectl config current-context # đang ở context nào?
kubectl config use-context prod # chuyển sang cluster prod⚠️ Tai nạn kinh điển: gõ kubectl delete tưởng đang ở dev, hóa ra context đang trỏ prod. Luôn liếc current-context trước khi gõ lệnh phá. (Mẹo: cài kubectx/kubens hoặc hiện context lên prompt shell.)
🚀 Lab — Nhìn vào bụng một cluster
Chưa cần dựng cluster prod 3 máy (để dành Bài 05). Để chạy kubectl ngay hôm nay, dựng 1 cluster "đồ chơi" 1 node bằng kind (Kubernetes IN Docker) — nó chạy cả cluster bên trong... container Docker. Đẹp ở chỗ: kiến thức Docker chặng trước dùng được luôn.
Dựng cluster đồ chơi
# Cài kind (cần Docker đã có sẵn từ chặng trước)
curl -Lo ./kind https://kind.sigs.k8s.io/dl/latest/kind-linux-amd64
chmod +x ./kind && sudo mv ./kind /usr/local/bin/kind
# Cài kubectl — "remote control" để ra lệnh cho cluster
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# Dựng cluster 1 node — 30 giây
kind create cluster --name labKhám phá kiến trúc bạn vừa học
# 1. Có mấy node? (cluster đồ chơi này gộp control plane + worker vào 1)
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# lab-control-plane Ready control-plane 1m v1.30.x
# 2. NHÌN THẤY bộ não — các thành phần control plane chạy ở đây:
kubectl get pods -n kube-system
# Bạn sẽ thấy: kube-apiserver, etcd, kube-scheduler,
# kube-controller-manager, kube-proxy, coredns...
# → đúng 4 thành phần Control Plane + kube-proxy ta vừa học!
# 3. Tổng quan cluster — API Server đang nghe ở đâu
kubectl cluster-info
# 4. Soi 1 node: tài nguyên, Pod đang chạy, điều kiện Ready
kubectl describe node lab-control-plane→ Khoảnh khắc "à há": cái kubectl get pods -n kube-system cho bạn thấy tận mắt API Server, etcd, scheduler, controller manager đang chạy — chính 4 hộp trong sơ đồ "bộ não" ở trên. Lý thuyết vừa học không còn trừu tượng.
Dọn dẹp
kind delete cluster --name lab(Bài 02 ta sẽ dùng chính cluster kind này để nghịch Pod. Cứ giữ lại nếu muốn học liền mạch.)
Câu chuyện thực tế
Vẫn cái startup 6 dev ở chặng trước. Sau khi Compose cứu chúng tôi khỏi địa ngục onboarding, mọi thứ êm được gần 1 năm. Cho tới một tối thứ Sáu.
Server production — 1 con VM duy nhất chạy nguyên stack Compose — bị nhà cung cấp bảo trì hạ tầng ngoài kế hoạch. Reboot. Stack lên lại, nhưng MariaDB không init kịp, PHP connect fail, app trả 502. Lúc đó 21:47, cao điểm đặt hàng cuối tuần.
Tôi cầm điện thoại SSH vào, docker compose restart thủ công, canh thứ tự, đợi healthcheck. Mất 18 phút mới xanh hết. 18 phút đó:
- ~40 đơn hàng rớt giỏ (khách thấy lỗi là đóng tab).
- 1 khách lớn nhắn sếp tôi: "web sập à?" — câu mà không founder nào muốn đọc lúc 10 giờ tối.
- Tôi nhận ra điều đáng sợ nhất:
restart: unless-stoppedvô dụng khi cả cái máy biến mất. Không có máy thì restart cái gì?
Tuần sau tôi dành 4 ngày dựng cluster K8s 3 node (1 control plane + 2 worker) bằng kubeadm, migrate stack sang Deployment + Service. Lần kế tiếp 1 worker chết (tôi cố tình poweroff để test): K8s tự dời Pod sang worker còn lại trong ~30 giây, traffic không gián đoạn vì còn bản copy đang sống. Tôi ngồi nhìn kubectl get pods --watch và lần đầu hiểu chữ self-healing nghĩa là gì.
4 ngày đầu tư đổi lấy: ngủ ngon. Không còn cú điện thoại 3 giờ sáng.
Bài học:
Compose không sai — nó chỉ hết đất khi bạn cần >1 máy. Đừng chê Compose; biết khi nào nó chạm trần mới là kỹ năng.
Single point of failure giết bạn lúc bạn ngủ. 1 server = 1 quả bom hẹn giờ. Self-healing của K8s không phải "tính năng cho oai", nó là giấc ngủ của bạn.
Đo bằng tiền và bằng đêm mất ngủ, không phải bằng độ "ngầu". 4 ngày học K8s chỉ đáng nếu nỗi đau đủ lớn. Với startup đang scale thì quá đáng. Với blog cá nhân thì... cứ Compose.
Test self-healing bằng cách cố tình phá. Tôi chỉ thật sự tin K8s sau khi tự tay
poweroff1 node và thấy nó hồi phục. Đừng tin lý thuyết — hãy break nó.Học kiến trúc TRƯỚC khi học lệnh. Đêm đó tôi debug được nhanh ở các sự cố sau là vì hiểu "ai làm gì": lỗi mạng → soi kube-proxy/CNI; Pod không lên → soi scheduler/kubelet; cluster mất trí nhớ → soi etcd. Không có bản đồ kiến trúc thì debug như mò kim.
Pitfalls
Nghĩ K8s thay thế Docker. Sai. K8s điều phối, container runtime (containerd) mới chạy. Image Docker của bạn vẫn dùng được.
Dùng K8s cho app nhỏ 1 container. Overkill kinh điển. Tốn 3 máy + công vận hành để chạy thứ Compose làm trong 1 dòng. Hỏi "tôi có thật sự cần nhiều máy không?" trước.
Quên tắt swap. Kubelet yêu cầu swap off, nếu không sẽ refuse to start hoặc hành xử khó lường. (Ta xử lý kỹ ở Bài 05.)
Chỉ 1 control plane trong production. etcd thành single point of failure. Production cần ≥3 control plane cho HA (số lẻ để bầu leader).
Không backup etcd. Mất etcd = mất toàn bộ trạng thái cluster, không khôi phục được. Backup định kỳ là bắt buộc.
Tưởng scheduler đi hỏi từng worker. Không — nó đọc trạng thái qua API Server (← etcd). Cluster trăm node mà hỏi từng máy thì sập ngay.
Cgroup driver lệch nhau (systemd vs cgroupfs giữa kubelet và containerd) → kubelet crash loop. Phải bật
SystemdCgroup = truecho containerd. (Bài 05.)Version skew. kubeadm/kubelet/kubectl lệch version quá xa → lỗi khó hiểu. Giữ chúng cùng minor version, và
apt-mark holdđể không tự upgrade.Debug sai tầng vì không hiểu kiến trúc. Pod không lên mà đi soi mạng, lỗi mạng mà đi soi scheduler → mất hàng giờ. Bản đồ "ai làm gì" giúp bạn nhắm đúng chỗ.
Học K8s mà bỏ qua nền Compose/Docker. K8s là "Compose ở cluster scale" — bỏ nền thì 50% kiến thức bạn phải học lại từ đầu một cách khổ sở.
Coi node Control Plane là chỗ chạy app. Mặc định control plane bị "taint" để không nhận Pod thường — bộ não nên để dành cho việc ra quyết định, không gánh tải app.
Gõ lệnh phá khi context đang trỏ nhầm cluster.
kubectl deleteở "tưởng dev" mà thực ra là prod = thảm họa. Liếckubectl config current-contexttrước.Tưởng dựng xong control plane là chạy được luôn. Thiếu CNI → node
NotReadymãi, Pod không lên. Thiếu CoreDNS → gọi nhau bằng tên service không được. Addon không phải tùy chọn.
Tóm tắt
- K8s = orchestration: tự triển khai, scale, quản lý container trên một cụm nhiều máy. Google viết, CNCF duy trì.
- Vì sao vượt Compose: Compose chạm trần ở 1 host — máy chết là app chết. K8s self-healing cả khi cả node chết, tự scale, update không downtime.
- Tư duy cốt lõi: Compose imperative ("chạy đi"), K8s declarative ("tôi muốn 3 bản, tự lo"). Vòng lặp đối chiếu (reconciliation) liên tục đưa thực tế khớp mong muốn.
- 2 loại node: Control Plane (bộ não) + Worker (tay chân, chạy app).
- Control Plane: API Server (cửa ngõ), etcd (trí nhớ), Scheduler (xếp chỗ), Controller Manager (giữ lời hứa) — thêm Cloud Controller Manager khi chạy cloud.
- Worker 3 thành phần: kubelet (quản đốc), kube-proxy (gác mạng), container runtime (động cơ — containerd, không phải Docker).
- Addon bắt buộc: CNI (mạng Pod — thiếu thì node
NotReady) và CoreDNS (DNS nội bộ). - Quy tắc vàng: mọi thứ qua API Server; chỉ API Server chạm etcd.
- kubectl + kubeconfig (
~/.kube/config): context = ghép (cluster + user + namespace). Luôn kiểm tracurrent-contexttrước khi gõ lệnh phá. - Cài đặt: kubeadm (chính thức, học rõ từng bước) vs Kubespray (Ansible, nhanh) vs managed (EKS/GKE/AKS, cloud lo control plane). Học kubeadm trước.
- Khi nào dùng K8s: chỉ khi thật sự cần nhiều máy + không downtime + tự co giãn. App nhỏ → Compose vẫn đúng.
Bài sau (Bài 02 — Pod & kubectl) ta đi xuống tầng thấp nhất: Pod — đơn vị nhỏ nhất K8s biết tới, "vỏ bọc" quanh container của bạn. Ta sẽ tạo Pod đầu tiên từ YAML, vào shell, đọc log, debug khi nó CrashLoopBackOff — tức là làm với K8s những việc bạn đã quen làm với docker run, nhưng bằng tư duy khai báo.
Nếu hôm nay bạn nhìn kubectl get pods -n kube-system và chỉ mặt được API Server, etcd, scheduler — bạn đã có bản đồ. Phần còn lại của chặng chỉ là điền chi tiết vào bản đồ đó.
— Minh Hưng