iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0

昨天把 Probe 都說明清楚了,今天要學 Resource Request 和 Limit,設定每個 Pod 能用多少 CPU 和記憶體 。


沒有設定 Resource 的風險

目前的 Todo App 每個 Pod 都沒有設定資源限制,這在生產環境是危險的。

假設 todo-api 突然接到大量請求,CPU 使用率飆升,開始吃掉同一台 Node 上其他 Pod 的資源。其他服務(例如 MySQL)因為拿不到足夠的 CPU,開始變慢甚至崩潰——一個服務的問題,拖垮了整台 Node 上的所有服務。

Resource Request 和 Limit 就是用來避免這個情況的。


Request 和 Limit 是什麼

Request(請求量):K8s 在調度 Pod 的時候,保留給這個 Pod 的資源量。

Scheduler 在決定 Pod 要跑在哪個 Node 的時候,會根據 Request 計算「這個 Node 還有沒有足夠的資源」。如果 Node 的可用資源小於 Pod 的 Request,這個 Pod 就不會被調度到這個 Node。

Limit(上限):Pod 最多能用多少資源。**

  • CPU Limit:超過上限,Pod 的 CPU 使用率會被限流(throttle),不會被殺掉
  • Memory Limit:超過上限,Pod 會被 OOMKilled(Out of Memory Kill),K8s 重啟它

CPU 和記憶體的單位

CPU:

  • 1 = 1 顆 vCPU / 1 個核心
  • 0.5 或 500m = 半顆 CPU(m 是 millicores,1000m = 1 CPU)

記憶體:

  • 128Mi = 128 Mebibytes(1 Mi = 1024 * 1024 bytes)
  • 1Gi = 1 Gibibyte
  • 128M、1G 是 SI 單位(1 M = 1000 * 1000 bytes),K8s 建議用 Mi、Gi

實際操作

今天目標:幫 todo-api、todo-frontend、MySQL 三個服務各加上 Resource Request 和 Limit,啟用 metrics-server 後用 kubectl top 確認各 Pod 的當前實際資源使用狀況。

Step1: 幫 todo-api 加上 Resource 設定

更新 todo-api-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: todo-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: todo-api
  template:
    metadata:
      labels:
        app: todo-api
        tier: backend
    spec:
      containers:
        - name: api
          image: yourname/todo-app-api:v1.0.0
          ports:
            - containerPort: 8000
          envFrom:
            - configMapRef:
                name: todo-api-config
            - secretRef:
                name: todo-api-secret
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 15
            periodSeconds: 10
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /ready
              port: 8000
            initialDelaySeconds: 5
            periodSeconds: 5
            failureThreshold: 3
          resources:
            requests:
              cpu: "100m"       # 最少需要 0.1 顆 CPU
              memory: "128Mi"   # 最少需要 128MB 記憶體
            limits:
              cpu: "500m"       # 最多使用 0.5 顆 CPU
              memory: "256Mi"   # 最多使用 256MB 記憶體
kubectl apply -f todo-api-deployment.yaml

Step2: 幫 todo-frontend 加上 Resource 設定

前端是 nginx serve 靜態檔案,資源需求比後端少。
調整 todo-frontend-deployment.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: todo-frontend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: todo-frontend
  template:
    metadata:
      labels:
        app: todo-frontend
        tier: frontend
    spec:
      containers:
        - name: frontend
          image: yourname/todo-frontend:v1.0.0
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: "50m"      # 調度時保留 0.05 顆 CPU
              memory: "64Mi"  # 調度時保留 64MB 記憶體
            limits:
              cpu: "200m"     # 最多使用 0.2 顆 CPU,超過會被限流
              memory: "128Mi" # 最多使用 128MB 記憶體,超過會 OOMKilled
kubectl apply -f todo-frontend-deployment.yaml

Step3: 幫 MySQL 加上 Resource 設定

資料庫需要比較多記憶體,調整 mysql-statefulset.yaml :

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-headless
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
        tier: database
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          ports:
            - containerPort: 3306
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_ROOT_PASSWORD
            - name: MYSQL_DATABASE
              value: "tododb"
            - name: MYSQL_USER
              value: "user"
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: MYSQL_PASSWORD
          livenessProbe:
            exec:
              command:
                - /bin/sh
                - -c
                - mysqladmin ping -h localhost -u root -p${MYSQL_ROOT_PASSWORD}
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3
          volumeMounts:
            - name: mysql-data
              mountPath: /var/lib/mysql
          resources:
            requests:
              cpu: "500m"
              memory: "1Gi"
            limits:
              cpu: "500m"     # 和 request 相同,確保 Guaranteed
              memory: "1Gi"   # 和 request 相同,確保 Guaranteed
  volumeClaimTemplates:
    - metadata:
        name: mysql-data
      spec:
        accessModes:
          - ReadWriteOnce
        resources:
          requests:
            storage: 5Gi
kubectl apply -f mysql-statefulset.yaml

Step4: 確認 Resource 設定

# 取得 Pod
kubectl get pod

kubectl describe pod <todo-api-pod-name>

在輸出裡找 Limits 和 Requests 欄位:

https://ithelp.ithome.com.tw/upload/images/20260921/20183863G31jLqcfDz.png

Step5: 看當前資源使用狀況

前置步驟:啟用 metrics-server

kubectl top 需要 metrics-server 才能運作,minikube 預設沒有啟用,先執行:

minikube addons enable metrics-server

啟用後等約 1 分鐘讓它開始收集資料,再執行以下指令。

看當前 Node 資源使用:

kubectl top nodes

https://ithelp.ithome.com.tw/upload/images/20260921/201838635gvuVAMkNv.png

看當前各 Pod 的資源使用:

kubectl top pods

https://ithelp.ithome.com.tw/upload/images/20260921/20183863eY1wTsyWjE.png


延伸筆記:QoS 等級

K8s 根據 Pod 的 Resource 設定,自動分配三種 QoS(Quality of Service)等級。當 Node 資源不足需要驅逐 Pod 的時候,K8s 會優先驅逐 QoS 等級低的 Pod。

  1. Guaranteed:Request 和 Limit 都設定,且兩者相等。
    最高優先級,Node 資源不足時最後被驅逐。適合對穩定性要求最高的服務(例如資料庫)。
resources:
  requests:
    cpu: "500m"
    memory: "256Mi"
  limits:
    cpu: "500m"      # 和 request 相同
    memory: "256Mi"  # 和 request 相同
  1. Burstable:設定了 Request 和 Limit,但兩者不相等;或只設定了其中一個。
    中等優先級,平常用 Request 的量,有需要可以 burst 到 Limit。適合大多數服務( 例如 todo-api 、 todo-frontend )。
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "500m"
    memory: "256Mi"
  1. BestEffort:完全沒有設定 Resource。
    最低優先級,Node 資源不足時第一個被驅逐。生產環境不建議用這個等級。

小結

今天學了 Resource Request 和 Limit:

  • Request:調度時保留的資源,影響 Pod 能否被調度到某個 Node
  • Limit:執行時的資源上限,CPU 超過會限流,Memory 超過會被 OOMKilled
  • QoS 等級由 Resource 設定決定,影響 Node 資源不足時的驅逐優先順序

明天會學 Namespace,把不同環境的資源隔離開來 !


上一篇
Day 15|Readiness Probe
下一篇
Day 17|Namespace
系列文
從零學 K8s|30 天核心概念 × 實作,新手也能真正掌握 Kubernetes 共 19 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言