2.2. Core Concepts: Pods
Mục lục
- 1. Pod là gì?
- 2. Multi-container Pod
- 3. Deploy Pod bằng lệnh kubectl run
- 4. File định nghĩa Pod bằng YAML
- 5. Demo: tạo Pod bằng file YAML
- 6. Các lệnh kubectl thường dùng với Pod
1. Pod là gì?
Trước khi tìm hiểu về Pod, giả định rằng những điều sau đã được thiết lập sẵn: ứng dụng đã được phát triển và build thành Docker image, có sẵn trên một Docker repository như Docker Hub để Kubernetes pull về, và Kubernetes cluster đã setup sẵn, đang hoạt động (single-node hay multi-node không quan trọng).
Mục tiêu cuối cùng khi dùng Kubernetes là deploy ứng dụng dưới dạng container trên các máy được cấu hình làm worker node trong cluster. Nhưng Kubernetes không deploy container trực tiếp lên worker node: container luôn được đóng gói vào một Kubernetes object gọi là Pod. Pod là instance đơn lẻ của một ứng dụng, và cũng là object nhỏ nhất có thể tạo trong Kubernetes.
💡 Hình dung: Pod giống một căn hộ, còn container là người thuê chính sống trong đó. Muốn có thêm người ở, không nhét thêm giường vào căn hộ cũ mà xây hẳn một căn hộ mới. Chỉ khi cả khu (node) hết đất mới cần tính xây thêm khu mới.
Trường hợp đơn giản nhất chỉ có đúng 1 căn hộ: một single-node cluster, chạy một Docker container duy nhất, đóng gói trong một Pod duy nhất.
Nhưng nếu lượng người dùng truy cập tăng lên, cần thêm instance để chia tải, thì instance mới đó nằm ở đâu, có phải là một container nữa nhét vào ngay Pod đang có? Không: Kubernetes tạo hẳn một Pod mới, với một instance mới của cùng ứng dụng. Kết quả: 2 instance chạy trên 2 Pod riêng biệt, vẫn trên cùng một node.
Tải tiếp tục tăng, node hiện tại hết chỗ chứa, lúc đó mới cần thêm một node mới vào cluster để có thêm "đất xây".
Nhìn lại cả 3 bước trên, quy luật luôn nhất quán: Pod giữ quan hệ một-một với container ứng dụng. Scale up bằng cách tạo Pod mới, scale down bằng cách xóa Pod hiện có, không bao giờ nhét thêm container vào một Pod đã tồn tại chỉ để scale. (Cách load balancing traffic giữa các Pod sẽ bàn ở phần sau, khi nói tới Service; ở đây chỉ cần nắm đúng nguyên tắc 1-1 này.)
2. Multi-container Pod
Vừa nói rằng Pod thường có quan hệ một-một với container. Nhưng có bị giới hạn chỉ 1 container trong 1 Pod không? Không: một Pod đơn lẻ có thể chứa nhiều container, chỉ là chúng hiếm khi là nhiều container cùng loại.
Theo đúng nguyên tắc ở mục trước, muốn scale ứng dụng thì tạo thêm Pod. Nhưng đôi khi có một helper container làm tác vụ hỗ trợ cho web application (xử lý dữ liệu người dùng nhập, xử lý file upload, v.v.) và cần sống cùng vòng đời với container ứng dụng. Trường hợp đó, đặt cả 2 container vào cùng một Pod: application container được tạo thì helper cũng được tạo theo, application container chết thì helper cũng chết theo, vì cả hai thuộc cùng một Pod.
💡 Tiếp tục hình dung căn hộ ở mục trước: helper container giống một người ở cùng phòng với người thuê chính: cùng vào cùng ra, cùng chịu chung số phận căn hộ đó. Khác hẳn việc thuê nguyên một căn hộ khác chỉ để chứa người phụ này.
Hai container trong cùng Pod giao tiếp trực tiếp với nhau qua localhost vì dùng chung network space, và cũng chia sẻ được cùng storage space.
Nhìn lại từ góc độ thuần Docker
Tạm gác Kubernetes sang một bên, bàn về Docker container đơn thuần. Giả sử bạn đang viết một process hay script để deploy ứng dụng trên một Docker host. Bước đầu chỉ cần docker run python-app là ứng dụng chạy ổn, người dùng truy cập được. Khi tải tăng, bạn deploy thêm instance bằng cách chạy docker run vài lần nữa, cũng chưa có gì phức tạp.
Rồi ứng dụng lớn dần, kiến trúc thay đổi, mọi thứ phức tạp hơn. Giờ có thêm một helper container hỗ trợ web application bằng cách xử lý hoặc fetch dữ liệu từ nơi khác. Mỗi helper giữ quan hệ một-một với một application container, cần giao tiếp trực tiếp và đọc được dữ liệu của container đó. Để làm được, bạn phải tự duy trì một bản đồ (map) xem app nào đi với helper nào. Phải tự thiết lập network connectivity giữa chúng bằng link và custom network. Phải tạo shareable volume rồi chia sẻ giữa các container, và duy trì thêm một bản đồ nữa cho phần volume đó. Nặng nhất là phần giám sát: application container chết thì phải tự tay kill helper container đi kèm vì nó không còn việc gì để làm, và mỗi lần deploy một application container mới lại phải tự deploy helper mới cho nó.
Với Pod, Kubernetes tự động làm hết mọi việc đó. Chỉ cần định nghĩa Pod gồm những container nào, và các container trong Pod, theo mặc định, sẽ có quyền truy cập vào cùng storage, cùng network namespace, và cùng số phận: chúng được tạo cùng nhau và bị hủy cùng nhau.
Ngay cả khi ứng dụng không phức tạp đến vậy và sống ổn với một container duy nhất, Kubernetes vẫn buộc bạn tạo Pod. Về lâu dài đó lại là cái lợi: ứng dụng đã sẵn sàng cho các thay đổi kiến trúc và scale sau này.
Dù vậy, multi-container Pod là use case khá hiếm gặp. Tài liệu này chủ yếu dùng single container mỗi Pod, vậy một Pod như thế được tạo ra bằng cách nào? Nhanh nhất là đúng 1 dòng lệnh: kubectl run.
3. Deploy Pod bằng lệnh kubectl run
Trước đó đã học về lệnh kubectl run. Lệnh này thực chất làm gì? Nó deploy một Docker container bằng cách tạo một Pod: trước tiên Pod được tự động tạo ra, rồi một instance của Docker image NGINX được deploy vào đó.
Tên image do bạn chỉ định qua tham số --image. Application image, trong trường hợp này là image Nginx, được tải về từ Docker Hub repository, một public repository lưu các Docker image mới nhất của nhiều ứng dụng khác nhau. Có thể cấu hình Kubernetes pull image từ Docker Hub công khai hoặc từ một private repository nội bộ trong tổ chức.
Có Pod được tạo rồi, danh sách Pod hiện có xem bằng lệnh:
kubectl get pods
Lệnh này in ra danh sách Pod trong cluster. Ở đây Pod đang ở trạng thái ContainerCreating, và sẽ chuyển sang Running ngay khi container bắt đầu chạy.
Một lưu ý: phần này chưa bàn tới cách người dùng bên ngoài truy cập được NGINX web server, nên ở trạng thái hiện tại, web server chưa được expose ra ngoài. Truy cập nội bộ từ node thì vẫn được. Phạm vi ở đây chỉ dừng ở cách deploy một Pod; cách mở service đó cho end user sẽ nằm ở phần networking và services.
kubectl run tiện để tạo nhanh một Pod, nhưng cách này không tái sử dụng được: muốn tạo lại y hệt Pod đó lần sau, phải nhớ và gõ lại đúng lệnh, đúng flag. Cách bền hơn, cũng là cách dùng chính trong thực tế, là mô tả Pod bằng một file YAML.
4. File định nghĩa Pod bằng YAML
File YAML này dùng chung 1 cấu trúc cho mọi loại object Kubernetes (Pod, ReplicaSet, Deployment, Service,...), nên nắm được cấu trúc của Pod là nắm được cả nền tảng chung đó.
Một Kubernetes definition file luôn chứa đúng 4 field cấp cao nhất (top-level field): apiVersion, kind, metadata, và spec. Cả 4 đều là property gốc (root-level) và đều bắt buộc phải có: thiếu 1 trong 4 là file không hợp lệ.
apiVersion — chọn đúng phiên bản API
Field đầu tiên, apiVersion, cho biết phiên bản Kubernetes API dùng để tạo object. Với Pod, giá trị luôn là v1. Đi xa hơn Pod, giá trị này đổi tùy loại object (apps/v1 cho Deployment/ReplicaSet/DaemonSet/StatefulSet, batch/v1 cho Job/CronJob), nhưng chỉ cần nhớ chúng khi động tới đúng loại object tương ứng, phần sau tài liệu sẽ nói rõ.
kind — object đang tạo là gì
Ngay sau đó là kind, tức loại object đang tạo. Với Pod, set Pod (chú ý viết hoa chữ P, YAML phân biệt hoa thường). Cùng field này, ở chỗ khác sẽ gặp ReplicaSet, Deployment, hay Service.
metadata — đặt tên và gắn nhãn cho Pod
Hai field trên chỉ là string đơn giản. metadata thì khác, nó là một dictionary chứa dữ liệu về object: tên, nhãn (labels),... Mọi property dưới metadata phải thụt đúng. name và labels là con (children) của metadata, nên phải cùng thẳng hàng dọc với nhau (số khoảng trắng bao nhiêu không quan trọng, miễn bằng nhau); nếu labels thụt sâu hơn name, YAML sẽ hiểu nhầm nó là con của name thay vì anh em ngang hàng, và cả cấu trúc sai theo.
name là string value, ví dụ đặt Pod tên my-app-pod. labels lại là 1 dictionary khác nằm trong metadata, chứa bao nhiêu cặp key-value tùy ý, ví dụ app: myapp.
💡 Hình dung: labels giống nhãn dán trên thùng hàng trong kho: không ảnh hưởng gì tới nội dung bên trong thùng, nhưng giúp tìm và phân loại nhanh về sau. Có hàng trăm Pod chạy frontend và hàng trăm Pod chạy backend, chỉ cần dán đúng nhãn
frontend/backendngay từ đầu là lọc được bằng label sau này, không cần nhớ tên từng Pod.
Lưu ý: dưới metadata chỉ được khai những property Kubernetes đã định nghĩa sẵn (name, labels,...), không thêm tùy ý được. Ngược lại, dưới labels thì muốn thêm bao nhiêu cặp key-value cũng được, Kubernetes không giới hạn.
spec — nội dung thực sự của Pod
3 field trên mới chỉ khai type và name của object: biết đang tạo 1 Pod tên gì, nhưng chưa nói nó chạy container hay image nào. Đó là việc của field cuối, spec (specification), phần khác nhau nhiều nhất giữa các loại object, nên gặp một object lạ thì luôn phải tra tài liệu để biết đúng format spec của nó.
Với Pod 1 container, spec khá đơn giản: thêm 1 property containers, luôn là list/array, vì Pod có thể chứa nhiều container như mục 2 đã nói. Ở đây list chỉ có đúng 1 item (dấu - đứng trước đánh dấu phần tử đầu tiên), là 1 dictionary gồm name và image, với image: nginx là tên Docker image sẽ pull về.
Sau khi file được tạo, chạy:
kubectl create -f pod-definition.yaml
Và Kubernetes tạo Pod.
Bốn top-level property cần nhớ là apiVersion, kind, metadata và spec; việc còn lại chỉ là thêm giá trị vào đó tùy object định tạo.
Sau khi tạo Pod, làm sao xem nó?
kubectl get pods
Dùng lệnh này để xem danh sách Pod hiện có, ở đây chỉ có một. Để xem thông tin chi tiết về Pod:
kubectl describe pod
Lệnh này cho biết thông tin về Pod: khi nào nó được tạo, những nhãn nào được gán, những Docker container nào thuộc về nó, và các event liên quan tới Pod đó.
Nắm được cấu trúc 4 field rồi, phần tiếp theo ráp chúng lại thành một file pod.yaml hoàn chỉnh, dùng để deploy đúng Pod NGINX đã tạo bằng kubectl run ở mục 3, chỉ khác cách khai báo.
5. Demo: tạo Pod bằng file YAML
Gộp đúng 4 field vừa nói ở mục 4, file pod.yaml hoàn chỉnh trông như sau:
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
tier: frontend
spec:
containers:
- name: nginx
image: nginx
Tạo Pod xong, câu hỏi tiếp theo luôn là: dùng lệnh gì để xem, sửa, xóa, hay debug khi nó gặp sự cố? Phần cuối tổng hợp lại đúng những lệnh kubectl hay dùng nhất với Pod, để tra cứu nhanh mỗi khi cần.
6. Các lệnh kubectl thường dùng với Pod
Tự lab trên cluster local nào cũng được (Minikube, Kind, Docker Desktop Kubernetes). Output thực tế trên máy bạn sẽ khác đôi chút (AGE, IP, tên node...), nhưng cấu trúc và ý nghĩa các field thì như nhau.
Tạo Pod
Tạo nhanh một Pod bằng lệnh imperative, chỉ cần tên Pod và image:
kubectl run nginx --image=nginx
# Output:
pod/nginx created
Tạo Pod từ file YAML (xem cấu trúc file ở mục 4 và mục 5), với create cho object chưa từng tồn tại và apply cho cả tạo mới lẫn cập nhật:
kubectl create -f pod.yaml
kubectl apply -f pod.yaml
# Output:
pod/nginx created
Kết hợp lệnh imperative (
kubectl create/kubectl run) vàkubectl applytrên cùng một object thường sinh ra warning liên quan annotationlast-applied-configuration, chi tiết ở Part 2.5: Imperative vs Declarative.
Xem danh sách và trạng thái Pod
kubectl get pods
# Output:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 32s
Xem thêm IP và node được schedule:
kubectl get pods -o wide
# Output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 32s 10.244.0.5 minikube <none> <none>
Cột READY có dạng x/y, trong đó y là tổng số container trong Pod và x là số container đang sẵn sàng. Lọc theo label, hoặc xuất toàn bộ định nghĩa Pod dưới dạng YAML/JSON:
kubectl get pods -l app=nginx
kubectl get pod nginx -o yaml
kubectl get pod nginx -o json
Xem chi tiết một Pod
kubectl describe pod nginx
# Output:
Name: nginx
Namespace: default
Node: minikube/192.168.49.2
Status: Running
IP: 10.244.0.5
Containers:
nginx:
Image: nginx
State: Running
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 32s default-scheduler Successfully assigned default/nginx to minikube
Normal Pulled 30s kubelet Successfully pulled image "nginx"
Normal Started 30s kubelet Started container nginx
Lệnh này hữu ích nhất khi debug: mục Events ở cuối cho biết chính xác Pod đang kẹt ở bước nào (scheduling, pulling image, starting container...).
Sinh nhanh file YAML bằng dry-run
Thay vì viết YAML từ đầu, dùng kubectl run/kubectl create với --dry-run=client -o yaml để Kubernetes tự sinh khung file, rồi chỉnh sửa lại:
kubectl run redis --image=redis --dry-run=client -o yaml > redis.yaml
⚠️ Lưu ý: option
--dry-run(không kèm giá trị) đã bị deprecated, dùng--dry-run=client(chỉ generate ở client, không gửi lên API server) hoặc--dry-run=server(gửi lên API server để validate nhưng không lưu).
Sửa và xóa Pod
Phần lớn field của một Pod đang chạy là immutable, tức không sửa trực tiếp được (ví dụ image, spec.containers nói chung), nên kubectl edit chỉ dùng được cho các field cho phép sửa (labels, một số field dưới spec như activeDeadlineSeconds, tolerations,...):
kubectl edit pod nginx
Muốn đổi image hay cấu hình container, cách thực tế là sửa file YAML gốc rồi apply lại, hoặc xóa Pod và tạo lại:
kubectl delete pod nginx
# Output:
pod "nginx" deleted
Logs và truy cập vào container
Xem log của container trong Pod, thêm -f để theo dõi log real-time, -c <container> khi Pod có nhiều container:
kubectl logs nginx
kubectl logs -f nginx
kubectl logs nginx -c nginx
Chạy lệnh trực tiếp bên trong container, hoặc mở shell tương tác:
kubectl exec nginx -- ls /usr/share/nginx/html
kubectl exec -it nginx -- /bin/bash
Debug các lỗi Pod thường gặp
Một số Pod cố tình dùng image sai để minh họa lỗi hay gặp khi vận hành thực tế:
apiVersion: v1
kind: Pod
metadata:
name: webapp
labels:
app: webapp
spec:
containers:
- name: nginx
image: nginx
- name: agentx
image: agentx
kubectl apply -f webapp-pod.yaml
kubectl get pods
# Output:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 2m
webapp 1/2 ImagePullBackOff 0 20s
Cột READY hiển thị 1/2 vì container agentx dùng image không tồn tại. Xem lý do cụ thể bằng describe:
kubectl describe pod webapp
# Output (rút gọn):
Failed to pull image "agentx": rpc error: code = NotFound desc = failed to pull and unpack image "docker.io/library/agentx:latest": ...
Bảng dưới tổng hợp các STATUS/REASON hay gặp và hướng xử lý:
| STATUS / REASON | Ý nghĩa | Cách xử lý |
|---|---|---|
ContainerCreating | Đang pull image hoặc tạo container | Đợi thêm, nếu treo lâu thì describe pod xem Events |
ErrImagePull / ImagePullBackOff | Sai tên image, sai tag, hoặc private registry chưa auth | Kiểm tra lại image: trong YAML, kiểm tra imagePullSecrets |
CrashLoopBackOff | Container start rồi crash liên tục | kubectl logs <pod> (thêm --previous để xem log lần crash trước) |
Pending | Chưa được scheduler gán vào node nào | describe pod xem Events — thường do thiếu resource hoặc taint/toleration |
OOMKilled | Container bị kill vì vượt giới hạn memory | Tăng resources.limits.memory hoặc tối ưu ứng dụng |
Dọn dẹp Pod minh họa sau khi debug xong:
kubectl delete pod webapp
Danh sách lệnh chính
| Lệnh | Công dụng |
|---|---|
kubectl run <name> --image=<image> | Tạo nhanh 1 Pod bằng lệnh imperative |
kubectl create -f <file>.yaml / kubectl apply -f <file>.yaml | Tạo (hoặc cập nhật) Pod từ file YAML |
kubectl get pods / -o wide / -l <label> | Xem danh sách Pod, kèm IP/node, hoặc lọc theo label |
kubectl describe pod <name> | Xem chi tiết Pod — quan trọng nhất khi debug, nhờ mục Events |
kubectl run ... --dry-run=client -o yaml > file.yaml | Sinh nhanh khung YAML thay vì viết tay từ đầu |
kubectl edit pod <name> | Sửa các field cho phép sửa trên Pod đang chạy (labels,...) |
kubectl delete pod <name> | Xóa Pod |
kubectl logs <name> / -f / -c <container> | Xem log container, theo dõi real-time, hoặc chọn container cụ thể |
kubectl exec -it <name> -- <command> | Chạy lệnh hoặc mở shell bên trong container |
Nắm được từng lệnh trong bảng trên là đủ để thao tác Pod hàng ngày. Phần tiếp theo của tài liệu đi vào ReplicaSet và Deployment, nơi Kubernetes tự động hóa luôn việc tạo và thay thế Pod, thay vì phải gõ tay từng lệnh như ở đây.
Nguồn tham khảo
Nguồn gốc: Khóa "Certified Kubernetes Administrator (CKA)" — phần "Core Concepts" (Pods: khái niệm Pod, multi-container Pod, file định nghĩa YAML, demo tạo Pod, lab thực hành về Pods), nền tảng KodeKloud. Giảng viên: Mumshad Mannambeth.
Repo ghi chú, link tài liệu, và đáp án các practice question của toàn bộ khóa học: kodekloudhub/certified-kubernetes-administrator-course.
Fact-check:
apps/v1beta1/extensions/v1beta1(API group cũ) đã bị gỡ hoàn toàn khỏi Kubernetes từ v1.16 — 2026-08-19, Kubernetes blog — Deprecated APIs Removed In 1.16