AWS帳號認證開戶 容器資源限制詳解:CPU、記憶體與資源隔離
# 容器資源限制詳解:CPU、記憶體與資源隔離
在容器環境中,資源限制不是可選項,而是部署前必須完成的基礎配置。很多線上問題看起來像應用異常,實際上是 CPU 沒有限制、記憶體配置過低、節點超分過度,或資源隔離策略不合理導致。
本文不做概念鋪陳,直接從實際操作出發,說清楚以下幾個問題:
- 容器 CPU 和記憶體應該怎麼限制
- Docker 與 Kubernetes 分別怎麼配置
- `requests` 與 `limits` 怎麼設才不容易出事故
- 為什麼容器會 OOMKilled
- 為什麼 CPU 使用率不高但服務仍然變慢
- 如何驗證限制是否真正生效
- 線上故障如何排查
---
## 一、使用者搜尋這個主題時,真正想解決的是什麼
當使用者搜尋「容器資源限制詳解:CPU、記憶體與資源隔離」時,通常不是想了解術語,而是遇到了以下實際問題:
1. 容器沒有做限制,單個服務吃滿主機資源,影響其他業務
2. Pod 經常被殺掉,但不清楚是程式問題還是記憶體不足
3. Kubernetes 已經設了資源參數,但實際效能和預期不一致
4. 同樣的服務在測試環境正常,上線後出現 CPU 節流、延遲上升
5. 想知道不同類型業務應該如何設定 CPU、記憶體、QoS 與隔離策略
所以本文重點是:怎麼配置、怎麼驗證、怎麼排錯。
---
## 二、容器資源限制最容易出問題的幾個環節
實際部署中,問題大多出在這幾步:
### 1. 只設 limits,不設 requests
這會影響 Kubernetes 排程與資源保障。Pod 可能被排到資源本就緊張的節點,導致執行期抖動。
### 2. 記憶體 limit 設太小
應用啟動正常,但流量一上來就被 OOMKilled。
### 3. CPU limit 設太低
不是直接崩潰,而是請求延遲上升、GC 變慢、吞吐下降。
### 4. 沒有區分業務型別
AWS帳號認證開戶 API 服務、批次任務、快取服務、Java 應用,資源策略完全不同,不能套一份模板。
### 5. 只看應用監控,不看容器層監控
例如應用日誌沒有報錯,但實際上是 cgroup 限制造成節流或 OOM。
---
## 三、Docker 中如何設定 CPU 與記憶體限制
如果你目前使用的是單機 Docker 或在雲伺服器上直接跑容器,資源限制通常在 `docker run` 階段完成。
## 1. 限制記憶體
### 指令範例
```bash
docker run -d \
--name myapp \
--memory=512m \
--memory-swap=512m \
nginx
```
### 參數說明
- `--memory=512m`:容器最大可用記憶體為 512MB
- `--memory-swap=512m`:總記憶體加 swap 上限也為 512MB,等於禁止額外 swap
### 為什麼建議一起設定 `--memory-swap`
如果只設定 `--memory`,沒有明確控制 swap,容器可能在記憶體吃緊時進入 swap,導致延遲顯著增加。對 API 或資料庫類服務,這種情況通常比直接失敗更難排查。
### 驗證方式
```bash
docker inspect myapp | grep -i memory
```
或查看 cgroup 資訊:
```bash
cat /sys/fs/cgroup/memory/docker//memory.limit_in_bytes
```
不同系統路徑可能略有差異,使用 cgroup v2 的環境需要改查對應目錄。
---
## 2. 限制 CPU 核心數
### 指令範例
```bash
docker run -d \
--name cpu-test \
--cpus="1.5" \
nginx
```
### 含義
- `--cpus="1.5"` 表示容器最多可使用 1.5 個 CPU 核心的計算配額
這不是綁定實體核心,而是限制可用 CPU 時間比例。
### 進階設定方式
```bash
docker run -d \
--cpu-period=100000 \
--cpu-quota=50000 \
nginx
```
以上表示每 100000 微秒週期內,最多使用 50000 微秒 CPU 時間,即 0.5 CPU。
通常直接使用 `--cpus` 更直觀。
---
## 3. 綁定 CPU 核心
對延遲敏感型應用,可以指定容器只在特定核心上執行:
```bash
docker run -d \
--name pinned-app \
--cpuset-cpus="0,1" \
nginx
```
這種方式適合:
- 高性能計算
- 某些低延遲服務
- 需要避免跨核調度抖動的場景
不適合大多數普通 Web 應用,因為會降低調度彈性。
---
## 4. Docker Compose 配置範例
```yaml
version: '3.8'
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
```
注意:
- `deploy.resources` 在不同執行模式下支援程度不同
- 若不是 Swarm 環境,需要確認 Compose 版本與執行方式
- 實務上很多團隊在本機測試時誤以為已生效,實際沒有套用成功
建議配置後立即用 `docker stats` 驗證。
---
## 四、Kubernetes 中如何設定 CPU 與記憶體限制
Kubernetes 的重點不只是限制,更包括排程、資源保障與節點分配。
最常用的是 `requests` 和 `limits`。
## 1. 基本配置範例
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: web-app
image: nginx:latest
resources:
requests:
cpu: "500m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
```
### 參數怎麼理解
- `requests.cpu: 500m`:排程時至少預留 0.5 核心
- `limits.cpu: 1`:執行時最多用 1 核心
- `requests.memory: 256Mi`:排程時保證至少 256Mi 記憶體
- `limits.memory: 512Mi`:超過 512Mi 時可能被 OOM 殺掉
---
## 2. requests 與 limits 的實務設定方法
很多文章只說兩者不同,但沒告訴你怎麼填。實務上可以這樣做。
AWS帳號認證開戶 ### 場景 A:穩定型 API 服務
適合流量較平穩、延遲敏感的服務。
建議:
- `requests` 設為平時使用量的 P95
- `limits` 設為 `requests` 的 1.5 到 2 倍
例如:
- 平時 CPU 約 300m,尖峰 700m
- 平時記憶體 220Mi,尖峰 380Mi
AWS帳號認證開戶 則可設為:
```yaml
requests:
cpu: "400m"
memory: "256Mi"
limits:
cpu: "800m"
memory: "512Mi"
```
### 場景 B:Java 應用
Java 對記憶體限制更敏感,除了 Heap,還包括 Metaspace、Thread Stack、Direct Memory。
建議:
- 不要把 JVM Heap 設到接近容器 memory limit
- 預留 20% 到 30% 給非 Heap 區域
例如容器限制 1Gi:
- `-Xmx` 建議先從 512Mi 到 700Mi 開始,而不是直接設 1024Mi
### 場景 C:批次任務 / 離線處理
這類任務可能短時間大量吃 CPU。
建議:
- `requests` 可相對保守
- `limits.cpu` 可放寬
- 記憶體一定要根據實測,不要只看平均值
### 場景 D:快取或內存型服務
如 Redis 類服務,記憶體比 CPU 更關鍵。
建議:
- memory limit 必須明確
- 應用內部淘汰策略要和容器限制配合
- 不要讓容器 OOM 當作常規淘汰手段
---
## 3. 為什麼有些 Pod 沒爆 CPU,卻明顯變慢
這通常是 CPU Throttling,也就是 CPU 節流。
AWS帳號認證開戶 當容器達到 `limits.cpu` 後,即使節點還有空閒 CPU,容器也可能被限制執行時間。表面看 CPU 使用率不一定很高,但應用延遲會上升。
### 排查方式
先看 Pod 資源:
```bash
kubectl top pod -n default
```
再看容器節流指標,常用 Prometheus 指標如:
- `container_cpu_cfs_throttled_periods_total`
- `container_cpu_cfs_throttled_seconds_total`
如果節流持續增加,代表 `limits.cpu` 可能設太低。
### 解法
- 提高 `limits.cpu`
- 對延遲敏感應用,縮小 `requests` 與 `limits` 落差
- 避免在高峰期把 CPU limit 卡得過死
---
## 五、記憶體限制與 OOMKilled 排查實戰
容器最常見的故障之一就是 OOMKilled。
## 1. 查看 Pod 是否因 OOM 被殺
```bash
kubectl describe pod -n
```
重點看:
- `Last State`
- `Reason: OOMKilled`
- `Exit Code: 137`
如果出現這些訊息,基本可以確認是記憶體超限。
---
## 2. Docker 中查看 OOM
```bash
docker inspect | grep -i oom
```
AWS帳號認證開戶 或者直接看宿主機核心日誌:
```bash
dmesg | grep -i kill
```
常見會看到類似:
```bash
Out of memory: Kill process 12345 (java)
```
---
## 3. OOM 的真正常見原因
不是只有「記憶體不夠」這麼簡單,實務上常見是:
### 原因一:應用本身有記憶體洩漏
特徵:
- 使用量持續上升
- 重啟後短暫恢復
- 流量不變但記憶體曲線持續增長
### 原因二:limit 設得過低
特徵:
- 啟動正常
- 只在高峰期或大查詢時觸發
- 擴大 limit 後立即改善
### 原因三:JVM、Node.js、Python 等執行時與容器記憶體不匹配
例如:
- Java 預設堆外內存未控制
- Node.js 預設 old space 設定不符合容器限制
- Python 多進程模型帶來額外記憶體開銷
### 原因四:快取、buffer、連接池撐大
例如:
- MySQL client 連接池過大
- Nginx buffer 調過頭
- Redis 客戶端積壓大量資料
---
## 4. 解決 OOM 的實際步驟
### 步驟 1:先確認容器限制值
```bash
kubectl get pod -o yaml
```
檢查 `resources.limits.memory`。
### 步驟 2:比對監控中的實際峰值
不要看平均值,要看峰值、尖峰時間段和 GC 前後波動。
### 步驟 3:檢查應用內部參數
例如 Java:
```bash
JAVA_OPTS="-Xms512m -Xmx512m"
```
如果容器 limit 是 512Mi,這種設定就很危險,因為還有非 Heap 記憶體。
### 步驟 4:調整 limit 並做壓測
建議每次調整 20% 到 30%,配合流量回放或壓測,不要一次翻倍後就認為問題已解決。
---
## 六、資源隔離不只是 CPU 和記憶體,還包括節點與命名空間層面
在 Kubernetes 中,單純設定 Pod 資源還不夠,還要考慮多租戶或多業務隔離。
## 1. 使用 Namespace + ResourceQuota
這適合限制某個團隊、某個專案可使用的總資源。
```yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "20"
```
作用:
- 防止某個 namespace 無限制建立 Pod
- 控制總 requests 與 limits
- 避免共享叢集中的資源失控
---
## 2. 使用 LimitRange 統一默認值
避免開發人員忘記設定資源參數。
AWS帳號認證開戶 ```yaml
apiVersion: v1
kind: LimitRange
metadata:
name: default-limit-range
namespace: default
spec:
limits:
- default:
cpu: "1"
memory: "512Mi"
defaultRequest:
cpu: "200m"
memory: "256Mi"
type: Container
```
如果沒有設定,系統可自動套用預設值。
這對共享測試環境很實用。
---
## 3. 使用節點親和性與污點隔離業務
對高負載服務,建議不要和普通業務混部。
### 做法
- 給高規格節點打標籤
- 使用 `nodeSelector` 或 `nodeAffinity`
- 必要時對節點加 taint,讓只有特定 Pod 可調度上去
範例:
```yaml
spec:
nodeSelector:
workload: high-cpu
```
適用場景:
- 高 CPU 計算型服務
- 大記憶體服務
- 需要更穩定延遲的關鍵業務
---
## 七、如何驗證容器資源限制是否真的生效
配置完成後,不驗證等於沒做。
## 1. Docker 驗證
```bash
docker stats
```
重點看:
- CPU %
- MEM USAGE / LIMIT
- 容器是否達到上限
也可以進入容器內查看:
```bash
docker exec -it myapp sh
```
然後檢查 cgroup 限制檔案。
---
## 2. Kubernetes 驗證
AWS帳號認證開戶 ### 查看資源設定
```bash
kubectl get pod -o jsonpath='{.spec.containers[*].resources}'
```
### 查看實際使用
```bash
kubectl top pod
kubectl top node
```
AWS帳號認證開戶 ### 查看事件
```bash
kubectl describe pod
```
如果有 OOM、Eviction、調度失敗,這裡通常能看到線索。
---
## 3. 壓測驗證
不要只靠靜態查看,必須在壓測下驗證。
建議觀察:
- 平均與 P99 延遲
- CPU 是否接近 limit
- 記憶體是否穩定回收
- 是否出現 throttling
- 是否有重啟或 OOM
如果只在低流量下測試,很容易誤判配置合理。
---
## 八、常見配置錯誤與對應處理方式
## 錯誤 1:只設定 memory limit,沒有設定 CPU
後果:
AWS帳號認證開戶 - 容器可能搶佔大量 CPU
- 同節點其他服務延遲上升
處理:
- 至少為每個服務設定合理的 CPU requests
- 核心服務同時設定 limits
---
## 錯誤 2:CPU limit 設太小
後果:
- 不一定報錯
- 但 RT 飆高、吞吐下降
處理:
- 檢查節流指標
- 提高 CPU limit 或改為更貼近實際需求
---
## 錯誤 3:記憶體 limit 直接等於應用啟動參數
後果:
- 啟動看似正常
- 流量一上來就 OOM
處理:
- 預留執行時額外記憶體
- 對 JVM 類應用預留至少 20% 以上餘量
---
## 錯誤 4:多個高負載 Pod 全排到同一節點
後果:
- 節點資源局部熱點
- 同機服務抖動
處理:
- 使用 Pod Anti-Affinity
- 檢查排程策略
- 為關鍵服務做節點隔離
---
## 錯誤 5:把 requests 設得過高
後果:
- Pod 難以調度
- 節點看起來有空閒,但新 Pod 起不來
處理:
- 根據歷史監控調整 requests
- 不要用理論峰值直接當 requests
---
## 九、不同業務類型的資源配置建議
以下是實務中可直接參考的思路。
## 1. Nginx / 輕量 Web 服務
建議:
- CPU:`requests 100m~200m`,`limits 500m~1`
- 記憶體:`128Mi~256Mi` 起步
- 重點觀察連線數與 buffer 使用
## 2. Java 微服務
AWS帳號認證開戶 建議:
- 記憶體先估算 Heap、非 Heap、執行緒數
- `limits.memory` 不要過緊
- CPU 盡量避免限制過低,否則 GC 容易放大延遲
## 3. Go API 服務
建議:
AWS帳號認證開戶 - 通常記憶體較可控
- CPU limit 可根據 goroutine 實際壓測調整
- 注意高併發時連線池與快取占用
## 4. Redis 類快取服務
建議:
- 明確設定 memory limit
- 應用內 maxmemory 應低於容器 limit
- 預留系統與連線緩衝空間
## 5. 批次任務
建議:
- 適合獨立節點池
- 可放寬 CPU limit,但要避免影響線上服務
- Job 結束後及時釋放資源
---
AWS帳號認證開戶 ## 十、線上故障排查流程:容器變慢、重啟、搶資源時怎麼查
下面是一套可直接落地的排查順序。
## 場景一:Pod 頻繁重啟
AWS帳號認證開戶 ### 排查步驟
1. 查看 Pod 狀態
```bash
kubectl get pod -n
```
2. 查看事件與退出原因
```bash
kubectl describe pod -n
```
3. 查看上一次容器日誌
```bash
kubectl logs --previous -n
```
4. 確認是否 OOMKilled、探針失敗、啟動超時
AWS帳號認證開戶 ### 常見結論
- `OOMKilled`:調整記憶體限制或應用參數
- `CrashLoopBackOff`:先分辨是程式崩潰還是資源不足
- `Unhealthy`:探針過嚴,或 CPU 節流導致回應慢
---
## 場景二:服務 RT 升高,但 CPU 看起來不高
### 排查步驟
1. 查容器節流指標
2. 查 GC、執行緒池、請求堆積
3. 查節點是否有資源競爭
4. 確認 CPU limit 是否設太低
AWS帳號認證開戶 ### 常見結論
- 很多情況不是 CPU 不夠,而是被限得太死
AWS帳號認證開戶 ---
## 場景三:新 Pod 一直 Pending
AWS帳號認證開戶 ### 排查步驟
```bash
kubectl describe pod
```
看事件中是否出現:
- `Insufficient cpu`
- `Insufficient memory`
- 節點親和性不匹配
- taint 無法容忍
### 常見結論
- requests 設過高
- 節點池容量不足
- 隔離策略配置錯誤
---
## 十一、容器資源限制的配置實踐建議
如果你要把這套方法真正用在線上,建議按下面順序執行。
## 建議 1:先收集基線,再定初始值
不要一上來拍腦袋填 `500m/512Mi`。
至少先收集:
- 平均 CPU
- P95 CPU
- 峰值 CPU
- 平均記憶體
- 峰值記憶體
- 啟動期與高峰期的差異
## 建議 2:所有服務都要有 requests
AWS帳號認證開戶 即使是測試環境,也應盡量補齊,否則排程結果沒有參考價值。
## 建議 3:關鍵業務避免極端超分
尤其對 API 閘道、核心交易服務、資料處理入口,不要把多個高負載容器隨意堆在同一節點。
## 建議 4:記憶體以穩為主,CPU 以測為主
- 記憶體寧可保守一點,避免 OOM
- CPU 應依壓測結果調整,不要只看監控平均值
## 建議 5:將限制驗證納入發布流程
每次新版本發布前,至少確認:
- requests / limits 是否有變更
- 啟動記憶體是否異常增加
- 壓測下是否出現 throttling
- HPA 是否會因設定不合理而誤擴縮容
---
## 十二、實用命令清單
以下命令可直接用於日常巡檢與故障排查。
### Docker
```bash
docker stats
docker inspect
docker exec -it sh
dmesg | grep -i oom
```
### Kubernetes
```bash
kubectl get pod -A
kubectl describe pod -n
kubectl top pod -n
kubectl top node
kubectl logs --previous -n
kubectl get pod -o yaml
kubectl get events -n --sort-by=.metadata.creationTimestamp
```
---
## 結語
容器資源限制的核心,不是把 CPU 和記憶體填上去就結束,而是讓服務在可控範圍內穩定運行。
真正有效的做法是:
- 根據實際監控設定 `requests` 和 `limits`
- 對不同業務類型採用不同策略
- 配置後立即驗證是否生效
- 對 OOM、節流、Pending 等問題建立固定排查流程
- 在 namespace、節點、排程層面補齊資源隔離
如果你目前正遇到容器 OOM、CPU 被限速、Pod 難以調度或多服務互相搶資源,最直接的切入點不是重啟服務,而是先檢查資源配置與隔離策略是否合理。這往往比修改程式更快見效。

