🇬🇧 Read the English version of this article on tanhdev.com
In-Place Pod Resizing cho phép thay đổi tài nguyên CPU và Memory của container đang chạy mà không cần khởi động lại Pod. Nội dung dưới đây phân tích chi tiết cơ chế hoạt động, cấu hình YAML chuẩn production, tích hợp VPA và các điểm lưu ý quan trọng.
Trước phiên bản v1.35, việc thay đổi tài nguyên CPU hoặc Memory bắt buộc phải khởi động lại Pod (eviction & recreate). Điều này gây ngắt kết nối và ảnh hưởng trực tiếp tới tính khả dụng của hệ thống. Thử tưởng tượng với một cơ sở dữ liệu dạng stateful đang duy trì các kết nối mạng, hay một mô hình AI đang nạp 30GB model weights trong bộ nhớ, hoặc một tác vụ batch job chạy thời gian dài — việc khởi động lại Pod sẽ gây thiệt hại nghiêm trọng (catastrophic). In-Place Pod Resizing giải quyết triệt để vấn đề này bằng cách tách biệt việc quản lý tài nguyên khỏi vòng đời của Pod (pod lifecycle).
Đây là bộ cẩm nang thực tế cho production: giải thích chi tiết cơ chế hoạt động, hướng dẫn triển khai và các lưu ý quan trọng. Để có cái nhìn tổng quan về kiến trúc Kubernetes, bạn có thể tham khảo bài viết GitOps ở Quy Mô Lớn (GitOps at Scale). Nếu bạn đang tối ưu hóa các ứng dụng Go, bài viết Cải tiến Go 1.26 Green Tea GC là tài liệu kết hợp hiệu quả với In-Place Pod Resizing dành cho các workload yêu cầu tối ưu bộ nhớ.
1. Tổng Quan Về In-Place Pod Resizing
Answer-first: In-Place Pod Resizing cho phép gửi trực tiếp yêu cầu PATCH để cập nhật tài nguyên Pod mà không cần khởi động lại. Tính năng này đã chính thức đạt trạng thái Stable (GA) từ v1.35 (tháng 12/2025). Kubelet sẽ trực tiếp cập nhật giới hạn cgroup của container thông qua subresource /resize mà không làm gián đoạn dịch vụ.
So Sánh Trước và Sau Khi Tính Năng Đạt GA
| Kịch Bản (Scenario) | Trước v1.35 | Từ v1.35 (GA) |
|---|---|---|
| AI inference pod cần thêm RAM lúc cao tải (peak load) | Tiêu hủy Pod cũ → Khởi tạo Pod mới → Nạp lại model weights (chờ cold start 30s–5 phút) | Gửi lệnh PATCH resize → Hạn mức Memory tăng lập tức (~1s) → Không gián đoạn dịch vụ (No disruption) |
| Database cần tăng CPU burst | VPA thực hiện restart Pod làm rớt kết nối | VPA gửi patch resize, tăng CPU limit không mất kết nối |
| Yêu cầu điều chỉnh tài nguyên môi trường dev | Sửa deployment và thực hiện rolling restart | Sử dụng kubectl patch resize tức thì |
| Tài nguyên dư thừa ngoài giờ cao điểm | Scale down số lượng replicas (mất trạng thái) | Resize giảm tài nguyên Pod về mức tối thiểu mà vẫn giữ Pod running |
Lộ Trình Phát Triển Tính Năng Đến GA
| Phiên Bản | Trạng Thái | Ghi Chú |
|---|---|---|
| v1.27 (2023) | Alpha | Cần bật feature gate InPlacePodVerticalScaling |
| v1.31 (2024) | Beta | Được mở mặc định phía API server |
| v1.33 (2025) | Beta | Bật mặc định trên tất cả các thành phần |
| v1.35 (12/2025) | Stable (GA) | Bật mặc định, không cần feature gate |
2. Yêu Cầu Hạ Tầng Nền Tảng (Requirements)
Answer-first: Từ phiên bản Kubernetes v1.35+, tính năng In-Place Pod Resizing hoạt động mặc định (works out of the box) mà không cần bật bất kỳ feature gate nào. Yêu cầu quan trọng nhất là container runtime phải hỗ trợ API resize, cụ thể là containerd ≥ 1.6.9 hoặc CRI-O ≥ 1.25.
Danh Sách Kiểm Tra Yêu Cầu Hạ Tầng (Infrastructure Checklist)
| Thành Phần | Phiên Bản Tối Thiểu | Ghi Chú |
|---|---|---|
| Kubernetes | v1.35+ | Đạt trạng thái GA, không cần bật feature gates |
| containerd | ≥ 1.6.9 | Hỗ trợ hàm gọi CRI UpdateContainerResources |
| CRI-O | ≥ 1.25 | Container runtime thay thế tương thích hoàn toàn |
| kubelet | v1.35+ | Đồng bộ phiên bản với Kubernetes API Server |
| kubectl | v1.35+ | Hỗ trợ lệnh thao tác điều chỉnh tài nguyên Pod |
Mức Độ Hỗ Trợ Trên Các Dịch Vụ Managed Kubernetes
| Cloud Provider | Hỗ Trợ In-Place Resize | Ghi Chú |
|---|---|---|
| AWS EKS | ✅ Cluster v1.35+ | Hỗ trợ chính thức từ Tháng 3/2026 |
| GCP GKE | ✅ Cluster v1.35+ | Sẵn sàng cho production trên kênh Rapid channel |
| Azure AKS | ✅ Cluster v1.35+ | Phiên bản xem trước (Preview) từ Tháng 2/2026 |
| K3s | ✅ Bản v1.35+ | Tích hợp sẵn với embedded containerd |
3. Cơ Chế Hoạt Động: Resize Policy & Pod Status
Mỗi container trong Pod được cấu hình thuộc tính resizePolicy để chỉ định hành vi khi thay đổi CPU hoặc Memory:
Luồng Thực Thi Resize (Resize Flow)
sequenceDiagram
participant User as Người gọi kubectl / VPA
participant API as Cổng API Server
participant Kubelet as Kubelet
participant CRI as Bộ runtime containerd / CRI-O
participant Container as Lõi Running Container
User->>API: Gửi yêu cầu PATCH /api/v1/namespaces/ns/pods/name/resize
API->>API: Kiểm tra tài nguyên mới so với LimitRange/Quota
API->>Kubelet: Watcher phát hiện sự thay đổi trong Pod spec
Kubelet->>Kubelet: So sánh spec.resources với status.resources
Kubelet->>CRI: Gọi UpdateContainerResources(newCPU, newMemory)
CRI->>Container: Cập nhật cgroup limits (cpu.max, memory.max)
Container-->>CRI: Trả về thành công (không restart container)
CRI-->>Kubelet: Success
Kubelet->>API: Cập nhật pod.status.containerStatuses[].resources
Kubelet->>API: Đặt pod.status.resize = "" (hoàn tất)
Các Tùy Chọn Resize Policy
spec:
containers:
- name: inference
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # Thay đổi CPU: không yêu cầu khởi động lại container
- resourceName: memory
restartPolicy: RestartContainer # Thay đổi Memory: yêu cầu khởi động lại container
restartPolicy | Hành vi (Behavior) | Trường hợp sử dụng (Use When) |
|---|---|---|
NotRequired | Thao tác resize được thực hiện trực tiếp (in-place) thông qua việc điều chỉnh cgroup (cgroup adjustment) mà không cần khởi động lại container | Thường áp dụng cho CPU (an toàn khi thay đổi), và Memory (nếu ứng dụng có khả năng thích ứng linh hoạt với việc điều chỉnh memory limit) |
| RestartContainer | Container được khởi động lại ngay sau khi thay đổi kích thước | Sử dụng khi giảm Memory limit (tránh trường hợp ứng dụng đã chiếm dụng bộ nhớ vượt quá mức limit mới), hoặc đối với ứng dụng chỉ đọc cấu hình memory limit lúc khởi động |
Khuyến nghị cho môi trường Production (Production recommendation): Với phần lớn các dịch vụ, hãy thiết lập
restartPolicycủa CPU và Memory làNotRequiredđối với các thao tác tăng tài nguyên (increases only). Việc giảm memory limit trên các ứng dụng đang chiếm dụng bộ nhớ lớn (large heap allocations) có thể dẫn đến sự cố OOM Kill nếu ứng dụng không tự động giải phóng bộ nhớ (release memory).
Theo Dõi Trạng Thái Pod (Pod Status) Trong Quá Trình Resize
status:
resize: InProgress # các giá trị có thể gặp: Proposed, Deferred, Infeasible, ""
containerStatuses:
- name: inference
resources:
requests:
cpu: "4" # thực chất khoản tài nguyên xơi lót dọn mâm thực nhận current allocation
memory: "8Gi"
allocatedResources:
cpu: "4"
memory: "8Gi"
Trạng thái status.resize | Ý nghĩa kỹ thuật (Meaning) |
|---|---|
"" (Rỗng/Empty) | Quá trình thay đổi kích thước đã hoàn tất thành công hoặc không có yêu cầu resize nào đang chờ xử lý |
Proposed | API server đã ghi nhận và chấp nhận yêu cầu resize, nhưng Kubelet chưa bắt đầu thực thi (hasn’t acted yet) |
InProgress | Kubelet đã tiếp nhận yêu cầu và đang trong quá trình điều chỉnh tài nguyên cho Pod |
Deferred | Node hiện tại không đủ tài nguyên nhàn rỗi để đáp ứng ngay lập tức; Kubelet sẽ tạm hoãn và thử lại khi Node giải phóng tài nguyên |
Infeasible | Yêu cầu resize không thể thực hiện do vượt quá tổng dung lượng tài nguyên tối đa (Node capacity) của Node |
4. Các Mẫu File Cấu Hình YAML Chuẩn Production
Mẫu 1: Pod AI Inference Tự Động Resize CPU/Memory
apiVersion: v1
kind: Pod
metadata:
name: llm-inference
labels:
app: llm-inference
model: llama-3-70b
spec:
containers:
- name: inference
image: ghcr.io/yourorg/llm-server:v2.1
resources:
requests:
cpu: "4"
memory: "32Gi"
limits:
cpu: "8"
memory: "64Gi"
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired # Thoải mái con gà mái bọc an toàn: trọng số model weights được luồn trét nạp bằng mmap'd, không phải ôm nạp vô gánh nặng kỹ thuật xơi heap
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /health
port: 8080
periodSeconds: 5
Bơm kích tống resize đôn nạp ngay chóc giữa tâm bão giông tải nặng chót vót của inference (Resize during peak inference load):
# Tăng CPU khi tải đột biến (không cần restart container)
kubectl patch pod llm-inference --subresource resize --type merge -p \
'{"spec":{"containers":[{"name":"inference","resources":{"requests":{"cpu":"8"},"limits":{"cpu":"16"}}}]}}'
# Rú ga thục dồn tụt đạp lui dạt xuống lùi giảm gánh lúc chợp buông lơi rảnh ngơi off-peak
kubectl patch pod llm-inference --subresource resize --type merge -p \
'{"spec":{"containers":[{"name":"inference","resources":{"requests":{"cpu":"4"},"limits":{"cpu":"8"}}}]}}'
Mẫu 2: Database Pod - Resize Live Cho CPU, Restart Cho Memory
apiVersion: v1
kind: Pod
metadata:
name: postgres-primary
spec:
containers:
- name: postgres
image: postgres:16
resources:
requests:
cpu: "2"
memory: "4Gi"
limits:
cpu: "4"
memory: "8Gi"
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # Phần dải CPU phớt lờ rải dạt tự nhồi live mượt
- resourceName: memory
restartPolicy: RestartContainer # PostgreSQL đọc thông số shared_buffers tại thời điểm khởi động
env:
- name: POSTGRES_SHARED_BUFFERS
value: "2GB"
Mẫu 3: Batch Job - Resize Trực Tiếp Khi Đang Thực Thi
apiVersion: batch/v1
kind: Job
metadata:
name: data-pipeline
spec:
template:
spec:
containers:
- name: etl
image: yourorg/etl-runner:latest
resources:
requests:
cpu: "2"
memory: "8Gi"
limits:
cpu: "8"
memory: "32Gi"
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired
restartPolicy: Never
Trong các giai đoạn xử lý dữ liệu lớn của tiến trình ETL (memory-intensive phase), một controller bên ngoài (hoặc VPA) có thể điều chỉnh tài nguyên Pod ngay trong lúc thực thi (mid-execution) mà không gây gián đoạn tiến trình. Đối với các dịch vụ gặp phải sự cố rò rỉ goroutine gây tăng dung lượng bộ nhớ dần theo thời gian (gradual memory growth), In-Place Resizing giúp duy trì hệ thống tạm thời để phục vụ việc chẩn đoán nguyên nhân gốc rễ (root cause) thay vì là giải pháp thay thế hoàn toàn việc sửa lỗi.
5. Tích Hợp VPA: Tự Động Resize Pod Tại Chỗ
Answer-first: Vertical Pod Autoscaler (VPA) từ phiên bản v1.3+ đã hỗ trợ chế độ In-Place resize thông qua updateMode: "InPlace". Tính năng này cho phép tự động điều chỉnh tài nguyên Pod mà không cần khởi động lại Pod (without pod disruption), giúp VPA trở thành giải pháp chuẩn production cho các workload stateful.
Cấu Hình VPA Với Chế Độ InPlace Update
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: llm-inference-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: llm-inference
updatePolicy:
updateMode: "InPlace" # Chế độ mới: tự động resize mà không restart Pod
resourcePolicy:
containerPolicies:
- containerName: inference
minAllowed:
cpu: "2"
memory: "16Gi"
maxAllowed:
cpu: "32"
memory: "128Gi"
controlledResources: ["cpu", "memory"]
Luồng Hoạt Động Của VPA In-Place Resize
flowchart TD
VPA[VPA Recommender] -->|Phân tích metrics tài nguyên| REC[Tạo gợi ý Recommendation: Tăng CPU từ 8 lên 12]
REC --> UPDATER[VPA Updater]
UPDATER -->|Kiểm tra cấu hình updateMode| MODE{updateMode == InPlace?}
MODE -->|Có (InPlace)| PATCH[Gửi yêu cầu PATCH tới subresource /resize của Pod]
MODE -->|Không (Recreate)| EVICT[Evict Pod cũ và khởi tạo Pod mới với tài nguyên mới]
PATCH --> KUBELET[Kubelet cập nhật cgroup limits]
KUBELET --> DONE[Pod tiếp tục chạy ở trạng thái Running với tài nguyên mới ✅]
Chiến Lược Tối Ưu Chi Phí (Cost Optimization Pattern): Điều Chỉnh Tài Nguyên Theo Giờ (Time-Based Resizing)
Cấu hình cho tải xử lý AI inference có mô hình phụ tải (load patterns) thay đổi theo thời gian (tải cao vào giờ hành chính business hours và giảm thấp vào ban đêm overnight):
apiVersion: batch/v1
kind: CronJob
metadata:
name: inference-scaleup
spec:
schedule: "0 8 * * 1-5" # Lịch chạy lúc 8:00 AM các ngày trong tuần (weekdays)
jobTemplate:
spec:
template:
spec:
containers:
- name: resizer
image: bitnami/kubectl:1.35
command:
- /bin/sh
- -c
- |
kubectl get pods -l app=llm-inference -o name | while read pod; do
kubectl patch $pod --subresource resize --type merge -p \
'{"spec":{"containers":[{"name":"inference","resources":{"requests":{"cpu":"16","memory":"64Gi"},"limits":{"cpu":"32","memory":"128Gi"}}}]}}'
done
restartPolicy: OnFailure
---
apiVersion: batch/v1
kind: CronJob
metadata:
name: inference-scaledown
spec:
schedule: "0 22 * * 1-5" # Lịch chạy lúc 10:00 PM các ngày trong tuần (weekdays)
jobTemplate:
spec:
template:
spec:
containers:
- name: resizer
image: bitnami/kubectl:1.35
command:
- /bin/sh
- -c
- |
kubectl get pods -l app=llm-inference -o name | while read pod; do
kubectl patch $pod --subresource resize --type merge -p \
'{"spec":{"containers":[{"name":"inference","resources":{"requests":{"cpu":"4","memory":"32Gi"},"limits":{"cpu":"8","memory":"64Gi"}}}]}}'
done
restartPolicy: OnFailure
Ước tính chi phí tiết kiệm (Cost savings estimate): Giả sử một Pod chạy tải AI inference cần cấu hình tương đương p3.2xlarge ($3.06/giờ) trong 12 giờ cao điểm (business hours), sau đó tự động thu nhỏ (downscale) xuống cấu hình tương đương m5.xlarge ($0.192/giờ) trong 12 giờ thấp điểm (off-peak hours) — mức tiết kiệm ước tính có thể đạt khoảng ~$34/ngày cho mỗi Pod.
6. Các Giới Hạn & Lưu Ý Quan Trọng (Gotchas)
Answer-first: In-Place Pod Resizing có một số giới hạn thực tế: không thể giảm giới hạn tài nguyên xuống dưới mức đang được sử dụng thực tế (currently used resources), không thể làm thay đổi QoS class của Pod, và nếu Node bị thiếu hụt tài nguyên (node-level resource scarcity), yêu cầu resize sẽ chuyển sang trạng thái hoãn lại (Deferred) vô thời hạn. Bạn cần nắm rõ các quy tắc này trước khi triển khai thực tế.
Các Giới Hạn Cứng (Hard Limitations)
| Giới Hạn (Limitation) | Giải Thích (Explanation) | Giải Pháp (Workaround) |
|---|---|---|
| Không thay đổi được QoS Class (Cannot cross QoS boundaries) | Pod thuộc QoS Class Guaranteed (requests = limits) không thể resize thành Burstable (requests < limits) và ngược lại. | Thiết lập Pod đúng QoS Class mong muốn ngay từ thời điểm tạo Pod ban đầu. |
| Node thiếu hụt tài nguyên (Node resource scarcity) | Nếu Node không còn đủ tài nguyên khả dụng, trạng thái resize của Pod sẽ chuyển thành Deferred. | Sử dụng Pod Disruption Budgets kết hợp với Cluster Autoscaler để tự động mở rộng Node khi cần. |
| Rủi ro khi giảm Memory (Memory decrease risk) | Việc giảm limit memory xuống dưới mức RSS (Resident Set Size) đang sử dụng sẽ dẫn đến sự cố OOM Kill cho container. | Chỉ nên thực hiện giảm memory cho các ứng dụng có cơ chế quản lý bộ nhớ linh hoạt (như JVM với tham số -Xmx). |
| Không hỗ trợ cho Init Containers | Tính năng In-Place Resizing chỉ áp dụng cho app containers, không áp dụng cho init containers (vì init containers chỉ chạy một lần khi khởi tạo Pod). | N/A — Init containers là các tiến trình ngắn hạn (short-lived) chỉ thực thi trước khi ứng dụng khởi chạy. |
| Ràng buộc với ResourceQuota | Yêu cầu tài nguyên mới sau khi resize vẫn phải nằm trong giới hạn cho phép của ResourceQuota được thiết lập trên Namespace. | Dự phòng (Pre-allocate) dung lượng quota dư dả để đáp ứng cho các kịch bản resize Pod khi tải tăng cao. |
| Ràng buộc với LimitRange | Mức tài nguyên mới phải nằm trong dải giá trị cho phép được định nghĩa bởi LimitRange trên Namespace. | Đảm bảo dải giá trị min/max của LimitRange phù hợp với mức resize mong muốn của Pod. |
Các Lỗi Phổ Biến Cần Tránh (Common Pitfalls)
1. Rủi ro OOM Kill khi giảm Memory:
# ❌ LỆNH NGUY HIỂM: Giảm limit memory xuống dưới mức bộ nhớ mà ứng dụng đang sử dụng
kubectl patch pod myapp --subresource resize --type merge -p \
'{"spec":{"containers":[{"name":"app","resources":{"limits":{"memory":"2Gi"}}}]}}'
# Nếu RSS của ứng dụng đang là 3Gi -> Pod sẽ bị OOM Kill ngay lập tức
2. Không cấu hình resizePolicy:
Nếu không cấu hình resizePolicy, Kubernetes sẽ tự động áp dụng giá trị mặc định là NotRequired cho cả CPU lẫn Memory. Điều này hoạt động tốt với CPU, nhưng với Memory có thể gây ra những hành vi bất ngờ đối với các ứng dụng kiểm tra memory limit khi khởi động (ví dụ: JVM với tham số -XX:MaxRAMPercentage).
3. Ghi đè bởi Deployment Rollout (Deployment rollout overrides resize):
Khi thực hiện Deployment rollout, Kubernetes sẽ tạo ra các Pod mới dựa trên spec.template.resources của Deployment. Các thay đổi In-Place Resize đã áp dụng trên các Pod cũ sẽ bị mất. Để các thay đổi resize có hiệu lực lâu dài, bạn cần cập nhật trực tiếp spec.template.resources trên Deployment spec.
4. Không theo dõi trạng thái status.resize: Deferred:
Khi Node bị quá tải tài nguyên, các yêu cầu resize sẽ ở trạng thái Deferred vô thời hạn mà không có cảnh báo tự động. Cần chủ động giám sát trạng thái này:
updateMode: "InPlace". Ở chế độ này, VPA sẽ trực tiếp cập nhật subresource resize của Pod mà không cần phải thực hiện evict (xóa Pod) và khởi tạo lại Pod mới từ đầu. Điều này giúp VPA áp dụng tốt cho các ứng dụng stateful hoặc các workload nhạy cảm với thời gian khởi động, vốn không thể chấp nhận việc gián đoạn do restart Pod theo cơ chế eviction-based truyền thống.status.resize của Pod sẽ chuyển sang trạng thái Deferred. Điều này có nghĩa là kubelet đã ghi nhận yêu cầu thay đổi kích thước, nhưng chưa thể thực hiện ngay do thiếu hụt tài nguyên trên Node. Kubelet sẽ tự động thử lại (retry) khi Node có thêm tài nguyên khả dụng. Trong trường hợp yêu cầu resize vượt quá tổng dung lượng (capacity) tối đa của Node, trạng thái sẽ chuyển thành Infeasible. Bạn có thể theo dõi metric kube_pod_status_resize để phát hiện các Pod đang bị nghẽn ở trạng thái Deferred hoặc Infeasible.