K8s 4 — Kiến trúc Kubernetes

13 thg 7, 2026 3 lượt xem
#kubernetes
#devops
#etcd
#scheduler
#control-plane
#kubelet

Từ Compose đến Kubernetes: khi một máy là không đủ

Ở bài Docker Compose & mạng, chúng ta đã điều phối nhiều container trên một máy bằng một file docker-compose.yml. Compose rất tốt cho môi trường dev và cho những hệ thống nhỏ chạy gọn trên một host. Nhưng đời thực thì tàn nhẫn hơn:

  • Máy chạy Compose chết lúc 3 giờ sáng — ai bật lại toàn bộ service? Trên máy nào?
  • Lượng truy cập tăng gấp 10 — làm sao rải các bản sao (replica) của service ra nhiều máy để chịu tải?
  • Bạn có 200 container cần chạy trên 12 server — ai quyết định container nào chạy ở đâu để tận dụng CPU/RAM cho hợp lý?
  • Một container crash — ai phát hiện và khởi động lại ở nơi còn tài nguyên?

Compose không trả lời được những câu này vì nó chỉ biết về một máy. Cần một hệ thống điều phối ở tầng cụm nhiều máy (cluster). Đó chính là Kubernetes.

Kubernetes là gì

Kubernetes (viết tắt K8s) là một hệ điều phối container (container orchestrator): nó gom nhiều máy chủ lại thành một "máy tính khổng lồ" logic và tự động lo việc:

  • Triển khai (deploy): đặt container lên máy nào, với bao nhiêu bản sao.
  • Mở rộng (scale): tăng/giảm số bản sao theo tải.
  • Tự phục hồi (self-healing): container chết thì khởi động lại; máy chết thì dời container sang máy khác.
  • Cân bằng tải & khám phá dịch vụ (service discovery): cho các service tìm thấy nhau qua tên ổn định dù IP thay đổi.
  • Cập nhật cuốn chiếu (rolling update): đổi phiên bản mới mà không gián đoạn.

Điểm khác biệt cốt lõi so với Compose: bạn không ra lệnh từng bước ("chạy container này trên máy kia"). Bạn chỉ mô tả kết quả bạn muốn, và Kubernetes tự tìm cách đạt được nó — đó là mô hình khai báo.

Nếu bạn mới làm quen Pod/Deployment/Service ở mức tổng quan, xem trước bài DevOps — Kubernetes cơ bản. Bài này đi sâu vào kiến trúc bên trong.


Mô hình khai báo & vòng điều khiển (reconciliation)

Đây là tư tưởng nền tảng, hiểu nó thì mọi thứ còn lại sáng ra.

Mô hình mệnh lệnh (imperative) — kiểu Compose/script thủ công — bạn ra từng lệnh: "tạo container A", "khởi động lại B", "thêm 2 bản sao C". Bạn chịu trách nhiệm cho từng bước.

Mô hình khai báo (declarative) — kiểu Kubernetes — bạn viết ra trạng thái mong muốn (desired state) trong một file YAML (gọi là manifest), ví dụ: "tôi muốn 3 bản sao của web đang chạy phiên bản v2". Bạn giao bản mô tả đó cho cluster. Việc làm sao để đạt được nó là chuyện của Kubernetes.

Cơ chế biến mong muốn thành hiện thực là vòng điều khiển (control loop / reconciliation loop). Trong Kubernetes có nhiều controller, mỗi cái chạy một vòng lặp bất tận:

lặpii {
    desired  = trạng thái mong muốn (đọc từ etcd qua API server)
    actual   = trạng thái thực tế (đang chạy trong cluster)
    nếu actual != desired:
        thực hiện hành động để kéo actual về gần desired
}

Ví dụ: bạn khai báo replicas: 3 nhưng thực tế chỉ có 2 Pod đang chạy (một cái vừa crash). Controller phát hiện desired (3) ≠ actual (2) → tạo thêm 1 Pod. Đây chính là "self-healing" — không có phép màu, chỉ là một vòng lặp so sánh và sửa sai chạy liên tục.

Hệ quả quan trọng: Kubernetes hội tụ (converge) về trạng thái mong muốn chứ không thực thi một chuỗi lệnh một lần rồi thôi. Bạn xoá tay một Pod do Deployment quản lý? Nó mọc lại ngay, vì desired vẫn là 3. Muốn thật sự giảm còn 2, bạn phải sửa desired state, không phải đi xoá thủ công.


Toàn cảnh: Control Plane + Node

Một cluster Kubernetes gồm hai loại thành phần:

  1. Control plane ("bộ não") — ra quyết định, giữ trạng thái, điều phối. Thường chạy trên các máy riêng (control-plane node), và trong môi trường production thường có nhiều bản để đảm bảo sẵn sàng cao (HA).
  2. Node / worker ("cơ bắp") — nơi các container thật sự chạy. Cluster có thể có từ vài đến hàng nghìn node.

Sơ đồ dưới đây thể hiện các bộ phận và luồng tạo một Pod:


Control Plane — bộ não của cluster

kube-apiserver — cửa ngõ duy nhất

kube-apiserverfront-end của cluster, phơi bày một API HTTP kiểu REST. Quy tắc vàng: mọi thứ đi qua API server. Bạn (qua kubectl), các controller, scheduler, kubelet trên node — tất cả đều nói chuyện với cluster thông qua API server, không ai đọc/ghi trực tiếp vào kho dữ liệu.

Khi một yêu cầu đến, API server:

  • Xác thực (authentication): bạn là ai?
  • Phân quyền (authorization): bạn được phép làm gì? (RBAC)
  • Admission control: kiểm tra/điều chỉnh đối tượng trước khi lưu.
  • Ghi vào etcd nếu hợp lệ.

Vì API server là điểm nghẽn logic của toàn hệ thống, trong production nó thường được chạy nhiều bản sau một load balancer.

etcd — nguồn sự thật duy nhất

etcd là một kho key-value nhất quán và sẵn sàng cao, dùng làm nơi lưu toàn bộ trạng thái cluster: mọi đối tượng (Pod, Deployment, Service, ConfigMap, Secret...), cấu hình và trạng thái của chúng.

Đây là source of truth — nếu etcd mất, cluster mất trí nhớ. Vì vậy trong vận hành thật:

  • etcd được chạy theo cụm lẻ (3, 5 node) dùng thuật toán đồng thuận Raft.
  • Phải backup etcd định kỳluyện tập khôi phục — đây là một trong những việc quan trọng nhất của vận hành, sẽ nói kỹ ở bài Vận hành production.

Chỉ API server được nói chuyện trực tiếp với etcd. Đây là thiết kế có chủ đích: mọi truy cập trạng thái đều đi qua một cửa để dễ kiểm soát, xác thực và ghi log.

kube-scheduler — người xếp chỗ

Khi một Pod mới được tạo mà chưa được gán node (nodeName còn trống), kube-scheduler phát hiện và chọn node phù hợp cho nó. Nó cân nhắc nhiều yếu tố:

  • Tài nguyên: node có đủ CPU/RAM đáp ứng requests của Pod không?
  • Ràng buộc: nodeSelector, taints/tolerations, affinity/anti-affinity (ví dụ "đừng đặt 2 bản sao cùng một node").
  • Các yếu tố khác: data locality, độ ưu tiên, deadline...

Lưu ý: scheduler không tự đặt container lên máy. Nó chỉ ghi quyết định (gán node) trở lại qua API server. Việc chạy thật là của kubelet.

kube-controller-manager — nơi các vòng lặp trú ngụ

kube-controller-manager là một tiến trình chứa nhiều controller được gộp chung vào một binary cho gọn. Mỗi controller là một vòng reconciliation cho một loại đối tượng, ví dụ:

  • Node controller: theo dõi node còn sống không; node "mất tích" thì xử lý các Pod trên đó.
  • ReplicaSet controller: giữ đúng số bản sao Pod như mong muốn.
  • Deployment controller: điều phối rolling update, tạo/thu ReplicaSet.
  • ... và nhiều controller khác (Job, endpoints, service account...).

Đây chính là nơi tư tưởng "desired vs actual" được hiện thực hoá. Chi tiết các workload (Deployment, ReplicaSet, StatefulSet...) ở bài Workloads.

cloud-controller-manager — cầu nối với cloud (tuỳ chọn)

cloud-controller-manager tách phần logic gắn với nhà cung cấp cloud (tạo load balancer, gắn volume, quản lý route mạng...) ra riêng. Nếu bạn chạy Kubernetes trên máy tự dựng (on-prem), thành phần này có thể không có.


Node (worker) — nơi container thật sự chạy

Mỗi node là một máy (vật lý hoặc ảo) chạy các thành phần sau:

kubelet — agent trên node

kubeletđại diện của control plane trên mỗi node. Nhiệm vụ:

  • Nhận thông tin các Pod được gán cho node này (từ API server).
  • Đảm bảo container trong Pod đang chạy đúng như mô tả — gọi container runtime để tạo/khởi động/dừng container.
  • Chạy health check (liveness/readiness probe) và báo cáo sức khoẻ của Pod và node trở lại API server liên tục.

kubelet chỉ quản lý các container do Kubernetes tạo, không quản lý container bạn tự chạy tay bằng Docker trên máy đó.

container runtime — người chạy container qua CRI

kubelet không tự tay tạo container; nó ra lệnh cho container runtime làm việc đó. Giao tiếp giữa kubelet và runtime tuân theo một chuẩn gọi là CRI (Container Runtime Interface) — một API thống nhất cho phép Kubernetes làm việc với nhiều runtime khác nhau. Các runtime phổ biến tuân thủ CRI:

  • containerd
  • CRI-O

(Docker Engine ngày nay không còn được kubelet gọi trực tiếp; nền tảng bên dưới Docker vốn dựa trên containerd.) Điều bạn cần nhớ: nhờ CRI, Kubernetes không bị khoá vào một runtime cụ thể.

kube-proxy — mạng cho Service

kube-proxy duy trì các quy tắc mạng trên node để hiện thực hoá đối tượng Service (định tuyến và cân bằng tải tới các Pod đứng sau một địa chỉ ảo ổn định). Trong tài liệu chính thức, kube-proxy được đánh dấu là tuỳ chọn: một số plugin mạng (CNI) có thể tự cung cấp chức năng tương đương, khi đó có thể không cần kube-proxy. Chi tiết Service/mạng ở bài Networking & Services.


Các đối tượng cơ bản

Bạn điều khiển Kubernetes bằng cách khai báo các đối tượng (object) trong manifest YAML:

  • Podđơn vị triển khai nhỏ nhất. Một Pod bọc một (hoặc vài) container chia sẻ chung mạng và storage. Kubernetes không chạy container "trần"; nó luôn chạy chúng bên trong Pod.
  • Các cấp cao hơn — bạn hiếm khi tạo Pod trực tiếp. Bạn tạo Deployment (và qua đó ReplicaSet), StatefulSet, DaemonSet, Job... — chúng tạo và quản lý Pod giùm bạn (số bản sao, tự phục hồi, cập nhật). Xem bài Workloads.
  • Namespace — chia cluster thành các "không gian" logic để cô lập và tổ chức tài nguyên (ví dụ dev, staging, prod).
  • Label & selector — gắn nhãn key-value lên đối tượng (app: web) rồi dùng selector để nhóm/chọn chúng. Đây là "chất keo" nối Deployment ↔ Pod ↔ Service.

Manifest tối giản cho một Pod (minh hoạ):

# (minh hoạ)
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    app: web
spec:
  containers:
    - name: nginx
      image: nginx:1.27
      ports:
        - containerPort: 80

Luồng tạo một Pod (từng bước)

Ghép mọi thứ lại, đây là điều xảy ra khi bạn apply manifest trên (bám theo sơ đồ mermaid ở trên):

  1. kubectl apply gửi manifest tới kube-apiserver.
  2. API server xác thực/phân quyền, rồi ghi đối tượng Pod vào etcd. Lúc này Pod tồn tại nhưng chưa gán node.
  3. kube-scheduler đang theo dõi, thấy Pod chưa có node → chọn node phù hợp và ghi quyết định (gán node) trở lại qua API server (vào etcd).
  4. kubelet trên node được chọn nhận biết có Pod dành cho mình (qua API server).
  5. kubelet gọi container runtime qua CRI để kéo image và tạo container.
  6. Runtime tạo và chạy container.
  7. kubelet báo cáo trạng thái Pod (Running/Ready...) trở lại API server, ghi vào etcd. kubectl get pod giờ hiện Running.

Chú ý mẫu hình lặp lại: không thành phần nào ra lệnh trực tiếp cho thành phần khác. Chúng theo dõi (watch) API server và phản ứng với thay đổi trạng thái. API server + etcd là "bảng thông báo" trung tâm; scheduler và kubelet là những người quan sát bảng đó và hành động. Kiến trúc "level-triggered qua trạng thái chung" này chính là thứ làm Kubernetes bền bỉ và tự phục hồi.


kubectl cơ bản

kubectl là công cụ dòng lệnh để nói chuyện với API server. Vài lệnh cốt lõi (minh hoạ):

# (minh hoạ)
# Áp dụng trạng thái mong muốn từ file
kubectl apply -f pod.yaml

# Liệt kê Pod (thêm -o wide để thấy node, -A để xem mọi namespace)
kubectl get pods -o wide

# Xem chi tiết + sự kiện của một đối tượng (rất hữu ích khi debug)
kubectl describe pod nginx

# Xem log của container trong Pod
kubectl logs nginx -f

# Chọn cluster/namespace đang thao tác
kubectl config get-contexts
kubectl config use-context prod-cluster

Context cho biết kubectl đang trỏ tới cluster nàonamespace nào. Nhầm context là cách kinh điển để "vô tình apply lên production" — luôn kiểm tra kubectl config current-context trước các thao tác nguy hiểm.

Lưu ý môi trường: sandbox của loạt bài này chỉ có PostgreSQL, không có cluster Kubernetes, nên các lệnh kubectl và YAML ở đây là minh hoạ — bạn cần một cluster thật (minikube, kind, hay managed) để chạy.


Use case thực tế

Điều gì xảy ra khi bạn apply một Deployment. Bạn khai báo replicas: 3. Manifest vào API server → etcd. Deployment controller thấy có Deployment mới → tạo một ReplicaSet. ReplicaSet controller thấy desired=3, actual=0 → tạo 3 đối tượng Pod (chưa có node). Scheduler gán 3 Pod đó cho các node còn tài nguyên. kubelet ở mỗi node kéo image và chạy container. Kết quả: 3 bản sao chạy rải trên cluster, mà bạn chỉ viết ra "tôi muốn 3 bản".

Node chết thì sao? Giả sử node B mất kết nối (mất điện, hỏng mạng). kubelet trên B ngừng gửi heartbeat. Node controller sau một khoảng chờ đánh dấu node B là NotReady, rồi coi các Pod trên đó là mất. Với Pod thuộc một ReplicaSet: giờ actual (2) < desired (3) → controller tạo Pod thay thế → scheduler đặt lên node còn sống → dịch vụ tự hồi phục. Đây là self-healing ở cấp cluster, tất cả nhờ vòng reconciliation. (Lưu ý: dữ liệu trên local disk của node chết không tự chuyển theo — đó là lý do state cần lưu ngoài, sẽ bàn ở Vận hành production.)


Managed Kubernetes

Tự dựng và vận hành control plane (đặc biệt là etcd HA) khá nặng. Vì vậy các cloud lớn cung cấp managed Kubernetes, lo phần control plane giùm bạn, bạn chỉ tập trung vào workload:

  • Amazon EKS (AWS)
  • Google GKE (GCP)
  • Azure AKS (Azure)

Với chúng, control plane được quản lý (bạn không thấy/không phải vá etcd, API server), còn node thì bạn hoặc cloud quản lý.


Ghi nhớ

  • Kubernetes = hệ điều phối container ở cấp nhiều máy: deploy, scale, self-healing, service discovery — thứ Compose (một máy) không làm được.
  • Khai báo, không mệnh lệnh: bạn mô tả desired state trong YAML; các controller chạy vòng reconciliation để kéo actual state về khớp. Xoá tay Pod do Deployment quản lý → nó mọc lại.
  • Control plane = bộ não: kube-apiserver (cửa ngõ duy nhất, mọi thứ đi qua đây) · etcd (source of truth, cần backup) · kube-scheduler (chọn node) · kube-controller-manager (các vòng lặp) · cloud-controller-manager (tuỳ chọn).
  • Node = cơ bắp: kubelet (chạy & báo cáo Pod) · container runtime (containerd/CRI-O qua CRI) · kube-proxy (mạng Service, tuỳ chọn).
  • Pod là đơn vị nhỏ nhất; thực tế bạn dùng Deployment và các workload cấp cao. Namespace để cô lập, label/selector để nối các đối tượng.
  • Luồng tạo Pod: kubectl apply → apiserver ghi etcd → scheduler gán node → kubelet gọi runtime tạo container → báo cáo trạng thái. Không ai ra lệnh trực tiếp cho ai — mọi thứ watch trạng thái chung.
  • kubectl apply/get/describe/logs là bộ lệnh sống còn; luôn kiểm tra context trước thao tác nguy hiểm.

Tiếp theo: đi sâu vào Workloads (Deployment, ReplicaSet, StatefulSet, DaemonSet, Job), sau đó là Networking & Services.


Nguồn tham khảo: tài liệu chính thức kubernetes.io — Kubernetes ComponentsCluster Architecture.

Bài viết liên quan

Continuous Integration/Delivery/Deployment, cấu trúc pipeline, ví dụ GitHub Actions và chiến lược release.

13 thg 7, 2026 4

Container vs máy ảo, image/layer, Dockerfile, volume, network, Docker Compose và best practices.

13 thg 7, 2026 3

Vì sao cần orchestration; Pod, Deployment, Service, Ingress; scaling, self-healing và cấu hình.

13 thg 7, 2026 3

Bản chất DevOps: phá bỏ rào cản Dev–Ops, vòng lặp vô tận, CALMS, và vì sao tự động hoá.

13 thg 7, 2026 3