该提案旨在允许 Pod 资源 requests 和 limits 的原地更新,而不需要重新启动 Pod 或其容器,该方案的核心思想是让 PodSpec 的 Resources 是可变的,表示所需的资源,此外 扩展 PodStatus 来反映分配给 Pod 的资源,并提供有关应用于 Pod 及其容器的实际资源信息。此外该提案还提出了改进容器运行时接口(CRI)API,以便在运行时管理容器的 CPU 和内存资源配置,尝试扩展 UpdateContainerResources 这个 CRI API,使其适用于 Windows 和除 Linux 之外的其他未来的运行时。它还需求扩展 ContainerStatus CRI API,以允许 Kubelet 能够发现当前配置在容器上的资源。注意:RestartNotRequired 并不能保证容器不会重新启动,如果不这样做就无法应用新的资源,那么运行时可能会选择停止该容器。设置标志来单独控制 CPU 和内存是由于观察到通常 CPU 可以被添加/删除而没有什么问题,而对可用内存的更改更有可能需要重新启动。如果同时更新具有不同策略的多种资源类型,则任何重新启动策略都优先于 RestartNotRequired 策略。如果 pod 的 RestartPolicy 为 Never,则必须将 ResizePolicy 字段设置为 RestartNotRequired 才能通过验证。也就是说,如果系统无法原地执行调整大小,则任何原地调整大小都可能导致容器停止而不重新启动。
// ContainerResource 保存容器的资源配置
message ContainerResources {
// 特定于Linux容器的资源配置
LinuxContainerResources linux = 1;
// 特定于Windows容器的资源配置
WindowsContainerResources windows = 2;
}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;
}@@ -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;
}--- 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)注意:在 Pod 被拒绝后,调度器可以尝试在刚拒绝它的同一节点上重新调度替换 Pod。Kubelet 重启容错如果 Kubelet 在处理 Pod 大小调整的过程中重新启动,那么在重新启动时,所有 Pod 都会以其当前 Status...ResourcesAllocated 值被接纳,并且在添加所有现有 Pod 后处理大小调整。这可确保调整大小不会影响之前已接纳的现有 Pod。
T=0: 一个新的 Pod 被创建
- `spec.containers[0].resources.requests[cpu]` = 1
- 所有状态都未设置
T=1: 应用 apiserver 默认值
- `spec.containers[0].resources.requests[cpu]` = 1
- `status.containerStatuses[0].resourcesAllocated[cpu]` = 1
- `status.resize[cpu]` = unset
T=2: kubelet 运行 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 调整)
- apiserver 验证请求(例如 limits 不低于 requests,不超过 ResourceQuota 等)并接受操作
- apiserver 设置 `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 发现大小调整 #1 并接受它
- kubelet 发送 patch 操作 {
`resourceVersion` = `<previous value>` # 启用冲突检测
`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 # 此时又来进行 Resize 操作
- apiserver 验证请求并接受操作
- apiserver 设置 `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: 容器运行时应用 cpu=1.5
- kubelet 发送 patch 操作 {
`resourceVersion` = `<previous value>` # 启用冲突检测
`status.containerStatuses[0].resources.requests[cpu]` = 1.5
`status.resize[cpu]` = unset
}
- apiserver操作失败,出现“冲突”错误
T=7: kubelet刷新并查看到大小调整 #2 (cpu = 2)
- kubelet 认为这是可行的,但现在不行
- kubelet sends patch {
`resourceVersion` = `<updated value>` # enable conflict detection
`status.containerStatuses[0].resources.requests[cpu]` = 1.5
`status.resize[cpu]` = "Deferred" # 标记为延迟
}
- `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 验证请求并接受请求
- apiserver 设置 `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 观测到 pod 第三次 resize 操作 #3 并接受它
- kubelet sends patch {
`resourceVersion` = `<previous value>` # enable conflict detection
`status.containerStatuses[0].resourcesAllocated[cpu]` = 1.6
`status.resize[cpu]` = "InProgress" # 标记为调整中
}
- `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: 容器运行时应用 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 验证请求和接受操作
- apiserver 设置 `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 观测到pod第四次调整 resize #4
- 这个节点没有 100 CPUs, 所以 kubelet 不接受
- kubelet sends patch {
`resourceVersion` = `<previous value>` # enable conflict detection
`status.resize[cpu]` = "Infeasible" # 标记为拒绝
}
- `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+-----------+ +-----------+ +-----------+
| | | | | |
| apiserver | | kubelet | | runtime |
| | | | | |
+-----+-----+ +-----+-----+ +-----+-----+
| | |
| watch (pod update) | |
|------------------------------>| |
| [Containers.Resources] | |
| | |
| (admit) |
| | |
| | UpdateContainerResources() |
| |----------------------------->|
| | (set limits)
| |<- - - - - - - - - - - - - - -|
| | |
| | ContainerStatus() |
| |----------------------------->|
| | |
| | [ContainerResources] |
| |<- - - - - - - - - - - - - - -|
| | |
| update (pod status) | |
|<------------------------------| |
| [ContainerStatuses.Resources] | |
| | |
该 KEP 对应的 PR # In-place Pod Vertical Scaling feature #102884(https://github.com/kubernetes/kubernetes/pull/102884) 第一次也是2021年,到现在也两年左右时间了,这不得不佩服 Kubernetes 社区的严谨,毕竟该 PR 改动较大,不过幸运的时该 PR 已于昨天合并了,真是不容易,总共涉及160多个文件变更,虽然很大一部分是用于测试的代码。
下面我们来看下要怎么使用这个新的特性。现在有一个如下所示的测试 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"$ kubectl apply -f 2pod.yaml$ 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: 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"$ kubectl patch pod 2pod --patch '{"spec":{"containers":[{"name":"stress", "resources":{"requests":{"cpu":"650m"}, "limits":{"cpu":"650m"}}}]}}'
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: 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"resize: InProgress 的字段,表示接受调整并正在执行资源大小调整。如果现在再次调整资源大小:$ kubectl patch pod 2pod --patch '{"spec":{"containers":[{"name":"stress", "resources":{"requests":{"cpu":"3950m"}, "limits":{"cpu":"3950m"}}}]}}'
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: 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"$ 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"使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下
我在一个静态网站上工作(因此没有真正的服务器支持),我想在另一个网站中包含一个小的细长片段,可能会向它传递一个变量。这可能吗?在rails中很容易,虽然是render方法,但我不知道如何在slim上做(显然load方法不适用于slim)。 最佳答案 Slim包含Include插件,允许在编译时直接在模板文件中包含其他文件:require'slim/include'includepartial_name文档可在此处获得:https://github.com/slim-template/slim/blob/master/doc/incl