Kubernetes กลายเป็นมาตรฐานสำหรับ Container Orchestration ในปี 2026 องค์กรจำนวนมากย้ายระบบมาอยู่บน Kubernetes ทั้งบน Cloud (EKS, GKE, AKS) และ On-premise แต่ปัญหาใหญ่ที่หลายทีมพบเจอคือ ค่าใช้จ่ายที่พุ่งสูงขึ้นอย่างควบคุมไม่ได้ จากผลสำรวจพบว่าองค์กรส่วนใหญ่ใช้ทรัพยากร Kubernetes จริงๆ แค่ 30-50% ของที่จ่ายไป ที่เหลือเป็นการสูญเปล่า
บทความนี้จะสอนเทคนิคการลดค่าใช้จ่าย Kubernetes แบบครบวงจร ตั้งแต่การ Right-sizing Pods, Autoscaling, Spot Nodes ไปจนถึง FinOps Practices ที่ช่วยให้คุณลดค่าใช้จ่ายลงได้ 40-70% โดยไม่กระทบ Performance และ Reliability
ทำไมค่าใช้จ่าย Kubernetes ถึงสูงเกินจริง?
มีหลายสาเหตุที่ทำให้ค่าใช้จ่าย K8s พุ่งสูงเกินความจำเป็น:
1. Over-provisioning
Developer มักตั้ง Resource Requests สูงเกินจริง เพราะกลัว Application จะไม่เสถียร เช่น Application ใช้ CPU จริงแค่ 100m แต่ Request ไว้ 500m หรือใช้ Memory จริง 256Mi แต่ Request ไว้ 1Gi ทรัพยากรที่ Request ไว้แต่ไม่ได้ใช้ก็ยังต้องจ่ายเงิน เพราะ Kubernetes จะจองไว้ให้ Pod นั้น
2. Idle Resources
หลาย Application มี Traffic Pattern แบบ Peaks and Valleys เช่น ใช้งานมากตอนกลางวัน แต่แทบไม่มีใครใช้ตอนกลางคืนหรือวันหยุด ถ้าไม่มี Autoscaling ทรัพยากรจะถูกจองไว้ตลอด 24 ชั่วโมง
3. No Resource Limits
Pod ที่ไม่ตั้ง Resource Limits สามารถกิน CPU และ Memory ได้ไม่จำกัด ทำให้ Node ต้องใหญ่กว่าที่ควร และอาจกระทบ Pod อื่นบน Node เดียวกัน
4. Over-sized Nodes
การเลือก Node Type ที่ใหญ่เกินไป เช่น ใช้ m5.4xlarge (16 vCPU, 64GB RAM) ทั้งที่ Workload ต้องการแค่ m5.xlarge (4 vCPU, 16GB RAM) ก็ทำให้เสียเงินโดยไม่จำเป็น
Resource Requests vs Limits: พื้นฐานที่ต้องเข้าใจ
หัวใจของ K8s Cost Optimization คือการเข้าใจ Resource Requests และ Limits:
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: my-app:latest
resources:
requests: # ขั้นต่ำที่ต้องการ (Scheduler ใช้ตัดสินใจ)
cpu: "100m" # 100 milliCPU = 0.1 CPU
memory: "256Mi"
limits: # สูงสุดที่อนุญาต
cpu: "500m"
memory: "512Mi"
| Parameter | หน้าที่ | ถ้าไม่ตั้ง |
|---|---|---|
| requests.cpu | CPU ขั้นต่ำที่ Scheduler จะจองไว้ | ไม่จอง (Best-effort) |
| requests.memory | Memory ขั้นต่ำที่ Scheduler จะจองไว้ | ไม่จอง (เสี่ยง OOMKilled) |
| limits.cpu | CPU สูงสุด (Throttle เมื่อเกิน) | ใช้ได้ไม่จำกัด |
| limits.memory | Memory สูงสุด (OOMKilled เมื่อเกิน) | ใช้ได้ไม่จำกัด |
Vertical Pod Autoscaler (VPA)
VPA ช่วยปรับ Resource Requests/Limits ของ Pod อัตโนมัติตามการใช้งานจริง แทนที่คุณจะต้องมานั่งดู Monitoring แล้วปรับเอง VPA จะทำให้อัตโนมัติ:
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app-vpa
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Auto" # Auto, Recreate, Off
resourcePolicy:
containerPolicies:
- containerName: app
minAllowed:
cpu: "50m"
memory: "128Mi"
maxAllowed:
cpu: "2000m"
memory: "4Gi"
controlledResources: ["cpu", "memory"]
VPA มี 3 โหมดการทำงาน:
- Off: แค่แนะนำ (Recommendation Only) ไม่เปลี่ยนอะไร เหมาะสำหรับเริ่มต้น
- Auto/Recreate: ปรับ Requests อัตโนมัติ (ต้อง Restart Pod) เหมาะเมื่อมั่นใจแล้ว
- Initial: ตั้ง Requests ตอนสร้าง Pod ใหม่เท่านั้น ไม่แก้ Pod ที่ทำงานอยู่
Horizontal Pod Autoscaler (HPA)
HPA เพิ่ม/ลดจำนวน Pod ตามโหลด ช่วยให้ใช้ทรัพยากรตรงกับ Traffic จริง:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Scale เมื่อ CPU > 70%
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # รอ 5 นาทีก่อน Scale Down
policies:
- type: Percent
value: 10
periodSeconds: 60 # ลดได้ไม่เกิน 10% ต่อนาที
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Percent
value: 100
periodSeconds: 60 # เพิ่มได้ 100% ต่อนาที
KEDA: Event-Driven Autoscaling
KEDA (Kubernetes Event-Driven Autoscaling) ขยายความสามารถของ HPA ให้ Scale ได้ตาม Event Sources ที่หลากหลาย ไม่ใช่แค่ CPU/Memory:
# ติดตั้ง KEDA
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda-system
---
# ScaledObject: Scale ตามจำนวน Messages ใน Queue
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-processor
spec:
scaleTargetRef:
name: order-processor
minReplicaCount: 0 # Scale to Zero ได้!
maxReplicaCount: 50
triggers:
- type: rabbitmq
metadata:
queueName: orders
host: amqp://rabbitmq.default.svc
queueLength: "10" # 1 Pod ต่อ 10 messages
- type: prometheus # Scale ตาม Custom Metrics
metadata:
serverAddress: http://prometheus:9090
metricName: http_requests_total
threshold: "100"
query: sum(rate(http_requests_total[2m]))
KEDA สามารถ Scale to Zero ได้ ซึ่งเป็นสิ่งที่ HPA ปกติทำไม่ได้ ทำให้ Workload ที่ไม่มีงาน (เช่น Queue Worker ที่ Queue ว่าง) จะไม่ใช้ทรัพยากรเลย ประหยัดค่าใช้จ่ายได้อย่างมาก
Cluster Autoscaler
Cluster Autoscaler ทำงานระดับ Node โดยจะเพิ่ม/ลด Node ตามความต้องการ:
# ติดตั้งบน AWS EKS
helm install cluster-autoscaler autoscaler/cluster-autoscaler \
--set autoDiscovery.clusterName=my-cluster \
--set awsRegion=ap-southeast-1 \
--set extraArgs.scale-down-delay-after-add=10m \
--set extraArgs.scale-down-unneeded-time=10m \
--set extraArgs.skip-nodes-with-local-storage=false
Cluster Autoscaler จะเพิ่ม Node เมื่อมี Pod ที่ Pending (ไม่มี Node ว่างพอ) และลด Node เมื่อ Node มี Utilization ต่ำกว่า Threshold (ปกติ 50%) โดยจะย้าย Pod ไป Node อื่นก่อนลบ Node
Karpenter: ทางเลือกที่ฉลาดกว่า
Karpenter เป็น Node Provisioner จาก AWS ที่ทำงานเร็วกว่า Cluster Autoscaler มาก (30 วินาที vs หลายนาที) และฉลาดกว่าในการเลือก Node Type ที่เหมาะสม:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
requirements:
- key: "karpenter.sh/capacity-type"
operator: In
values: ["on-demand", "spot"] # ใช้ Spot ได้
- key: "node.kubernetes.io/instance-type"
operator: In
values: ["m5.large", "m5.xlarge", "m6i.large", "c5.large"]
- key: "topology.kubernetes.io/zone"
operator: In
values: ["ap-southeast-1a", "ap-southeast-1b"]
limits:
cpu: "100"
memory: "400Gi"
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 30s
Spot/Preemptible Nodes: ประหยัดได้ 60-90%
Spot Instances (AWS) หรือ Preemptible VMs (GCP) มีราคาถูกกว่า On-demand 60-90% แต่อาจถูกเรียกคืนได้ทุกเมื่อ สำหรับ Kubernetes ถ้าจัดการให้ดี Spot Nodes ปลอดภัยมาก:
แยก Node Pool
# On-demand Node Pool สำหรับ Critical Workloads
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
managedNodeGroups:
- name: on-demand-critical
instanceType: m5.xlarge
minSize: 2
maxSize: 5
labels:
workload-type: critical
# Spot Node Pool สำหรับ Non-critical Workloads
- name: spot-general
instanceTypes: ["m5.large", "m5.xlarge", "m6i.large", "c5.large"]
spot: true
minSize: 0
maxSize: 20
labels:
workload-type: general
ใช้ Node Affinity + Tolerations
apiVersion: apps/v1
kind: Deployment
metadata:
name: batch-processor
spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: workload-type
operator: In
values: ["general"]
tolerations:
- key: "spot"
operator: "Equal"
value: "true"
effect: "NoSchedule"
Pod Disruption Budget (PDB)
# ป้องกันไม่ให้ Spot Eviction ทำให้ Service ล่ม
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: my-app-pdb
spec:
minAvailable: 2 # ต้องมี Pod ทำงานอยู่อย่างน้อย 2 ตัวเสมอ
selector:
matchLabels:
app: my-app
Namespace Resource Quotas และ LimitRanges
ป้องกันไม่ให้ทีมใดทีมหนึ่งใช้ทรัพยากรเกินกว่าที่ควร:
# ResourceQuota: จำกัดทรัพยากรรวมของ Namespace
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
requests.cpu: "10" # รวม CPU Request ไม่เกิน 10 cores
requests.memory: "20Gi" # รวม Memory Request ไม่เกิน 20GB
limits.cpu: "20"
limits.memory: "40Gi"
pods: "50" # จำนวน Pod ไม่เกิน 50
---
# LimitRange: กำหนดค่า Default สำหรับ Pod ที่ไม่ได้ตั้ง
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-alpha
spec:
limits:
- default: # Default Limits
cpu: "500m"
memory: "512Mi"
defaultRequest: # Default Requests
cpu: "100m"
memory: "128Mi"
max: # Maximum ที่ตั้งได้
cpu: "4"
memory: "8Gi"
min: # Minimum ที่ต้องตั้ง
cpu: "50m"
memory: "64Mi"
type: Container
LimitRange สำคัญมาก เพราะถ้า Pod ไหนไม่ได้ตั้ง Resources มันจะใช้ค่า Default ที่คุณกำหนด ป้องกันไม่ให้มี Pod ที่กิน Resource ไม่จำกัด
Cost Monitoring Tools
Kubecost
Kubecost เป็นเครื่องมือ Open Source ที่แสดงค่าใช้จ่ายของ K8s แบบ Real-time แยกตาม Namespace, Deployment, Pod, Label หรือ Team:
# ติดตั้ง Kubecost
helm install kubecost cost-analyzer \
--repo https://kubecost.github.io/cost-analyzer/ \
--namespace kubecost --create-namespace \
--set kubecostToken="YOUR_TOKEN"
# เข้าถึง Dashboard
kubectl port-forward -n kubecost svc/kubecost-cost-analyzer 9090:9090
Kubecost ให้ข้อมูลที่สำคัญ เช่น ค่าใช้จ่ายต่อ Namespace ต่อวัน ทรัพยากรที่ใช้จริง vs ที่ Request ไว้ คำแนะนำ Right-sizing และ Savings Potential ถ้าปรับตามคำแนะนำ
OpenCost
OpenCost เป็นโปรเจกต์ CNCF ที่เป็น Open Source ทั้งหมด ทำงานคล้าย Kubecost แต่ไม่มี Commercial License:
# ติดตั้ง OpenCost
helm install opencost opencost/opencost \
--namespace opencost --create-namespace
CloudHealth / Spot.io / Datadog Cost Management
สำหรับองค์กรขนาดใหญ่ที่ต้องการ Enterprise Features เช่น Multi-cloud Cost Visibility, Chargeback/Showback, Budget Alerts และ Anomaly Detection เครื่องมือเหล่านี้มี Features ครบกว่า แต่มีค่าใช้จ่ายเพิ่ม
Right-sizing Tools
Goldilocks
Goldilocks จาก Fairwind ช่วย Visualize คำแนะนำ Right-sizing จาก VPA:
# ติดตั้ง Goldilocks
helm install goldilocks fairwinds-stable/goldilocks \
--namespace goldilocks --create-namespace
# เปิดใช้งานสำหรับ Namespace ที่ต้องการ
kubectl label namespace my-app goldilocks.fairwinds.com/enabled=true
# เข้า Dashboard
kubectl port-forward -n goldilocks svc/goldilocks-dashboard 8080:80
Goldilocks จะสร้าง VPA แบบ Recommendation Mode สำหรับทุก Deployment ใน Namespace ที่ Label ไว้ แล้วแสดงคำแนะนำว่าควรตั้ง Requests/Limits เท่าไหร่ผ่าน Web Dashboard ที่อ่านง่าย
KRR (Kubernetes Resource Recommender)
KRR จาก Robusta เป็น CLI Tool ที่ดึงข้อมูลจาก Prometheus แล้วแนะนำ Right-sizing:
# ติดตั้ง
pip install krr
# Scan ทั้ง Cluster
krr simple
# ผลลัพธ์จะแสดง:
# Deployment | CPU Req | CPU Rec | Memory Req | Memory Rec | Savings
# my-app | 500m | 120m | 1Gi | 280Mi | $45/mo
# api-gateway | 1000m | 350m | 2Gi | 800Mi | $78/mo
Multi-tenancy และ Cost Sharing
ในองค์กรที่มีหลายทีมใช้ K8s Cluster ร่วมกัน การแบ่งค่าใช้จ่ายเป็นเรื่องสำคัญ:
Chargeback vs Showback
- Chargeback: เรียกเก็บเงินจริงจากแต่ละทีม ตาม Resource Usage
- Showback: แสดงค่าใช้จ่ายให้เห็น แต่ไม่ได้เรียกเก็บจริง (ช่วยให้ทีมตระหนักถึงค่าใช้จ่าย)
# ใช้ Labels สำหรับ Cost Allocation
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
labels:
team: "platform"
environment: "production"
cost-center: "CC-1234"
project: "user-service"
การใช้ Labels อย่างเป็นระบบช่วยให้ Kubecost หรือ OpenCost สามารถ Aggregate ค่าใช้จ่ายตามทีม ตาม Project หรือตาม Cost Center ได้อัตโนมัติ
Bin-packing และ Cluster Consolidation
Bin-packing คือการจัด Pod ให้อยู่บน Node น้อยที่สุดเท่าที่จะเป็นไปได้ เพื่อลดจำนวน Node ที่ต้องจ่ายเงิน:
Descheduler
Kubernetes Scheduler จัด Pod ลง Node แค่ตอนสร้าง Pod ใหม่ ไม่ได้จัดใหม่เมื่อ Cluster เปลี่ยนแปลง Descheduler ช่วยย้าย Pod ไปรวมกันเพื่อ Consolidation:
apiVersion: descheduler/v1alpha2
kind: DeschedulerPolicy
profiles:
- name: consolidation
pluginConfig:
- name: LowNodeUtilization
args:
thresholds:
cpu: 20 # Node ที่ใช้ CPU < 20% ถือว่า Underutilized
memory: 20
targetThresholds:
cpu: 50 # ย้าย Pod ไปจนกว่า Node จะใช้ CPU 50%
memory: 50
- name: RemoveDuplicates # ลบ Pod ซ้ำบน Node เดียวกัน
plugins:
balance:
enabled:
- LowNodeUtilization
- RemoveDuplicates
Reserved Instances สำหรับ K8s Nodes
สำหรับ Workload ที่ต้องทำงานตลอด 24 ชั่วโมง (Baseline Capacity) การใช้ Reserved Instances ประหยัดได้มากกว่า On-demand:
| ประเภท | ส่วนลด | เหมาะกับ |
|---|---|---|
| On-demand | 0% | ทดลอง, Burst Traffic |
| Spot/Preemptible | 60-90% | Fault-tolerant Workloads |
| Reserved (1 ปี) | 30-40% | Baseline ที่ใช้ตลอด |
| Reserved (3 ปี) | 50-60% | Baseline ที่มั่นใจมาก |
| Savings Plans | 30-50% | ยืดหยุ่นกว่า RI |
กลยุทธ์ผสม
# แนวทาง 3-Tier Node Strategy
# 1. Reserved Instances: 40% ของ Capacity (Baseline)
# - System Pods (kube-system, monitoring)
# - Database, StatefulSets
# - Critical Services ที่ต้องทำงานตลอด
# 2. On-demand: 20% ของ Capacity (Buffer)
# - Critical Workloads ที่ทนต่อ Interruption ไม่ได้
# - ช่วง Scale Up ก่อนที่ Spot จะพร้อม
# 3. Spot Instances: 40% ของ Capacity (Variable)
# - Stateless Web Servers
# - Queue Workers
# - Batch Processing
# - CI/CD Runners
FinOps สำหรับ Kubernetes
FinOps (Cloud Financial Operations) เป็นแนวปฏิบัติที่ช่วยให้ทีม Engineering, Finance และ Business ทำงานร่วมกันเพื่อจัดการค่าใช้จ่าย Cloud อย่างมีประสิทธิภาพ:
หลักการ FinOps สำหรับ K8s
- Visibility: ทุกคนต้องเห็นค่าใช้จ่ายของทีมตัวเอง (ใช้ Kubecost Dashboard)
- Optimization: มี Process Right-sizing เป็นประจำ (ทุกเดือน Review คำแนะนำ VPA)
- Governance: ตั้งกฎเกณฑ์ เช่น LimitRanges, ResourceQuotas, Budget Alerts
- Accountability: แต่ละทีมรับผิดชอบค่าใช้จ่ายของตัวเอง
Automation สำหรับ FinOps
# ตัวอย่าง: GitHub Actions สำหรับ Right-sizing Review รายเดือน
name: Monthly K8s Cost Review
on:
schedule:
- cron: '0 9 1 * *' # วันที่ 1 ของทุกเดือน เวลา 9:00
jobs:
cost-review:
runs-on: ubuntu-latest
steps:
- name: Run KRR Scan
run: |
pip install krr
krr simple --format json > krr-report.json
- name: Generate Report
run: |
python generate_cost_report.py
- name: Send to Slack
uses: slackapi/slack-github-action@v2
with:
payload: |
{"text": "Monthly K8s Cost Report is ready!"}
Checklist: ลดค่าใช้จ่าย K8s ทันที
เรียงตามผลกระทบจากมากไปน้อย:
- ติดตั้ง Cost Monitoring (Kubecost/OpenCost) เพื่อเห็นค่าใช้จ่ายจริง
- Right-size Pods ดู Usage จริงแล้วปรับ Requests/Limits ให้ตรง (ประหยัดได้ 20-40%)
- เปิด HPA สำหรับทุก Deployment ที่ Traffic ไม่คงที่ (ประหยัดได้ 10-30%)
- ใช้ Spot Nodes สำหรับ Stateless Workloads (ประหยัดได้ 40-70%)
- ตั้ง LimitRanges ทุก Namespace เพื่อป้องกัน Over-provisioning
- ใช้ Cluster Autoscaler/Karpenter เพื่อลด Node ที่ไม่ได้ใช้
- ซื้อ Reserved Instances สำหรับ Baseline Capacity
- ใช้ KEDA สำหรับ Event-driven Workloads ที่ Scale to Zero ได้
- ตั้ง ResourceQuotas สำหรับ Multi-tenant Clusters
- Review ค่าใช้จ่ายทุกเดือน เป็น FinOps Practice
สรุป
ค่าใช้จ่าย Kubernetes ไม่จำเป็นต้องสูงเกินจริง ด้วยเทคนิคที่กล่าวมาในบทความนี้ ตั้งแต่การ Right-sizing Pods ด้วย VPA และ Goldilocks การ Autoscaling ด้วย HPA และ KEDA การใช้ Spot Nodes อย่างปลอดภัย ไปจนถึงการสร้างวัฒนธรรม FinOps ในองค์กร คุณสามารถลดค่าใช้จ่ายลงได้ 40-70% โดยไม่กระทบ Performance และ Reliability ของระบบ
เริ่มต้นวันนี้ด้วยการติดตั้ง Kubecost หรือ OpenCost เพื่อเห็นค่าใช้จ่ายจริงของ Cluster ก่อน จากนั้นค่อยๆ ปรับ Right-sizing และเปิด Autoscaling ทีละส่วน ค่าใช้จ่ายที่ประหยัดได้จะทำให้ทั้งทีม Engineering และ Management มีความสุข
