Hóa đơn AWS tháng đến và con số bên cạnh EKS dev cluster khiến tôi phải dừng lại ngay. $847 cho một cluster mà developer chỉ thực sự dùng khoảng 10 tiếng mỗi ngày, 5 ngày một tuần. Tức là 50 giờ sử dụng thực tế so với 718 giờ bị tính phí.
Năm mươi đô mỗi ngày cho compute chạy không tải thực sự khó biện hộ: workload dev và staging chạy 24/7 dù chẳng ai đụng vào sau 7 giờ tối hay cuối tuần. Node vẫn chạy, pod vẫn hoạt động, và AWS vẫn tính tiền đều đặn. Đây là kiểu lãng phí cloud điển hình âm thầm tích lũy — và là loại mà chỉ cần một file YAML là có thể giải quyết phần lớn.
Vấn Đề Thực Tế: Kubernetes Không Bao Giờ Ngủ
Staging cluster của chúng tôi có 14 Deployments và 3 StatefulSets trải trên hai namespace. Vào một tối thứ Ba lúc 11 giờ đêm, CPU utilization dưới 2% trên tất cả pod. Mọi process đều nhàn rỗi, chờ đợi tải không đến cho đến 8 giờ sáng hôm sau. Nhưng các node không biết điều đó. Chúng cứ tiếp tục chạy, vì đó là việc Kubernetes node làm.
Cuối tuần còn tệ hơn, không chỉ qua đêm. Bốn mươi tám giờ compute không tạo ra bất kỳ giá trị gì, lặp lại mỗi tuần. Với tuần làm việc 5 ngày và giờ hoạt động từ 8 giờ sáng đến 8 giờ tối, bạn đang trả tiền cho workload chỉ thực sự hữu ích khoảng 35% thời gian.
Nguyên Nhân Gốc Rễ: Kubernetes Được Thiết Kế cho High Availability, Không Phải Tối Ưu Chi Phí
Khi bạn deploy thứ gì đó lên Kubernetes, nó sẽ chạy cho đến khi bạn dừng lại một cách tường minh. Nền tảng này không có khái niệm lịch trình “giờ làm việc” nào cả. Kubernetes mặc định bạn muốn workload luôn sẵn sàng — điều này hoàn toàn hợp lý với production, nhưng lại tạo ra lãng phí không cần thiết trong môi trường dev và staging.
Horizontal Pod Autoscaler (HPA) scale dựa trên các chỉ số CPU và memory. Nó giúp xử lý traffic spike, nhưng HPA bắt buộc số replica tối thiểu là 1 — không thể scale workload xuống zero hoàn toàn. Đây là giới hạn kiến trúc cứng, không phải vấn đề cấu hình. Để đạt được zero thực sự cần KEDA hoặc một công cụ dựa trên lịch trình như kube-green.
Cluster dev và staging kế thừa hành vi luôn bật của production, ngay cả khi không ai nhìn vào lúc 3 giờ sáng Chủ nhật. Nền tảng không có gì để ngăn chặn điều đó.
Các Giải Pháp Tôi Đã So Sánh Trước Khi Chọn Kube-green
Scale Thủ Công bằng kubectl
Cả team đồng ý chạy kubectl scale deployment --replicas=0 trước khi rời đi mỗi tối. Cách này hoạt động được khoảng hai tuần. Rồi mọi người bắt đầu quên, hoặc để deployment ở 1 replica “phòng khi cần.” Quy trình thủ công không thể tồn tại qua những lần chuyển context của developer.
CronJob Bash Tự Viết
Tôi đã viết một Kubernetes CronJob để scale tất cả Deployments trong một số namespace xuống zero lúc 8 giờ tối và tăng lại lúc 8 giờ sáng. Nó hoạt động — cho đến khi không còn hoạt động nữa. Script không lưu số replica ban đầu ở đâu cả, nên mọi thứ thức dậy với 1 replica. Các service cần 3+ replica để health check pass bắt đầu thất bại, và tôi mất một buổi sáng debug thứ trông như crash ứng dụng nhưng thực ra chỉ là thiếu replica.
KEDA (Kubernetes Event-Driven Autoscaler)
KEDA có thể scale workload xuống zero dựa trên các nguồn sự kiện bên ngoài. Nó rất phù hợp cho các service dựa trên queue, nhưng dùng nó chỉ để tắt mọi thứ vào ban đêm giống như dùng búa tạ để đóng đinh ghim. Mỗi Deployment sẽ cần ScaledObject riêng, và quản lý chúng trên nhiều namespace tạo ra overhead vận hành còn nhiều hơn vấn đề ban đầu.
Kube-green
Được xây dựng đặc biệt cho việc tạm dừng theo lịch. Một CRD mỗi namespace, định nghĩa khi nào sleep và khi nào thức dậy, xong. Nó lưu số replica ban đầu dưới dạng annotation trước khi scale xuống zero, rồi khôi phục chính xác khi thức dậy. Sáu tháng chạy trên dev và staging — không có phantom restart, không có lần wakeup bị bỏ lỡ, không có alert on-call vì staging quên mở lại. Kết quả nhất quán và ổn định.
Cài Đặt Kube-green: Hướng Dẫn Thực Tế
Cài Đặt qua Helm
helm repo add kube-green https://kube-green.dev/helm-charts
helm repo update
helm install kube-green kube-green/kube-green \
--namespace kube-green \
--create-namespace
Xác nhận operator đang chạy:
kubectl get pods -n kube-green
# NAME READY STATUS RESTARTS AGE
# kube-green-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
Tài Nguyên SleepInfo
Đây là toàn bộ bề mặt cấu hình của kube-green — một file YAML cho mỗi namespace:
apiVersion: kube-green.com/v1alpha1
kind: SleepInfo
metadata:
name: dev-sleep-schedule
namespace: development
spec:
weekdays: "1-5" # Thứ Hai đến Thứ Sáu
sleepAt: "20:00" # Ngủ lúc 8 giờ tối
wakeUpAt: "08:00" # Thức dậy lúc 8 giờ sáng
timeZone: "Asia/Tokyo"
suspendDeployments: true
suspendStatefulSets: true
suspendCronJobs: true
kubectl apply -f dev-sleep-schedule.yaml
Kube-green ghi số replica ban đầu vào annotation của mỗi resource trước khi scale xuống zero. Khi thức dậy, nó đọc các annotation đó và khôi phục chính xác những gì đã có trước đó. Không có configuration drift, không đoán mò.
Staging với Giờ Khác và Các Ngoại Lệ
Staging thường hoạt động muộn hơn cho các QA run. Bạn có thể cấu hình lịch riêng và loại trừ các workload cụ thể khỏi quá trình tạm dừng:
apiVersion: kube-green.com/v1alpha1
kind: SleepInfo
metadata:
name: staging-sleep-schedule
namespace: staging
spec:
weekdays: "1-5"
sleepAt: "23:00" # Muộn hơn cho QA testing
wakeUpAt: "07:30" # Sớm cho smoke test buổi sáng
timeZone: "Asia/Tokyo"
suspendDeployments: true
suspendStatefulSets: false # Giữ database chạy
excludeRef:
- apiVersion: apps/v1
kind: Deployment
name: monitoring-agent # Luôn giữ cái này hoạt động
Dùng excludeRef cho monitoring agent hoặc bất kỳ service nào mà health check bên ngoài phụ thuộc vào. Kube-green bỏ qua hoàn toàn những thứ đó trong chu kỳ tạm dừng.
Kiểm Tra Trạng Thái và Debug
# Xem trạng thái sleep hiện tại
kubectl get sleepinfo -n development
# NAME SLEEP AT WAKE UP AT WEEKDAYS TIMEZONE STATUS
# dev-sleep-schedule 20:00 08:00 1-5 Asia/Tokyo Sleeping
# Kiểm tra số replica đã lưu trên các deployment đang tạm dừng
kubectl get deployments -n development -o jsonpath=\
'{range .items[*]}{.metadata.name}: replicas={.metadata.annotations.sleepinfo\.kube-green\.dev/replicas}{"\n"}{end}'
Ghi Đè Thủ Công Khi Cần
Khi developer cần môi trường hoạt động vào thứ Bảy, họ chỉ cần scale deployment trực tiếp:
kubectl scale deployment my-app --replicas=2 -n development
Kube-green sẽ không chống lại bạn. Nó đọc số replica hiện tại vào thời điểm sleep và lưu bất cứ thứ gì đang có. Vào lần wakeup theo lịch tiếp theo, hoạt động bình thường tiếp tục mà không cần dọn dẹp thủ công.
Những Gì Kube-green Không Bao Gồm
Kube-green tạm dừng workload — nó không quản lý infrastructure trực tiếp. Trên Kubernetes có quản lý (EKS, GKE, AKS), control plane của bạn vẫn chạy bất kể. Tiết kiệm chi phí node chỉ thực sự xảy ra nếu cluster autoscaler thực sự xóa node khi pod đã biến mất. Đảm bảo node group hỗ trợ scale-to-zero:
# Xác nhận kích thước tối thiểu của EKS node group
aws eks describe-nodegroup \
--cluster-name my-cluster \
--nodegroup-name dev-workers \
--query 'nodegroup.scalingConfig'
# Nên hiển thị minSize: 0 hoặc 1
Ngoài ra: Chi phí PersistentVolume không dừng lại khi pod sleep. Volume EBS tính phí theo giờ dù có được gắn vào hay không. Với môi trường dev thực sự chi phí thấp, hãy cân nhắc ephemeral storage cho dữ liệu không quan trọng, hoặc chấp nhận rằng chi phí storage là khoản nhỏ hơn đáng để bỏ qua.
Con Số Thực Tế Sau Sáu Tháng
Trước khi có kube-green, dev cluster của chúng tôi trung bình 8 node chạy 24/7. Sau đó — với cluster autoscaler xóa node khi pod đã biến mất — chúng tôi thường giảm xuống còn 1–2 node trong giờ ngoài làm việc. Hóa đơn hàng tháng giảm từ ~$847 xuống còn ~$290. Staging có kết quả tương tự: giảm khoảng 65% trên cả hai môi trường.
Chi phí vận hành gần như bằng không. Sau 30 phút setup ban đầu và một tuần theo dõi thời gian wakeup, hệ thống chạy mà không cần can thiệp gì. Developer hầu như không để ý đến lịch — thời gian thức dậy buổi sáng có nghĩa là môi trường sẵn sàng trước khi mọi người uống xong tách cà phê đầu tiên.
Tác dụng phụ thú vị hơn là về văn hóa. Trước đây, không ai nghĩ đến việc liệu tài nguyên dev có cần thiết ở quy mô đó không. Giờ đây, sự minh bạch về chi phí đã khơi dậy các cuộc trò chuyện về right-sizing: tại sao một Deployment dev cần 3 replica? Tại sao StatefulSet đó được cấu hình 4Gi memory khi staging test chưa bao giờ gần đạt đến giới hạn? Kube-green đã giúp việc sở hữu tài nguyên trở nên rõ ràng theo cách mà billing dashboard đơn thuần không bao giờ làm được.
Nếu cluster dev hoặc staging của bạn đang chạy suốt ngày đêm mà không có chiến lược tạm dừng, đây là con đường nhanh nhất đến khoản tiết kiệm đáng kể — ba mươi phút setup, $557 trở lại ngân sách hàng tháng của bạn, mỗi tháng. CRD đơn giản, operator nhẹ, và khoản tiết kiệm đó tích lũy lại mỗi cuối tuần.

