成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Pod 原地垂直伸縮 - 一個(gè)四年的KEP和兩年的PR

開源
目前,更改資源分配是需要重新創(chuàng)建 Pod 的,因?yàn)?PodSpec 的容器資源是不可改變的。 雖然許多無狀態(tài)的工作負(fù)載被設(shè)計(jì)成可以承受這樣的中斷,但有些工作負(fù)載更加敏感,特別是在使用低數(shù)量的 Pod 副本時(shí)。


該提案旨在允許 Pod 資源 requests 和 limits 的原地更新,而不需要重新啟動(dòng) Pod 或其容器,該方案的核心思想是讓 PodSpec? 的 Resources 是可變的,表示所需的資源,此外 擴(kuò)展 PodStatus 來反映分配給 Pod 的資源,并提供有關(guān)應(yīng)用于 Pod 及其容器的實(shí)際資源信息。

此外該提案還提出了改進(jìn)容器運(yùn)行時(shí)接口(CRI)API,以便在運(yùn)行時(shí)管理容器的 CPU 和內(nèi)存資源配置,嘗試擴(kuò)展 UpdateContainerResources 這個(gè) CRI API,使其適用于 Windows 和除 Linux 之外的其他未來的運(yùn)行時(shí)。它還需求擴(kuò)展 ContainerStatus CRI API,以允許 Kubelet 能夠發(fā)現(xiàn)當(dāng)前配置在容器上的資源。

原因

由于各種原因,分配給 Pod 的容器資源可能需要變更比,這種場(chǎng)景有很多:

  • 如 Pod 處理的負(fù)載大幅增加,而目前的資源不足了
  • 又或者說負(fù)載大幅減少了,而分配的資源未被使用
  • 資源配置不合理

目前,更改資源分配是需要重新創(chuàng)建 Pod 的,因?yàn)?nbsp;PodSpec 的容器資源是不可改變的。 雖然許多無狀態(tài)的工作負(fù)載被設(shè)計(jì)成可以承受這樣的中斷,但有些工作負(fù)載更加敏感,特別是在使用低數(shù)量的 Pod 副本時(shí)。

此外,對(duì)于有狀態(tài)或批處理的工作負(fù)載,Pod 重啟是一個(gè)嚴(yán)重的破壞行為,會(huì)導(dǎo)致工作負(fù)載可用性降低或運(yùn)行成本提高。

允許在不重新創(chuàng)建 Pod 或重新啟動(dòng)容器的情況下改變資源,可以直接解決這個(gè)問題。此外,原地 Pod 垂直伸縮功能依賴于容器運(yùn)行時(shí)接口(CRI)來更新 Pod 容器的 CPU 和/或內(nèi)存的 requests/limits。

當(dāng)前的 CRI API 有一些需要解決的缺點(diǎn):

  • UpdateContainerResources CRI API 需要一個(gè)參數(shù)來描述要為 Linux 容器更新的容器資源,這在未來可能無法適用于 Windows 容器或其他潛在的非 Linux 運(yùn)行時(shí)。
  • 沒有 CRI 機(jī)制可以讓 Kubelet 從容器運(yùn)行時(shí)查詢和發(fā)現(xiàn)容器上配置的 CPU 和內(nèi)存限制。
  • 處理 UpdateContainerResources CRI API 的運(yùn)行時(shí)的預(yù)期行為沒有很好地定義或記錄。

目標(biāo)

  • 主要:允許更改容器的資源請(qǐng)求(requests)和限制(limits),而不必重新啟動(dòng)容器。
  • 次要:允許參與者(用戶、VPA、StatefulSet、JobController)決定在無法進(jìn)行原地資源調(diào)整的情況下如何進(jìn)行。
  • 次要:允許用戶指定哪些容器可以在不重啟的情況下調(diào)整資源大小。

此外,該提案對(duì) CRI API 還有兩個(gè)實(shí)現(xiàn)目標(biāo):

  • 修改 UpdateContainerResources 以使其適用于 Windows 容器,以及 Linux 以外的其他運(yùn)行時(shí)管理的容器。
  • 提供 CRI API 機(jī)制,以查詢?nèi)萜鬟\(yùn)行時(shí)當(dāng)前應(yīng)用于容器的 CPU 和內(nèi)存資源配置。

該提案的另一個(gè)目標(biāo)是更好地定義和記錄容器運(yùn)行時(shí)在處理資源更新時(shí)的預(yù)期行為。

提案

API 變化

PodSpec 在容器資源請(qǐng)求和限制方面是可變的,PodStatus 被擴(kuò)展以顯示分配給 Pod 和其容器的資源。

  • Pod.Spec.Containers[i].Resources 成為一個(gè)純粹的聲明,表示 Pod 資源的期望狀態(tài)。
  • Pod.Status.ContainerStatuses[i].ResourcesAllocated(新字段,類型 v1.ResourceList)表示分配給 Pod 及其容器的節(jié)點(diǎn)資源。
  • Pod.Status.ContainerStatuses[i].Resources(新字段,類型為 v1.ResourceRequirements)顯示 Pod 及其容器所持有的實(shí)際資源。
  • Pod.Status.Resize(新字段,類型為 map[string]string)解釋了指定容器上的指定資源正在發(fā)生什么事情。

新的 ResourcesAllocated 字段表示正在進(jìn)行中的大小調(diào)整操作,并由保存在節(jié)點(diǎn)檢查點(diǎn)的狀態(tài)驅(qū)動(dòng)。在考慮節(jié)點(diǎn)上的可用空間時(shí),調(diào)度器應(yīng)該使用 Spec.Containers[i].Resources 和 Status.ContainerStatuses[i].ResourcesAllocated 中較大的那個(gè)。

子資源

對(duì)于 alpha 版,資源的變化將通過更新 pod 規(guī)范(spec)來實(shí)現(xiàn)。對(duì)于 beta(或者可能是 alpha 的后續(xù)版本),將定義一個(gè)新的子資源 /resize,該子資源最終可以應(yīng)用于其他使用了 PodTemplates 的資源,例如 Deployments、ReplicaSets、Jobs 和 StatefulSets。這將允許用戶對(duì) VPA 等控制器授予 RBAC 訪問權(quán)限,而不允許對(duì) pod specs 進(jìn)行完全寫入訪問。這里的具體 API 待確定。

容器調(diào)整策略

為了提供細(xì)粒度的用戶控制,PodSpec.Containers? 擴(kuò)展了 ResizePolicy? - 一個(gè)支持 cpu? 和 memory 作為名稱的命名子對(duì)象(新對(duì)象)列表。它支持以下策略值:

  • RestartNotRequired - 默認(rèn)值;如果可能,嘗試在不重啟容器的情況下調(diào)整它的大小。
  • Restart? - 容器需要重新啟動(dòng)才能應(yīng)用新的資源值(例如,Java 進(jìn)程需要更改其 Xmx 標(biāo)志),通過使用 ResizePolicy,用戶可以將容器標(biāo)記為安全(或不安全)的原地資源更新。 Kubelet 使用它來確定所需的操作。

注意:RestartNotRequired 并不能保證容器不會(huì)重新啟動(dòng),如果不這樣做就無法應(yīng)用新的資源,那么運(yùn)行時(shí)可能會(huì)選擇停止該容器。

設(shè)置標(biāo)志來單獨(dú)控制 CPU 和內(nèi)存是由于觀察到通常 CPU 可以被添加/刪除而沒有什么問題,而對(duì)可用內(nèi)存的更改更有可能需要重新啟動(dòng)。

如果同時(shí)更新具有不同策略的多種資源類型,則任何重新啟動(dòng)策略都優(yōu)先于 RestartNotRequired? 策略。如果 pod 的 RestartPolicy? 為 Never,則必須將 ResizePolicy? 字段設(shè)置為 RestartNotRequired 才能通過驗(yàn)證。也就是說,如果系統(tǒng)無法原地執(zhí)行調(diào)整大小,則任何原地調(diào)整大小都可能導(dǎo)致容器停止而不重新啟動(dòng)。

調(diào)整狀態(tài)

除了上述內(nèi)容之外,還將添加一個(gè)新字段 Pod.Status.Resize[],該字段表面 kubelet 是否接受或拒絕了針對(duì)指定資源的建議調(diào)整操作。每當(dāng) Pod.Spec.Containers[i].Resources.Requests 字段與 Pod.Status.ContainerStatuses[i].Resources 字段不同時(shí),這個(gè)新字段就會(huì)解釋原因。

該字段可以設(shè)置為以下值之一:

  • Proposed - 提議的調(diào)整大小(在 Spec...Resources 中)尚未被接受或拒絕。
  • InProgress - 建議的調(diào)整大小已被接受并正在執(zhí)行中。
  • Deferred - 提議的調(diào)整大小在理論上是可行的(它適合在這個(gè)節(jié)點(diǎn)上)但現(xiàn)在不能;它將被重新評(píng)估。
  • Infeasible - 提議的調(diào)整大小不可行并被拒絕;它不會(huì)被重新評(píng)估。
  • 沒有值 - 沒有建議的大小調(diào)整

任何時(shí)候 apiserver watch 到建議的調(diào)整大小(對(duì) Spec...Resources 字段的修改),它都會(huì)自動(dòng)將此字段設(shè)置為 Proposed。為了使該字段未來是安全的,消費(fèi)者應(yīng)該假設(shè)任何未知值都與 Deferred 相同。

CRI 變更

Kubelet 調(diào)用 UpdateContainerResources CRI API,該 API 目前使用 runtimeapi.LinuxContainerResources 參數(shù),適用于 Docker 和 Kata,但不適用于 Windows。將這個(gè)參數(shù)改為 runtimeapi.ContainerResources,它與運(yùn)行時(shí)無關(guān),并將包含特定平臺(tái)的信息。這將使 UpdateContainerResources API 適用于 Windows,以及未來除 Linux 之外的任何其他運(yùn)行時(shí),方法是使 API 中傳遞的資源參數(shù)特定于目標(biāo)運(yùn)行時(shí)。

此外,ContainerStatus CRI API 被擴(kuò)展為持有 runtimeapi.ContainerResources 數(shù)據(jù),這樣它就允許 Kubelet 從運(yùn)行時(shí)查詢 Container 的 CPU 和內(nèi)存限制配置。這就要求運(yùn)行時(shí)響應(yīng)當(dāng)前應(yīng)用于容器的 CPU 和內(nèi)存資源值。

這些 CRI 的變化是一項(xiàng)單獨(dú)的工作,并不影響本 KEP 中提出的設(shè)計(jì)。

要完成上述 CRI 更改:

  • 下面介紹一個(gè)新的名為 ContainerResources 的 protobuf 消息對(duì)象,它封裝了 LinuxContainerResources 和 WindowsContainerResources。
  • 通過簡單地向 message ContainerResources 添加新的特定于運(yùn)行時(shí)的資源結(jié)構(gòu),可以輕松地為未來的運(yùn)行時(shí)擴(kuò)展此消息。
// ContainerResource 保存容器的資源配置
message ContainerResources {
// 特定于Linux容器的資源配置
LinuxContainerResources linux = 1;
// 特定于Windows容器的資源配置
WindowsContainerResources windows = 2;
}
  • message UpdateContainerResourcesRequest 被擴(kuò)展為攜帶 ContainerResources 字段,如下所示。
  • 這通過讓依賴當(dāng)前 LinuxContainerResources 的運(yùn)行時(shí)繼續(xù)工作,同時(shí)使更新的運(yùn)行時(shí)版本能夠使用 UpdateContainerResourcesRequest.Resources.Linux 來保持向后兼容性,
  • 它開啟了 UpdateContainerResourcesRequest.Linux 字段的 deprecation。
  • 對(duì)于 Linux 運(yùn)行時(shí),Kubelet 除了 UpdateContainerResourcesRequest.Resources.Linux 字段外填充 UpdateContainerResourcesRequest.Linux 字段。
message UpdateContainerResourcesRequest {
// ID of the container to update.
string container_id = 1;
// Resource configuration specific to Linux container.
LinuxContainerResources linux = 2;
// Resource configuration for the container.
ContainerResources resources = 3;
}
  • message ContainerStatus 被擴(kuò)展為返回 ContainerResources,如下所示。
  • 這使 Kubelet 能夠使用 ContainerStatus CRI API 查詢運(yùn)行時(shí)并發(fā)現(xiàn)當(dāng)前應(yīng)用于容器的資源。
@@ -914,6 +912,8 @@ message ContainerStatus {
repeated Mount mounts = 14;
// Log path of container.
string log_path = 15;
+ // Resource configuration of the container.
+ ContainerResources resources = 16;
}
  • ContainerManager CRI API 服務(wù)接口修改如下。
  • UpdateContainerResources 采用 ContainerResources 參數(shù)而不是 LinuxContainerResources。
--- a/staging/src/k8s.io/cri-api/pkg/apis/services.go
+++ b/staging/src/k8s.io/cri-api/pkg/apis/services.go
@@ -43,8 +43,10 @@ type ContainerManager interface {
ListContainers(filter *runtimeapi.ContainerFilter) ([]*runtimeapi.Container, error)
// ContainerStatus returns the status of the container.
ContainerStatus(containerID string) (*runtimeapi.ContainerStatus, error)
- // UpdateContainerResources updates the cgroup resources for the container.
- UpdateContainerResources(containerID string, resources *runtimeapi.LinuxContainerResources) error
+ // UpdateContainerResources updates resource configuration for the container.
+ UpdateContainerResources(containerID string, resources *runtimeapi.ContainerResources) error
// ExecSync executes a command in the container, and returns the stdout output.
// If command exits with a non-zero exit code, an error is returned.
ExecSync(containerID string, cmd []string, timeout time.Duration) (stdout []byte, stderr []byte, err error)
  • 修改 Kubelet 代碼適配上面的 CRI 變更。

風(fēng)險(xiǎn)

  1. 向后兼容:當(dāng) Pod.Spec.Containers[i].Resources 成為期望狀態(tài)的代表時(shí),Pod 的真實(shí)資源分配在 Pod.Status.ContainerStatuses[i].ResourcesAllocated 中被跟蹤,查詢 PodSpec 并依賴 PodSpec 中的 Resources 來確定資源分配的應(yīng)用程序?qū)⒖吹娇赡懿淮韺?shí)際分配的值。這一變化需要在發(fā)行說明和頂級(jí) Kubernetes 文檔中加以記錄和強(qiáng)調(diào)。
  2. 降低內(nèi)存大小:降低 cgroup 的內(nèi)存限制可能不起作用,因?yàn)?pages 可能正在使用中,可能需要采取一些措施,如在當(dāng)前使用量附近設(shè)置限制。這個(gè)問題需要進(jìn)一步調(diào)查。
  3. 舊的客戶端版本:以前版本的客戶端不知道新的 ResourcesAllocated 和 ResizePolicy 字段,會(huì)把它們?cè)O(shè)置為 nil。為了保持兼容性,PodResourceAllocation 準(zhǔn)入控制器通過將非零值舊 Pod 復(fù)制到當(dāng)前 Pod 來改變這種更新。

設(shè)計(jì)細(xì)節(jié)

Kubelet 與 APIServer 的交互

當(dāng)一個(gè)新的 Pod 被創(chuàng)建時(shí),Scheduler 負(fù)責(zé)選擇一個(gè)合適的 Node 來容納這個(gè) Pod。

對(duì)于新創(chuàng)建的 Pod,apiserver 將設(shè)置 ResourcesAllocated 字段以匹配每個(gè)容器的 Resources.Requests。當(dāng) Kubelet 接納 Pod 時(shí),ResourcesAllocated 中的值用于確定是否有足夠的空間接納 Pod。 Kubelet 在接納 Pod 時(shí)不會(huì)設(shè)置 ResourcesAllocated。

當(dāng)請(qǐng)求調(diào)整 Pod 大小時(shí),Kubelet 會(huì)嘗試更新分配給 Pod 及其容器的資源。 Kubelet 首先通過計(jì)算節(jié)點(diǎn)中所有 Pod 分配的資源總和 (Pod.Spec.Containers[i].ResourcesAllocated) 來檢查新的所需資源是否適合節(jié)點(diǎn)可分配資源,除了被調(diào)整大小的 Pod。對(duì)于正在調(diào)整大小的 Pod,它將新的所需資源(即 Spec.Containers[i].Resources.Requests)添加到總和中。

  • 如果新的所需資源適合,Kubelet 通過更新 Status...ResourcesAllocated 字段并將 Status.Resize 設(shè)置為 InProgress 來接受大小調(diào)整。然后調(diào)用 UpdateContainerResources CRI API 來更新容器資源限制。成功更新所有容器后,它會(huì)更新 Status...Resources 以反映新的資源值并取消設(shè)置 Status.Resize。
  • 如果新的所需資源不適合,Kubelet 會(huì)將 Status.Resize 字段更新為 Infeasible 并且不會(huì)對(duì)大小調(diào)整進(jìn)行操作。
  • 如果新的所需資源適合但目前正在使用中,Kubelet 會(huì)將 Status.Resize 字段更新為 Deferred。

除了上述內(nèi)容之外,每當(dāng)調(diào)整大小被接受或拒絕時(shí),kubelet 將在 Pod 上生成事件,如果可能的話,記錄在調(diào)整大小過程中的關(guān)鍵步驟,這將使人們知道正在取得進(jìn)展。

如果有多個(gè) Pod 需要調(diào)整大小,它們將按照 Kubelet 定義的順序依次處理(例如按照出現(xiàn)的順序)。

調(diào)度器可能會(huì)并行地將一個(gè)新的 Pod 分配給節(jié)點(diǎn),因?yàn)樗褂镁彺娴?Pod 來計(jì)算節(jié)點(diǎn)的可分配值。如果發(fā)生這種競(jìng)爭情況,如果節(jié)點(diǎn)在 Pod 調(diào)整大小后沒有空間,Kubelet 會(huì)通過拒絕新 Pod 來解決它。

注意:在 Pod 被拒絕后,調(diào)度器可以嘗試在剛拒絕它的同一節(jié)點(diǎn)上重新調(diào)度替換 Pod。

Kubelet 重啟容錯(cuò)

如果 Kubelet 在處理 Pod 大小調(diào)整的過程中重新啟動(dòng),那么在重新啟動(dòng)時(shí),所有 Pod 都會(huì)以其當(dāng)前 Status...ResourcesAllocated 值被接納,并且在添加所有現(xiàn)有 Pod 后處理大小調(diào)整。這可確保調(diào)整大小不會(huì)影響之前已接納的現(xiàn)有 Pod。

調(diào)度器和 APIServer 交互

Scheduler 繼續(xù)使用 Pod 的 Spec.Containers[i].Resources.Requests 來調(diào)度新的 Pod,并繼續(xù) watch Pod 更新,并更新其緩存。為了計(jì)算分配給 Pod 的節(jié)點(diǎn)資源,它必須考慮 Status.Resize 所描述的未決的調(diào)整。。

對(duì)于 Status.Resize = "InProgress" 或 "Infeasible" 的容器,它可以簡單地使用  Status.ContainerStatus[i].ResourcesAllocated。

對(duì)于 Status.Resize = "Proposed" 的容器,它必須是悲觀的,并假設(shè)調(diào)整大小將立即被接受。因此它必須使用 Pod 的 Spec...Resources.Requests 和 Status...ResourcesAllocated 值中較大的一個(gè)。

流程控制

以下步驟表示了一個(gè) Pod 的一系列原地調(diào)整大小操作的流程,該 Pod 的所有容器的 ResizePolicy 設(shè)置為 RestartNotRequired,這樣可以針對(duì)各種邊緣情況進(jìn)行演示。

T=0: 一個(gè)新的 Pod 被創(chuàng)建
- `spec.containers[0].resources.requests[cpu]` = 1
- 所有狀態(tài)都未設(shè)置

T=1: 應(yīng)用 apiserver 默認(rèn)值
- `spec.containers[0].resources.requests[cpu]` = 1
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1
- `status.resize[cpu]` = unset

T=2: kubelet 運(yùn)行 pod 并更新 API
- `spec.containers[0].resources.requests[cpu]` = 1
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1
- `status.resize[cpu]` = unset
- `status.containerStatuses[0].resources.requests[cpu]` = 1

T=3: Resize #1: cpu = 1.5 (通過 PUT 或者 PATCH 或者 /resize 調(diào)整)
- apiserver 驗(yàn)證請(qǐng)求(例如 limits 不低于 requests,不超過 ResourceQuota 等)并接受操作
- apiserver 設(shè)置 `resize[cpu]` "Proposed"
- `spec.containers[0].resources.requests[cpu]` = 1.5
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1
- `status.resize[cpu]` = "Proposed"
- `status.containerStatuses[0].resources.requests[cpu]` = 1

T=4: Kubelet watching pod 發(fā)現(xiàn)大小調(diào)整 #1 并接受它
- kubelet 發(fā)送 patch 操作 {
`resourceVersion` = `<previous value>` # 啟用沖突檢測(cè)
`status.containerStatuses[0].resourcesAllocated[cpu]` = 1.5
`status.resize[cpu]` = "InProgress"
}
- `spec.containers[0].resources.requests[cpu]` = 1.5
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.5
- `status.resize[cpu]` = "InProgress"
- `status.containerStatuses[0].resources.requests[cpu]` = 1

T=5: Resize #2: cpu = 2 # 此時(shí)又來進(jìn)行 Resize 操作
- apiserver 驗(yàn)證請(qǐng)求并接受操作
- apiserver 設(shè)置 `resize[cpu]` "Proposed"
- `spec.containers[0].resources.requests[cpu]` = 2
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.5
- `status.resize[cpu]` = "Proposed"
- `status.containerStatuses[0].resources.requests[cpu]` = 1

T=6: 容器運(yùn)行時(shí)應(yīng)用 cpu=1.5
- kubelet 發(fā)送 patch 操作 {
`resourceVersion` = `<previous value>` # 啟用沖突檢測(cè)
`status.containerStatuses[0].resources.requests[cpu]` = 1.5
`status.resize[cpu]` = unset
}
- apiserver操作失敗,出現(xiàn)“沖突”錯(cuò)誤

T=7: kubelet刷新并查看到大小調(diào)整 #2 (cpu = 2)
- kubelet 認(rèn)為這是可行的,但現(xiàn)在不行
- kubelet sends patch {
`resourceVersion` = `<updated value>` # enable conflict detection
`status.containerStatuses[0].resources.requests[cpu]` = 1.5
`status.resize[cpu]` = "Deferred" # 標(biāo)記為延遲
}
- `spec.containers[0].resources.requests[cpu]` = 2
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.5
- `status.resize[cpu]` = "Deferred"
- `status.containerStatuses[0].resources.requests[cpu]` = 1.5

T=8: Resize #3: cpu = 1.6
- apiserver 驗(yàn)證請(qǐng)求并接受請(qǐng)求
- apiserver 設(shè)置 `resize[cpu]` "Proposed"
- `spec.containers[0].resources.requests[cpu]` = 1.6
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.5
- `status.resize[cpu]` = "Proposed"
- `status.containerStatuses[0].resources.requests[cpu]` = 1.5

T=9: Kubelet 觀測(cè)到 pod 第三次 resize 操作 #3 并接受它
- kubelet sends patch {
`resourceVersion` = `<previous value>` # enable conflict detection
`status.containerStatuses[0].resourcesAllocated[cpu]` = 1.6
`status.resize[cpu]` = "InProgress" # 標(biāo)記為調(diào)整中
}
- `spec.containers[0].resources.requests[cpu]` = 1.6
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.6
- `status.resize[cpu]` = "InProgress"
- `status.containerStatuses[0].resources.requests[cpu]` = 1.5

T=10: 容器運(yùn)行時(shí)應(yīng)用 cpu=1.6
- kubelet sends patch {
`resourceVersion` = `<previous value>` # enable conflict detection
`status.containerStatuses[0].resources.requests[cpu]` = 1.6
`status.resize[cpu]` = unset
}
- `spec.containers[0].resources.requests[cpu]` = 1.6
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.6
- `status.resize[cpu]` = unset
- `status.containerStatuses[0].resources.requests[cpu]` = 1.6

T=11: Resize #4: cpu = 100
- apiserver 驗(yàn)證請(qǐng)求和接受操作
- apiserver 設(shè)置 `resize[cpu]` "Proposed"
- `spec.containers[0].resources.requests[cpu]` = 100
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.6
- `status.resize[cpu]` = "Proposed"
- `status.containerStatuses[0].resources.requests[cpu]` = 1.6

T=12: Kubelet 觀測(cè)到pod第四次調(diào)整 resize #4
- 這個(gè)節(jié)點(diǎn)沒有 100 CPUs, 所以 kubelet 不接受
- kubelet sends patch {
`resourceVersion` = `<previous value>` # enable conflict detection
`status.resize[cpu]` = "Infeasible" # 標(biāo)記為拒絕
}
- `spec.containers[0].resources.requests[cpu]` = 100
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1.6
- `status.resize[cpu]` = "Infeasible"
- `status.containerStatuses[0].resources.requests[cpu]` = 1.6

容器資源限制更新順序

當(dāng)一個(gè) Pod 中的多個(gè)容器請(qǐng)求原地調(diào)整大小時(shí),Kubelet 通過以下方式更新 Pod 及其容器的資源限制:

  1. 如果資源調(diào)整導(dǎo)致資源類型(CPU 或內(nèi)存)凈增加,Kubelet 首先更新該資源類型的 Pod 級(jí) cgroup 限制,然后更新 Container 資源限制。
  2. 如果資源調(diào)整導(dǎo)致資源類型凈減少,Kubelet 首先更新 Container 資源限制,然后更新 Pod 級(jí)別的 cgroup 限制。
  3. 如果資源更新導(dǎo)致資源類型沒有凈變化,則僅更新容器資源限制。

在上述所有情況下,Kubelet 在應(yīng)用限制增加之前應(yīng)用容器資源限制減少。

容器資源限制更新失敗處理

如果 Pod 中的多個(gè)容器正在被更新,并且任何容器的 UpdateContainerResources CRI API 都失敗,Kubelet 將回退并在稍后進(jìn)行重試。 Kubelet 不會(huì)嘗試更新在失敗容器之后排隊(duì)等待更新的容器的限制。這確保容器限制的總和在任何時(shí)候都不會(huì)超過 Pod 級(jí)別的 cgroup 限制。成功更新所有容器限制后,Kubelet 會(huì)更新 Pod 的 Status.ContainerStatuses[i].Resources 以匹配所需的限制值。

CRI 變化流程

下圖是 Kubelet 使用 UpdateContainerResources 和 ContainerStatus CRI APIs 來設(shè)置新的容器資源限制,并在用戶改變 Pod Spec 中的所需資源時(shí)更新 Pod 狀態(tài)的概述。

+-----------+                   +-----------+                  +-----------+
| | | | | |
| apiserver | | kubelet | | runtime |
| | | | | |
+-----+-----+ +-----+-----+ +-----+-----+
| | |
| watch (pod update) | |
|------------------------------>| |
| [Containers.Resources] | |
| | |
| (admit) |
| | |
| | UpdateContainerResources() |
| |----------------------------->|
| | (set limits)
| |<- - - - - - - - - - - - - - -|
| | |
| | ContainerStatus() |
| |----------------------------->|
| | |
| | [ContainerResources] |
| |<- - - - - - - - - - - - - - -|
| | |
| update (pod status) | |
|<------------------------------| |
| [ContainerStatuses.Resources] | |
| | |
  • Kubelet 調(diào)用 ContainerManager 接口中的 UpdateContainerResources() CRI API,通過在 API 的 ContainerResources 參數(shù)中指定這些值來為容器配置新的 CPU 和內(nèi)存限制。Kubelet 在調(diào)用此 CRI API 時(shí),Kubelet 會(huì)根據(jù)目標(biāo)運(yùn)行時(shí)平臺(tái)來設(shè)置 ContainerResources 參數(shù)。
  • Kubelet 在 ContainerManager 接口中調(diào)用 ContainerStatus() CRI API 以獲取應(yīng)用于 Container 的 CPU 和內(nèi)存限制。它使用 ContainerStatus.Resources 中返回的值來更新 Pod 狀態(tài)中該容器的 ContainerStatuses[i].Resources.Limits。

注意事項(xiàng)

  • 如果一個(gè)節(jié)點(diǎn)的 CPU Manager 策略被設(shè)置為 "static",則僅允許 CPU 調(diào)整大小的整數(shù)值。如果在 CPU Manager 策略為 "static" 的節(jié)點(diǎn)上請(qǐng)求非整數(shù)的 CPU 調(diào)整,該調(diào)整將被拒絕,并在 Events 中記錄一個(gè)錯(cuò)誤信息。
  • 為了避免競(jìng)爭狀況,在計(jì)算 Pod 使用的資源時(shí),所有組件將使用 Pod 的 Status.ContainerStatuses[i].ResourcesAllocated。
  • 如果在 Pod 被調(diào)整大小時(shí)有額外的調(diào)整請(qǐng)求到達(dá),這些請(qǐng)求將在正在進(jìn)行的調(diào)整完成后處理。而調(diào)整大小是朝著最新的期望狀態(tài)驅(qū)動(dòng)的。
  • 如果應(yīng)用程序一直占用頁面,降低內(nèi)存限制可能并不總是會(huì)很快就生效。Kubelet 將使用一個(gè)控制循環(huán)來設(shè)置接近使用的內(nèi)存限制,以便強(qiáng)制回收,并且只有在限制達(dá)到預(yù)期值時(shí)才更新 Pod 的 Status.ContainerStatuses[i].Resources。
  • Pod Overhead 的影響,Kubelet 將 Pod Overhead 添加到調(diào)整大小的請(qǐng)求中,以確定是否可以在原地調(diào)整大小。

實(shí)現(xiàn)

其實(shí)該 KEP 草案第一次創(chuàng)建是在 2018 年了,到現(xiàn)在接近 5 年了。

圖片

該 KEP 對(duì)應(yīng)的 PR # In-place Pod Vertical Scaling feature #102884(https://github.com/kubernetes/kubernetes/pull/102884) 第一次也是2021年,到現(xiàn)在也兩年左右時(shí)間了,這不得不佩服 Kubernetes 社區(qū)的嚴(yán)謹(jǐn),畢竟該 PR 改動(dòng)較大,不過幸運(yùn)的時(shí)該 PR 已于昨天合并了,真是不容易,總共涉及160多個(gè)文件變更,雖然很大一部分是用于測(cè)試的代碼。

圖片

下面我們來看下要怎么使用這個(gè)新的特性。

現(xiàn)在有一個(gè)如下所示的測(cè)試 Pod:

# 2pod.yaml 
apiVersion: v1
kind: Pod
metadata:
name: 2pod
spec:
containers:
- name: stress
image: skiibum/ubuntu-stress:18.10
resources:
limits:
cpu: "500m"
memory: "500Mi"
requests:
cpu: "500m"
memory: "500Mi"

直接創(chuàng)建該 Pod 即可:

$ kubectl apply -f 2pod.yaml

創(chuàng)建后我們查看下該資源清單的詳細(xì)數(shù)據(jù):

$ kubectl get po 2pod -oyaml 
apiVersion: v1
kind: Pod
metadata:
name: 2pod
namespace: default
spec:
containers:
- image: skiibum/ubuntu-stress:18.10
name: stress
resizePolicy:
- policy: RestartNotRequired # 默認(rèn)值:如果可能,嘗試在不重啟容器的情況下調(diào)整它的大小。
resourceName: cpu
- policy: RestartNotRequired
resourceName: memory
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
...
...
status:
conditions:
...
containerStatuses:
- containerID: docker://015b2d8605c732329129a8d61894ef5438b5a8ed09da0b5e56dad82d3b57a789
image: skiibum/ubuntu-stress:18.10
name: stress
ready: true
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
resourcesAllocated:
cpu: 500m
memory: 500Mi
restartCount: 0
started: true
...
qosClass: Guaranteed
startTime: "2021-06-27T02:06:56Z"

可以看到最大的一個(gè)變化就是現(xiàn)在的 Pod 資源清單中新增了一個(gè) resizePolicy 屬性,下面自動(dòng)配置的 cpu 和 memory 兩種資源的 resize 策略為 RestartNotRequired,這也是默認(rèn)值,表示如果可能,嘗試在不重啟容器的情況下調(diào)整它的大小。

另外在 Status 下面出現(xiàn)了一個(gè)新的自動(dòng) ResourcesAllocated,表示分配給 Pod 及其容器的節(jié)點(diǎn)資源。

現(xiàn)在修改該 Pod 的容器資源大小:

$ kubectl patch pod 2pod --patch '{"spec":{"containers":[{"name":"stress", "resources":{"requests":{"cpu":"650m"}, "limits":{"cpu":"650m"}}}]}}'
pod/2pod patched

修改后再次查看詳細(xì)的 Pod 資源清單:

$ kubectl get po 2pod -oyaml 
apiVersion: v1
kind: Pod
metadata:
name: 2pod
namespace: default
spec:
containers:
- image: skiibum/ubuntu-stress:18.10
name: stress
resizePolicy:
- policy: RestartNotRequired
resourceName: cpu
- policy: RestartNotRequired
resourceName: memory
resources:
limits:
cpu: 650m
memory: 500Mi
requests:
cpu: 650m
memory: 500Mi
...
...
status:
conditions:
...
containerStatuses:
- containerID: docker://015b2d8605c732329129a8d61894ef5438b5a8ed09da0b5e56dad82d3b57a789
image: skiibum/ubuntu-stress:18.10
name: stress
ready: true
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
resourcesAllocated:
cpu: 650m
memory: 500Mi
restartCount: 0
started: true
...
qosClass: Guaranteed
resize: InProgress
startTime: "2021-06-27T02:06:56Z"

我們可以看到原本 PodSpec 下面的 resources 資源大小已經(jīng)變化了,重點(diǎn)還是在 Status 中,可以發(fā)現(xiàn)多了一個(gè) ??resize: InProgress?? 的字段,表示接受調(diào)整并正在執(zhí)行資源大小調(diào)整。

如果現(xiàn)在再次調(diào)整資源大小:

$ kubectl patch pod 2pod --patch '{"spec":{"containers":[{"name":"stress", "resources":{"requests":{"cpu":"3950m"}, "limits":{"cpu":"3950m"}}}]}}'
pod/2pod patched

調(diào)整后查看 Pod 詳細(xì)數(shù)據(jù):

$ kubectl get po 2pod -oyaml 
apiVersion: v1
kind: Pod
metadata:
name: 2pod
namespace: default
spec:
containers:
- image: skiibum/ubuntu-stress:18.10
name: stress
resizePolicy:
- policy: RestartNotRequired
resourceName: cpu
- policy: RestartNotRequired
resourceName: memory
resources:
limits:
cpu: 3950m
memory: 500Mi
requests:
cpu: 3950m
memory: 500Mi
...
...
status:
conditions:
...
containerStatuses:
- containerID: docker://015b2d8605c732329129a8d61894ef5438b5a8ed09da0b5e56dad82d3b57a789
image: skiibum/ubuntu-stress:18.10
name: stress
ready: true
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
resourcesAllocated:
cpu: 650m
memory: 500Mi
restartCount: 0
started: true
...
qosClass: Guaranteed
resize: Deferred
startTime: "2021-06-27T02:06:56Z"

此時(shí) Status 中的 resize 變成了 Deferred 狀態(tài),表示提議的調(diào)整大小在理論上是可行的(它適合在這個(gè)節(jié)點(diǎn)上)但現(xiàn)在還不能,它將被重新評(píng)估,注意 resourcesAllocated 還是上一次變更成功后的大小。

如果再次調(diào)整資源到節(jié)點(diǎn)不能滿足的情況下:

$ kubectl patch pod 2pod --patch '{"spec":{"containers":[{"name":"stress", "resources":{"requests":{"cpu":"4650m"}, "limits":{"cpu":"4650m"}}}]}}'
pod/2pod patched
$ kubectl get po 2pod -oyaml
apiVersion: v1
kind: Pod
metadata:
name: 2pod
namespace: default
spec:
containers:
- image: skiibum/ubuntu-stress:18.10
name: stress
resizePolicy:
- policy: RestartNotRequired
resourceName: cpu
- policy: RestartNotRequired
resourceName: memory
resources:
limits:
cpu: 4650m
memory: 500Mi
requests:
cpu: 4650m
memory: 500Mi
...
...
status:
conditions:
...
containerStatuses:
- containerID: docker://015b2d8605c732329129a8d61894ef5438b5a8ed09da0b5e56dad82d3b57a789
image: skiibum/ubuntu-stress:18.10
...
name: stress
ready: true
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 500m
memory: 500Mi
resourcesAllocated:
cpu: 650m
memory: 500Mi
restartCount: 0
...
qosClass: Guaranteed
resize: Infeasible
startTime: "2021-06-27T02:06:56Z"

現(xiàn)在 resize 狀態(tài)變成了 Infeasible,表示不能滿足資源條件,拒絕調(diào)整。

以后當(dāng)我們的 Pod 資源不足的時(shí)候,可以放心大膽去調(diào)整資源了,不用擔(dān)心容器被重啟了。

參考鏈接

  • https://github.com/kubernetes/kubernetes/pull/102884。
  • https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/1287-in-place-update-pod-resources。
責(zé)任編輯:姜華 來源: k8s技術(shù)圈
相關(guān)推薦

2021-08-30 11:48:33

開發(fā)技術(shù)互聯(lián)網(wǎng)

2015-08-25 10:00:26

IT 青年北漂感悟

2013-08-23 10:39:42

創(chuàng)業(yè)創(chuàng)業(yè)者

2018-04-27 09:52:38

2015-04-08 10:57:15

程序員程序員四年經(jīng)歷

2009-06-11 10:05:52

IT人職場(chǎng)程序員

2014-05-20 10:31:31

2012-07-26 09:29:34

2015-07-27 09:31:34

程序員

2009-03-20 09:17:17

2015-07-06 10:52:56

DockerDocker本質(zhì)鏈接器

2020-12-07 10:52:44

開源安全漏洞惡意攻擊

2013-01-08 10:35:05

程序員程序員的成長

2024-12-25 11:26:28

2018-07-25 15:57:21

人工智能AI試驗(yàn)AlphaGo

2022-01-26 10:41:04

面試字節(jié)阿里

2020-11-11 14:09:42

UI設(shè)計(jì)師進(jìn)階學(xué)習(xí)

2016-01-04 10:07:21

2015-01-04 09:58:06

Android 2.3

2014-05-04 10:38:40

手游創(chuàng)業(yè)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 成人av大全 | 亚洲成人一区二区 | 亚洲精品 在线播放 | 综合色久 | 九九综合 | 午夜影晥| 国产精品久久久亚洲 | 成人亚洲精品久久久久软件 | 国产精品一区二区欧美 | 成人在线播放 | 国产日韩一区二区三免费高清 | 精品久久久久久久久亚洲 | 国产一区在线免费观看 | 国产中文一区二区三区 | 91视频在线看| 插插宗合网 | 亚洲精品久久久久久久久久久久久 | 在线观看视频你懂得 | 中文精品视频 | 亚洲精品国产a久久久久久 中文字幕一区二区三区四区五区 | 日韩欧美一区二区在线播放 | 尤物在线精品视频 | 日韩精品一区二区三区高清免费 | 日韩免费成人av | 亚洲国产精品久久久久 | 亚洲狠狠 | www.久草.com | 国产成人av一区二区三区 | 盗摄精品av一区二区三区 | 亚洲精品在线播放 | 精品国产18久久久久久二百 | 91精品久久久久久久久久入口 | 国产探花在线观看视频 | 99精品久久久 | 日韩精品在线观看免费 | 日韩久久久久久 | 成人在线网 | 国产欧美日韩一区 | 操操操日日日 | 国产精品久久久久久久久久尿 | 91精品一区二区三区久久久久久 |