jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Docker for Developers · Part 9 — Kubernetes Fundamentals

Từ một host tới cluster: kiến trúc Kubernetes, Pod, Deployment, Service, kubectl, kind và lần deploy ứng dụng đầu tiên.

9 MIN READ Updated JUL 11, 2026

Đây là Phần 9 của chặng nền tảng về Docker → Compose → Kubernetes. Docker Compose chạy container trên một máy — bạn khai báo service trong YAML và docker compose up bật cả stack (Phần 5, Phần 6). Đủ cho dev local và nhiều triển khai nhỏ. Khi cần nhiều máy, tự phục hồi, rollout có kiểm soát và scale ngang trên nhiều node, bạn cần orchestrator — chuẩn công nghiệp là Kubernetes (k8s). Zero downtime còn phụ thuộc readiness, capacity, graceful shutdown và tính tương thích của ứng dụng; Kubernetes không tự bảo đảm chỉ vì dùng Deployment.

Thẳng thắn: Kubernetes nặng hơn Docker — nhiều khái niệm, YAML và bộ phận chuyển động. Nhưng nó không phải “Docker có thêm YAML”; nó là hệ control loop liên tục kéo trạng thái thật về trạng thái mong muốn. Bạn đúng chỗ vì đã hiểu image, container, mạng, volume, healthcheck và Compose từ Phần 1–8. Phần này giới thiệu mô hình tư duycluster đầu tiên trên laptop bằng kind. Phần 10 đi sâu config, probe và debug k8s.

Mỗi phần kết thúc bằng bài tập; hãy làm, đừng chỉ đọc.

Senior judgment: đừng dùng Kubernetes chỉ vì nghe “chuẩn production”. Nếu bạn có một app nhỏ, một server, traffic vừa phải và team chưa có năng lực vận hành cluster, Compose + systemd + backup + monitoring có thể tốt hơn. Kubernetes đáng giá khi bạn thật sự cần scheduling nhiều node, self-healing, policy deploy, tách quyền, và một nền tảng chung cho nhiều team/service.


Kiến trúc cluster

Một cluster Kubernetes là tập máy (vật lý hoặc ảo) phối hợp chạy workload của bạn. Một phía là control plane (bộ não); phía kia là worker node (nơi container thực sự chạy).

kubectl apply Control plane api-server scheduler controller-mgr etcd Worker node kubelet · kube-proxy · runtime Pod container(s) Pod container(s) Worker node kubelet · kube-proxy · runtime Pod container(s) Pod container(s) schedule pods → nodes
The control plane (api-server, scheduler, controller-manager, etcd) schedules Pods onto worker nodes (kubelet, kube-proxy, runtime)
  • API server — API REST; kubectl và controller đều nói chuyện qua đây.
  • Scheduler — chọn node phù hợp cho Pod mới.
  • Controller manager — giữ Deployment/ReplicaSet/Job khớp trạng thái mong muốn.
  • etcd — lưu trạng thái cluster.
  • kubelet — agent trên mỗi node, chạy Pod qua container runtime.
  • kube-proxy / networking — áp dụng quy tắc mạng Service → Pod.

Mô hình khai báo

Bạn không SSH vào node 3 rồi docker run. Bạn mô tả trạng thái mong muốn trong YAML rồi apply; Kubernetes điều chỉnh đến khi thực tế khớp. Pod chết thì controller tạo cái mới. Bạn yêu cầu ba replica thì hệ thống giữ ba.

Đây là bước nhảy tư duy lớn nhất: trong Docker bạn thường điều khiển một container; trong Kubernetes bạn điều khiển policy. Câu hỏi senior không còn là “làm sao start container này?”, mà là “nếu node chết, rollout fail, image pull lỗi, hoặc traffic đang vào pod chưa sẵn sàng thì hệ thống phản ứng thế nào?”


Các object lõi

Bạn sẽ sống với ba loại này khá lâu: Pod, Deployment, Service.

Pod — đơn vị lập lịch nhỏ nhất

Pod bọc một hoặc nhiều container dùng chung mạng và storage. Thực tế một container mỗi Pod là phổ biến. Pod ngắn hạn — chết thì IP mất; hiếm khi tạo Pod trần bằng tay.

Deployment — replica mong muốn & rolling update

Deployment sở hữu ReplicaSet, ReplicaSet sở hữu Pod. Bạn đặt replicas: 2 và Deployment đảm bảo hai Pod khớp, thay Pod hỏng, và rollout image từ từ.

  Deployment "web"

       │  manages

  ReplicaSet "web-7d4f9c8b6"

       │  owns
       ├──────────┬──────────┐
       ▼          ▼          ▼
    Pod web-1   Pod web-2   (scale adds more)

Service — mạng ổn định trước Pod

IP Pod đổi khi Pod restart. Servicetên DNS + IP ảo ổn định, cân bằng tải tới Pod khỏe khớp label selector.

Deployment replicas: 3 ReplicaSet keeps 3 alive Pod 1 Pod 2 Pod 3 Service stable VIP · LB traffic in →
A Deployment owns a ReplicaSet that keeps N Pods alive; a Service gives them one stable address and load-balances traffic across them

ClusterIP — DNS nội bộ; NodePort — cổng trên mọi node; LoadBalancer — LB cloud trên prod.


Cơ bản kubectl

kubectl là CLI cho API Kubernetes — giống docker với một daemon, nhưng cho cả cluster. Cài cùng kind hoặc minikube. Lệnh hằng ngày:

kubectl get pods                    # list Pods (default namespace)
kubectl get pods -n kube-system     # -n = namespace
kubectl get pods -o wide            # Pod IP, node name, nominated/readiness gates
kubectl describe pod <name>         # events, state, why Pending/CrashLoop
kubectl logs <pod>                  # stdout/stderr (like docker logs)
kubectl logs -f <pod>               # follow
kubectl exec -it <pod> -- sh        # shell inside (like docker exec)
kubectl apply -f manifest.yaml      # create or update from YAML
kubectl delete -f manifest.yaml     # remove resources in file
kubectl delete pod <name>           # delete one Pod (Deployment recreates it)

Dùng -n cho kube-system, staging… — tutorial thường ở default. Quy trình: sửa YAML → apply → get/describe/logs, controller điều chỉnh nền.


Cluster local với kind

kind chạy cluster trong Docker; minikube là lựa chọn khác — cùng quy trình kubectl.

# Install: https://kind.sigs.k8s.io/docs/user/quick-start/
kind create cluster --name dev
kubectl cluster-info --context kind-dev
kubectl get nodes
# NAME                 STATUS   ROLES           AGE   VERSION
# dev-control-plane    Ready    control-plane   1m    v1.36.x

context kubectl giờ trỏ tới kind-dev. Kiểm tra bằng kubectl config current-context.

Nạp image local vào kind

Image build bằng docker build nằm trên Docker host, không có sẵn trong node kind. Trước khi Deployment kéo myapp:local, nạp vào:

docker build -t myapp:local .
kind load docker-image myapp:local --name dev

Không bước này, Pod thường kẹt ImagePullBackOff.

Dọn khi xong:

kind delete cluster --name dev

Deployment đầu tiên

Tạo thư mục k8s-lab-09/ và lưu hai file.

nginx, hai replica, label để Service chọn:

# deployment.yaml — desired state: 2 nginx Pods
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deploy          # Deployment name (kubectl get deploy)
  labels:
    app: nginx
spec:
  replicas: 2                 # controller keeps 2 Pods running
  selector:
    matchLabels:
      app: nginx              # must match template labels below
  template:                   # Pod template — each Pod looks like this
    metadata:
      labels:
        app: nginx            # Service selector targets this label
    spec:
      containers:
        - name: nginx
          image: nginx:1.28-alpine   # public image; no kind load needed
          ports:
            - containerPort: 80      # container listens here (not published to host yet)

Service ClusterIP (truy cập bằng port-forward):

# service.yaml — stable VIP + DNS name → Pods with app=nginx
apiVersion: v1
kind: Service
metadata:
  name: nginx-svc
spec:
  type: ClusterIP              # default; internal cluster IP
  selector:
    app: nginx                 # must match Pod labels from Deployment
  ports:
    - port: 80                 # Service port (what clients connect to)
      targetPort: 80           # Pod containerPort

Apply và kiểm tra:

kubectl apply -f deployment.yaml -f service.yaml
kubectl get deploy,pods,svc
kubectl get pods -o wide
# wait until both Pods are Running (READY 1/1)

Truy cập từ laptop:

kubectl port-forward svc/nginx-svc 8080:80
# leave running; in another terminal:
curl -s http://localhost:8080 | head -5

port-forward tunnel tới Service — cách đơn giản nhất để curl từ laptop; NodePort cũng được nhưng cần map cổng thêm trên kind.


Từ Compose sang Kubernetes

Bạn đã nghĩ theo service từ Compose. Kubernetes tách trách nhiệm khác:

Compose (compose.yaml)Kubernetes
services.webDeployment + Service
ports: "8080:80"Service hoặc port-forward
volumes:emptyDir, PV + PVC (Phần 16)
environment: / env_file:env, ConfigMap, Secret (Phần 10)
healthcheckstartup/readiness/liveness probe (Phần 10)
depends_on startup orderKhông có tương đương trực tiếp; app phải retry hoặc dùng init container khi thật sự cần chờ
docker compose upkubectl apply -f …
docker compose scale web=3kubectl scale deploy/nginx-deploy --replicas=3

kompose khởi tạo manifest từ Compose; viết tay dạy label, selector và nối Deployment ↔ Service.


Các bẫy thường gặp

  • Cluster không tìm thấy image. Image public ổn; tag local cần kind load hoặc push registry.
  • Gọi thẳng IP Pod — IP ngắn hạn; luôn qua Service, và dùng Gateway/Ingress cho HTTP traffic từ ngoài cluster.
  • context sai — xác nhận kubectl config get-contexts trước khi xóa.
  • NodePort trên kind cần map cổng thêm; port-forward đơn giản hơn để curl từ máy bạn.
  • Không copy nguyên mạng Compose — DNS trong cluster là http://<tên-service> (cùng namespace).

Bảng tra nhanh

# cluster & context
kubectl get nodes
kubectl config current-context
kubectl config use-context kind-dev

# workloads
kubectl apply -f .
kubectl get deploy,rs,pods,svc
kubectl describe deploy nginx-deploy
kubectl scale deploy/nginx-deploy --replicas=4

# debug (mirror Part 8 docker habits)
kubectl logs <pod> -f
kubectl exec -it <pod> -- sh
kubectl get events --sort-by='.lastTimestamp'

# access
kubectl port-forward svc/nginx-svc 8080:80

# cleanup
kubectl delete -f deployment.yaml -f service.yaml
kind delete cluster --name dev

Bài tập / Exercises

Làm trong k8s-lab-09/ với manifest trong bài (hoặc tên riêng). Cần kind (hoặc minikube) và kubectl.

1. Tạo cluster kind tên lab09, xác nhận node Ready, context là kind-lab09.

Lời giải
kind create cluster --name lab09
kubectl get nodes
kubectl config current-context   # kind-lab09

2. Apply Deployment nginx replicas: 2, xác nhận hai Pod Running.

Lời giải
kubectl apply -f deployment.yaml
kubectl get pods -w
# Ctrl+C when both show 1/1 Running
kubectl get deploy nginx-deploy

3. Xóa một Pod, xem Pod mới xuất hiện — tự phục hồi từ Deployment.

Lời giải
kubectl get pods
kubectl delete pod nginx-deploy-xxxxxxxxxx-xxxxx   # pick one Pod name from get pods
kubectl get pods -w
# a new Pod is created; replica count stays at 2

4. Apply Service, port-forward cổng 8080, curl trang chào nginx.

Lời giải
kubectl apply -f service.yaml
kubectl port-forward svc/nginx-svc 8080:80 &
curl -s http://localhost:8080 | head -3
kill %1   # stop port-forward job

5. Scale Deployment lên 4 replica, xác nhận bốn Pod, rồi scale về 2.

Lời giải
kubectl scale deploy/nginx-deploy --replicas=4
kubectl get pods
kubectl scale deploy/nginx-deploy --replicas=2
kubectl get pods

Nâng cao: Build image local, kind load, đổi image Deployment thành lab09-app:local với imagePullPolicy: Never, apply, xác nhận Pod chạy.

Lời giải
# in deployment.yaml container spec:
image: lab09-app:local
imagePullPolicy: Never
kind load docker-image lab09-app:local --name lab09
kubectl apply -f deployment.yaml
kubectl get pods

Điểm chính

  • Compose = một host; Kubernetes = nhiều node với điều chỉnh, scale và rolling update.
  • Pod chạy container; Deployment giữ số replica và phục hồi; Service cho tên/IP ổn định trước Pod.
  • kubectl apply là vòng lặp hằng ngày; get / describe / logs / exec giống debug Docker ở Phần 8.
  • kind (+ kind load) là cách nhanh nhất để luyện không tốn tiền cloud.

Tiếp theo

Phần 10 — Kubernetes thực hành & Debug — ConfigMap và Secret, probe startup/readiness/liveness, resource request/limit, rollout và checklist debug kubectl khi Pod không lên. Networking nâng cao nằm ở Phần 14; storage bền vững ở Phần 16.