# 管理容器的計算資源
當您定義 [Pod](http://kubernetes.io/docs/user-guide/pods) 的時候可以選擇為每個容器指定需要的 CPU 和內存(RAM)大小。當為容器指定了資源請求后,調度器就能夠更好的判斷出將容器調度到哪個節點上。如果您還為容器指定了資源限制,節點上的資源就可以按照指定的方式做競爭。
## 資源類型
*CPU* 和 *memory* 都是 *資源類型*。資源類型具有基本單位。CPU 的單位是 core,memory 的單位是 byte。
CPU和內存統稱為*計算資源*,也可以稱為*資源*。計算資源的數量是可以被請求、分配和消耗的可測量的。它們與 [API 資源](https://kubernetes.io/docs/api/) 不同。 API 資源(如 Pod 和 [Service](https://kubernetes.io/docs/user-guide/services))是可通過 Kubernetes API server 讀取和修改的對象。
## Pod 和 容器的資源請求和限制
Pod 中的每個容器都可以指定以下的一個或者多個值:
- `spec.containers[].resources.limits.cpu`
- `spec.containers[].resources.limits.memory`
- `spec.containers[].resources.requests.cpu`
- `spec.containers[].resources.requests.memory`
盡管只能在個別容器上指定請求和限制,但是我們可以方便地計算出 Pod 資源請求和限制。特定資源類型的Pod 資源請求/限制是 Pod 中每個容器的該類型的資源請求/限制的總和。
## CPU 的含義
CPU 資源的限制和請求以 *cpu* 為單位。
Kubernetes 中的一個 cpu 等于:
- 1 AWS vCPU
- 1 GCP Core
- 1 Azure vCore
- 1 *Hyperthread* 在帶有超線程的裸機 Intel 處理器上
允許浮點數請求。具有 `spec.containers[].resources.requests.cpu` 為 0.5 的容器保證了一半 CPU 要求 1 CPU的一半。表達式 `0.1` 等價于表達式 `100m`,可以看作 “100 millicpu”。有些人說成是“一百毫 cpu”,其實說的是同樣的事情。具有小數點(如 `0.1`)的請求由 API 轉換為`100m`,精度不超過 `1m`。因此,可能會優先選擇 `100m` 的形式。
CPU 總是要用絕對數量,不可以使用相對數量;0.1 的 CPU 在單核、雙核、48核的機器中的意義是一樣的。
## 內存的含義
內存的限制和請求以字節為單位。您可以使用以下后綴之一作為平均整數或定點整數表示內存:E,P,T,G,M,K。您還可以使用兩個字母的等效的冪數:Ei,Pi,Ti ,Gi,Mi,Ki。例如,以下代表大致相同的值:
```bash
128974848, 129e6, 129M, 123Mi
```
下面是個例子。
以下 Pod 有兩個容器。每個容器的請求為 0.25 cpu 和 64MiB(2<sup>26</sup> 字節)內存,每個容器的限制為 0.5 cpu 和 128MiB 內存。您可以說該 Pod 請求 0.5 cpu 和 128 MiB 的內存,限制為 1 cpu 和 256MiB 的內存。
```yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
```
## 具有資源請求的 Pod 如何調度
當您創建一個 Pod 時,Kubernetes 調度程序將為 Pod 選擇一個節點。每個節點具有每種資源類型的最大容量:可為 Pod 提供的 CPU 和內存量。調度程序確保對于每種資源類型,調度的容器的資源請求的總和小于節點的容量。請注意,盡管節點上的實際內存或 CPU 資源使用量非常低,但如果容量檢查失敗,則調度程序仍然拒絕在該節點上放置 Pod。當資源使用量稍后增加時,例如在請求率的每日峰值期間,這可以防止節點上的資源短缺。
## 具有資源限制的 Pod 如何運行
當 kubelet 啟動一個 Pod 的容器時,它會將 CPU 和內存限制傳遞到容器運行時。
當使用 Docker 時:
- `spec.containers[].resources.requests.cpu` 的值將轉換成 millicore 值,這是個浮點數,并乘以1024,這個數字中的較大者或2用作 `docker run` 命令中的[ `--cpu-shares`](https://docs.docker.com/engine/reference/run/#/cpu-share-constraint) 標志的值。
- `spec.containers[].resources.limits.cpu` 被轉換成 millicore 值。被乘以 100000 然后 除以 1000。這個數字用作 `docker run` 命令中的 [`--cpu-quota`](https://docs.docker.com/engine/reference/run/#/cpu-quota-constraint) 標志的值。[`--cpu-quota` ] 標志被設置成了 100000,表示測量配額使用的默認100ms 周期。如果 [`--cpu-cfs-quota`] 標志設置為 true,則 kubelet 會強制執行 cpu 限制。從 Kubernetes 1.2 版本起,此標志默認為 true。
- `spec.containers[].resources.limits.memory` 被轉換為整型,作為 `docker run` 命令中的 [`--memory`](https://docs.docker.com/engine/reference/run/#/user-memory-constraints) 標志的值。
如果容器超過其內存限制,則可能會被終止。如果可重新啟動,則與所有其他類型的運行時故障一樣,kubelet 將重新啟動它。
如果一個容器超過其內存請求,那么當節點內存不足時,它的 Pod 可能被逐出。
容器可能被允許也可能不被允許超過其 CPU 限制時間。但是,由于 CPU 使用率過高,不會被殺死。
要確定容器是否由于資源限制而無法安排或被殺死,請參閱疑難解答]部分。
## 監控計算資源使用
Pod 的資源使用情況被報告為 Pod 狀態的一部分。
如果為集群配置了可選監控,則可以從監控系統檢索 Pod 資源的使用情況。
## 疑難解答
### 我的 Pod 處于 pending 狀態且事件信息顯示 failedScheduling
如果調度器找不到任何該 Pod 可以匹配的節點,則該 Pod 將保持不可調度狀態,直到找到一個可以被調度到的位置。每當調度器找不到 Pod 可以調度的地方時,會產生一個事件,如下所示:
```bash
$ kubectl describe pod frontend | grep -A 3 Events
Events:
FirstSeen LastSeen Count From Subobject PathReason Message
36s 5s 6 {scheduler } FailedScheduling Failed for reason PodExceedsFreeCPU and possibly others
```
在上述示例中,由于節點上的 CPU 資源不足,名為 “frontend” 的 Pod 將無法調度。由于內存不足(PodExceedsFreeMemory),類似的錯誤消息也可能會導致失敗。一般來說,如果有這種類型的消息而處于 pending 狀態,您可以嘗試如下幾件事情:
```bash
$ kubectl describe nodes e2e-test-minion-group-4lw4
Name: e2e-test-minion-group-4lw4
[ ... lines removed for clarity ...]
Capacity:
alpha.kubernetes.io/nvidia-gpu: 0
cpu: 2
memory: 7679792Ki
pods: 110
Allocatable:
alpha.kubernetes.io/nvidia-gpu: 0
cpu: 1800m
memory: 7474992Ki
pods: 110
[ ... lines removed for clarity ...]
Non-terminated Pods: (5 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
kube-system kube-dns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
680m (34%) 400m (20%) 920Mi (12%) 1070Mi (14%)
```
## 我的容器被終結了
您的容器可能因為資源枯竭而被終結了。要查看容器是否因為遇到資源限制而被殺死,請在相關的 Pod 上調用 `kubectl describe pod`:
```bash
[12:54:41] $ kubectl describe pod simmemleak-hra99
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
Labels: name=simmemleak
Status: Running
Reason:
Message:
IP: 10.244.2.75
Replication Controllers: simmemleak (1/1 replicas created)
Containers:
simmemleak:
Image: saadali/simmemleak
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2015 12:54:41 -0700
Last Termination State: Terminated
Exit Code: 1
Started: Fri, 07 Jul 2015 12:54:30 -0700
Finished: Fri, 07 Jul 2015 12:54:33 -0700
Ready: False
Restart Count: 5
Conditions:
Type Status
Ready False
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {scheduler } scheduled Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD pulled Pod container image "gcr.io/google_containers/pause:0.8.0" already present on machine
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD created Created with docker id 6a41280f516d
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} implicitly required container POD started Started with docker id 6a41280f516d
Tue, 07 Jul 2015 12:53:51 -0700 Tue, 07 Jul 2015 12:53:51 -0700 1 {kubelet kubernetes-node-tf0f} spec.containers{simmemleak} created Created with docker id 87348f12526a
```
在上面的例子中,`Restart Count: 5` 意味著 Pod 中的 `simmemleak` 容器被終止并重啟了五次。
您可以使用 `kubectl get pod` 命令加上 `-o go-template=...` 選項來獲取之前終止容器的狀態。
```bash
[13:59:01] $ kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}' simmemleak-60xbc
Container Name: simmemleak
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]
```
您可以看到容器因為 `reason:OOM killed` 被終止,`OOM` 表示 Out Of Memory。
## 不透明整型資源(Alpha功能)
Kubernetes 1.5 版本中引入不透明整型資源。不透明的整數資源允許集群運維人員發布新的節點級資源,否則系統將不了解這些資源。
用戶可以在 Pod 的 spec 中消費這些資源,就像 CPU 和內存一樣。調度器負責資源計量,以便在不超過可用量的同時分配給 Pod。
**注意:** 不透明整型資源在 kubernetes 1.5 中還是 Alpha 版本。只實現了資源計量,節點級別的隔離還處于積極的開發階段。
不透明整型資源是以 `pod.alpha.kubernetes.io/opaque-int-resource-` 為前綴的資源。API server 將限制這些資源的數量為整數。*有效* 數量的例子有 `3`、`3000m` 和 `3Ki`。*無效*數量的例子有 `0.5` 和 `1500m`。
申請使用不透明整型資源需要兩步。首先,集群運維人員必須在一個或多個節點上通告每個節點不透明的資源。然后,用戶必須在 Pod 中請求不透明資源。
要發布新的不透明整型資源,集群運維人員應向 API server 提交 `PATCH` HTTP請求,以指定集群中節點的`status.capacity` 的可用數量。在此操作之后,節點的 `status.capacity` 將包括一個新的資源。 `status.allocatable` 字段由 kubelet 異步地使用新資源自動更新。請注意,由于調度器在評估 Pod 適應度時使用節點 `status.allocatable` 值,所以在使用新資源修補節點容量和請求在該節點上調度資源的第一個 pod 之間可能會有短暫的延遲。
**示例**
這是一個 HTTP 請求,master 節點是 k8s-master,在 k8s-node-1 節點上通告 5 個 “foo” 資源。
```http
PATCH /api/v1/nodes/k8s-node-1/status HTTP/1.1
Accept: application/json
Content-Type: application/json-patch+json
Host: k8s-master:8080
[
{
"op": "add",
"path": "/status/capacity/pod.alpha.kubernetes.io~1opaque-int-resource-foo",
"value": "5"
}
]
```
```bash{% raw %}
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/pod.alpha.kubernetes.io~1opaque-int-resource-foo", "value": "5"}]' \
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
```
**注意:** 在前面的請求中,`~1` 是 patch 路徑中 `/` 字符的編碼。JSON-Patch 中的操作路徑值被解釋為 JSON-Pointer。更多詳細信息請參閱 [IETF RFC 6901, section 3](https://tools.ietf.org/html/rfc6901#section-3)。
```yaml
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: myimage
resources:
requests:
cpu: 2
pod.alpha.kubernetes.io/opaque-int-resource-foo: 1
```
## 計劃改進
在 kubernetes 1.5 版本中僅允許在容器上指定資源量。計劃改進對所有容器在 Pod 中共享資源的計量,如 [emptyDir volume](https://kubernetes.io/docs/concepts/storage/volumes/#emptydir)。
在 kubernetes 1.5 版本中僅支持容器對 CPU 和內存的申請和限制。計劃增加新的資源類型,包括節點磁盤空間資源和一個可支持自定義資源類型的框架。
Kubernetes 通過支持通過多級別的 [服務質量](http://issue.k8s.io/168) 來支持資源的過度使用。
在 kubernetes 1.5 版本中,一個 CPU 單位在不同的云提供商和同一云提供商的不同機器類型中的意味都不同。例如,在 AWS 上,節點的容量報告為 [ECU](http://aws.amazon.com/ec2/faqs/),而在 GCE 中報告為邏輯內核。我們計劃修改 cpu 資源的定義,以便在不同的提供商和平臺之間保持一致。
- 序言
- 云原生
- 云原生(Cloud Native)的定義
- CNCF - 云原生計算基金會簡介
- CNCF章程
- 云原生的設計哲學
- Play with Kubernetes
- 快速部署一個云原生本地實驗環境
- Kubernetes與云原生應用概覽
- 云原生應用之路——從Kubernetes到Cloud Native
- 云原生編程語言
- 云原生編程語言Ballerina
- 云原生編程語言Pulumi
- 云原生的未來
- Kubernetes架構
- 設計理念
- Etcd解析
- 開放接口
- CRI - Container Runtime Interface(容器運行時接口)
- CNI - Container Network Interface(容器網絡接口)
- CSI - Container Storage Interface(容器存儲接口)
- Kubernetes中的網絡
- Kubernetes中的網絡解析——以flannel為例
- Kubernetes中的網絡解析——以calico為例
- 具備API感知的網絡和安全性管理開源軟件Cilium
- Cilium架構設計與概念解析
- 資源對象與基本概念解析
- Pod狀態與生命周期管理
- Pod概覽
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中斷與PDB(Pod中斷預算)
- 集群資源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污點和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定義指標HPA
- 準入控制器(Admission Controller)
- 服務發現
- Service
- Ingress
- Traefik Ingress Controller
- 身份與權限控制
- ServiceAccount
- RBAC——基于角色的訪問控制
- NetworkPolicy
- 存儲
- Secret
- ConfigMap
- ConfigMap的熱更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存儲
- 集群擴展
- 使用自定義資源擴展API
- 使用CRD擴展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 資源調度
- QoS(服務質量等級)
- 用戶指南
- 資源對象配置
- 配置Pod的liveness和readiness探針
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的資源配額
- 命令使用
- Docker用戶過度到kubectl命令行指南
- kubectl命令概覽
- kubectl命令技巧大全
- 使用etcdctl訪問kubernetes數據
- 集群安全性管理
- 管理集群中的TLS
- kubelet的認證授權
- TLS bootstrap
- 創建用戶認證授權的kubeconfig文件
- IP偽裝代理
- 使用kubeconfig或token進行用戶身份認證
- Kubernetes中的用戶與身份認證授權
- Kubernetes集群安全性配置最佳實踐
- 訪問Kubernetes集群
- 訪問集群
- 使用kubeconfig文件配置跨集群認證
- 通過端口轉發訪問集群中的應用程序
- 使用service訪問群集中的應用程序
- 從外部訪問Kubernetes中的Pod
- Cabin - Kubernetes手機客戶端
- Kubernetic - Kubernetes桌面客戶端
- Kubernator - 更底層的Kubernetes UI
- 在Kubernetes中開發部署應用
- 適用于kubernetes的應用開發部署流程
- 遷移傳統應用到Kubernetes中——以Hadoop YARN為例
- 最佳實踐概覽
- 在CentOS上部署Kubernetes集群
- 創建TLS證書和秘鑰
- 創建kubeconfig文件
- 創建高可用etcd集群
- 安裝kubectl命令行工具
- 部署master節點
- 安裝flannel網絡插件
- 部署node節點
- 安裝kubedns插件
- 安裝dashboard插件
- 安裝heapster插件
- 安裝EFK插件
- 生產級的Kubernetes簡化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速構建測試集群
- 服務發現與負載均衡
- 安裝Traefik ingress
- 分布式負載測試
- 網絡和集群性能測試
- 邊緣節點配置
- 安裝Nginx ingress
- 安裝配置DNS
- 安裝配置Kube-dns
- 安裝配置CoreDNS
- 運維管理
- Master節點高可用
- 服務滾動升級
- 應用日志收集
- 配置最佳實踐
- 集群及應用監控
- 數據持久化問題
- 管理容器的計算資源
- 集群聯邦
- 存儲管理
- GlusterFS
- 使用GlusterFS做持久化存儲
- 使用Heketi作為Kubernetes的持久存儲GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存儲
- GlusterD-2.0
- Ceph
- 用Helm托管安裝Ceph集群并提供后端存儲
- 使用Ceph做持久化存儲
- 使用rbd-provisioner提供rbd持久化存儲
- OpenEBS
- 使用OpenEBS做持久化存儲
- Rook
- NFS
- 利用NFS動態提供Kubernetes后端存儲卷
- 集群與應用監控
- Heapster
- 使用Heapster獲取集群和對象的metric數據
- Prometheus
- 使用Prometheus監控kubernetes集群
- Prometheus查詢語言PromQL使用說明
- 使用Vistio監控Istio服務網格中的流量
- 分布式跟蹤
- OpenTracing
- 服務編排管理
- 使用Helm管理Kubernetes應用
- 構建私有Chart倉庫
- 持續集成與發布
- 使用Jenkins進行持續集成與發布
- 使用Drone進行持續集成與發布
- 更新與升級
- 手動升級Kubernetes集群
- 升級dashboard
- 領域應用概覽
- 微服務架構
- 微服務中的服務發現
- 使用Java構建微服務并發布到Kubernetes平臺
- Spring Boot快速開始指南
- Service Mesh 服務網格
- 企業級服務網格架構
- Service Mesh基礎
- Service Mesh技術對比
- 采納和演進
- 定制和集成
- 總結
- Istio
- 安裝并試用Istio service mesh
- 配置請求的路由規則
- 安裝和拓展Istio service mesh
- 集成虛擬機
- Istio中sidecar的注入規范及示例
- 如何參與Istio社區及注意事項
- Istio教程
- Istio免費學習資源匯總
- 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由轉發
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概覽
- 安裝Conduit
- Envoy
- Envoy的架構與基本術語
- Envoy作為前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 構建 SOFAMesh
- 大數據
- Spark standalone on Kubernetes
- 運行支持Kubernetes原生調度的Spark程序
- Serverless架構
- 理解Serverless
- FaaS-函數即服務
- OpenFaaS快速入門指南
- 邊緣計算
- 人工智能