Bạn đã quen với Docker, đóng gói ứng dụng thành container và chạy ngon lành trên một máy. Nhưng khi hệ thống lớn dần, câu hỏi mới xuất hiện: làm sao chạy hàng chục container trên nhiều máy chủ, tự khởi động lại khi chúng gặp sự cố, cập nhật phiên bản mới mà không gián đoạn dịch vụ? Đó là lúc Kubernetes (thường viết tắt là K8s) phát huy vai trò. Kubernetes có rất nhiều khái niệm, nhưng nếu nắm chắc ba đối tượng nền tảng là Pod, Deployment và Service, bạn đã hiểu được phần lớn cách một ứng dụng chạy trên cluster.

Kubernetes hoạt động theo kiểu "khai báo"

Trước khi đi vào từng đối tượng, cần hiểu triết lý cốt lõi: bạn mô tả trạng thái mong muốn (ví dụ "tôi muốn 3 bản sao của ứng dụng web phiên bản 2.1"), và Kubernetes liên tục so sánh trạng thái thực tế với mong muốn để tự điều chỉnh. Nếu một bản sao chết, hệ thống tạo bản mới. Nếu bạn đổi phiên bản, hệ thống thay dần các bản cũ.

Mỗi trạng thái mong muốn được viết trong một tệp YAML (manifest) và áp dụng bằng kubectl apply -f.

Một cluster gồm hai phần chính:

  • Control plane: bộ não của cluster, gồm API server, scheduler, các controller và kho lưu trạng thái etcd.
  • Node: các máy chạy workload, mỗi node có kubelet để quản lý container và một container runtime.

Pod: đơn vị nhỏ nhất

Pod là đơn vị triển khai nhỏ nhất trong Kubernetes. Một Pod chứa một hoặc nhiều container chạy cùng nhau, chia sẻ chung địa chỉ IP, không gian mạng và có thể dùng chung volume. Phần lớn trường hợp, mỗi Pod chỉ chứa một container chính. Pod nhiều container thường dùng cho mô hình sidecar, ví dụ một container phụ thu thập log cho container ứng dụng.

apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
    - name: web
      image: nginx:1.27
      ports:
        - containerPort: 80

Điều quan trọng cần nhớ: Pod mang tính tạm thời. Khi một Pod chết hoặc node chứa nó gặp sự cố, Pod đó không tự "hồi sinh"; thay vào đó một Pod mới (với IP mới) sẽ được tạo nếu có controller quản lý. Vì vậy, trong thực tế bạn hầu như không tạo Pod trực tiếp mà để Deployment làm việc đó.

Deployment: quản lý bản sao và cập nhật

Deployment là đối tượng phổ biến nhất để chạy ứng dụng không lưu trạng thái (stateless). Bạn khai báo số bản sao và mẫu Pod, Deployment sẽ tạo một ReplicaSet để đảm bảo luôn có đúng số Pod như mong muốn.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  selector:
    matchLabels: { app: web }
  template:
    metadata:
      labels: { app: web }
    spec:
      containers:
        - { name: web, image: "nginx:1.27", ports: [{ containerPort: 80 }] }

Deployment mang lại nhiều tính năng giá trị:

  • Tự phục hồi: Pod nào chết sẽ được thay thế tự động.
  • Mở rộng dễ dàng: kubectl scale deployment web --replicas=5 hoặc cấu hình tự động mở rộng với HorizontalPodAutoscaler.
  • Rolling update: khi bạn đổi image, Deployment thay dần các Pod cũ bằng Pod mới, giữ dịch vụ luôn có Pod sẵn sàng.
  • Rollback: nếu phiên bản mới có lỗi, kubectl rollout undo deployment/web đưa về phiên bản trước.

Lưu ý phần selector phải khớp với labels trong template. Nhãn (label) là cơ chế mà Kubernetes dùng để liên kết các đối tượng với nhau, và bạn sẽ thấy nó xuất hiện lại ở Service.

Service: địa chỉ ổn định cho nhóm Pod

Vì Pod được tạo và huỷ liên tục với IP thay đổi, các thành phần khác không thể gọi trực tiếp vào IP của Pod. Service giải quyết vấn đề này bằng cách cung cấp một địa chỉ và tên DNS ổn định, đồng thời phân phối lưu lượng tới các Pod có nhãn phù hợp.

apiVersion: v1
kind: Service
metadata:
  name: web
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80

Sau khi tạo, các Pod khác trong cùng namespace có thể gọi ứng dụng qua tên web. Các loại Service thường gặp:

  • ClusterIP (mặc định): chỉ truy cập được bên trong cluster, dùng cho giao tiếp giữa các dịch vụ nội bộ.
  • NodePort: mở một cổng trên mọi node để truy cập từ bên ngoài, thường dùng khi thử nghiệm.
  • LoadBalancer: yêu cầu nhà cung cấp cloud cấp một bộ cân bằng tải bên ngoài trỏ vào Service.

Để định tuyến HTTP theo tên miền hoặc đường dẫn cho nhiều dịch vụ, bạn sẽ tìm hiểu thêm về Ingress hoặc Gateway API, nhưng đó là bước tiếp theo.

Ba đối tượng phối hợp như thế nào?

Hãy hình dung luồng hoạt động:

  1. Bạn áp dụng manifest Deployment với 3 bản sao.
  2. Deployment tạo ReplicaSet, ReplicaSet tạo 3 Pod gắn nhãn app: web.
  3. Scheduler đặt các Pod lên những node phù hợp.
  4. Service chọn các Pod theo nhãn app: web và cân bằng lưu lượng giữa chúng.
  5. Khi một Pod chết, Pod mới được tạo và Service tự động đưa nó vào danh sách đích.

Một số lệnh kubectl hữu ích

kubectl apply -f k8s/
kubectl get pods,deploy,svc
kubectl describe pod <ten-pod>
kubectl logs -f deploy/web
kubectl rollout status deploy/web

Để thực hành, bạn có thể dựng cluster cục bộ bằng các công cụ như minikube, kind hoặc tính năng Kubernetes tích hợp trong Docker Desktop.

Kết luận

Kubernetes có thể khiến người mới choáng ngợp, nhưng phần lớn ứng dụng web đều được xây dựng từ ba viên gạch cơ bản: Pod chạy container, Deployment duy trì số bản sao và quản lý cập nhật, Service cung cấp địa chỉ ổn định để truy cập. Khi đã nắm vững chúng cùng cơ chế nhãn và tư duy khai báo, bạn sẽ dễ dàng tiếp cận các khái niệm nâng cao hơn như ConfigMap, Secret, Ingress, StatefulSet và tự động mở rộng.

Nguồn tham khảo