Skip to content

Commit f46365c

Browse files
committed
Update AEP
Signed-off-by: Omer Aplatony <[email protected]>
1 parent 19e34c0 commit f46365c

File tree

1 file changed

+62
-46
lines changed
  • vertical-pod-autoscaler/enhancements/8818-in-place-only

1 file changed

+62
-46
lines changed

vertical-pod-autoscaler/enhancements/8818-in-place-only/README.md

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -76,50 +76,55 @@ Modify the `CanInPlaceUpdate` to accomdate the new update mode:
7676

7777
```golang
7878
func (ip *PodsInPlaceRestrictionImpl) CanInPlaceUpdate(pod *apiv1.Pod, updateMode vpa_types.UpdateMode) utils.InPlaceDecision {
79-
switch updateMode {
80-
case vpa_types.UpdateModeInPlaceOrRecreate:
81-
if !features.Enabled(features.InPlaceOrRecreate) {
82-
return utils.InPlaceEvict
83-
}
84-
case vpa_types.UpdateModeInPlace:
85-
if !features.Enabled(features.InPlace) {
86-
return utils.InPlaceEvict
87-
}
88-
default:
89-
return utils.InPlaceEvict
90-
}
91-
92-
cr, present := ip.podToReplicaCreatorMap[getPodID(pod)]
93-
if present {
94-
singleGroupStats, present := ip.creatorToSingleGroupStatsMap[cr]
95-
if pod.Status.Phase == apiv1.PodPending {
96-
return utils.InPlaceDeferred
97-
}
98-
if present {
99-
if isInPlaceUpdating(pod) {
100-
// For InPlace mode we wait indefinitely for Kubelet
101-
if updateMode == vpa_types.UpdateModeInPlace {
102-
klog.V(4).InfoS("Pod is updating, waiting for completion (InPlace mode)",
103-
"pod", klog.KObj(pod))
104-
return utils.InPlaceDeferred
105-
}
106-
107-
// For InPlaceOrRecreate mode, check timeout
108-
canEvict := CanEvictInPlacingPod(pod, singleGroupStats, ip.lastInPlaceAttemptTimeMap, ip.clock)
109-
if canEvict {
79+
switch updateMode {
80+
case vpa_types.UpdateModeInPlaceOrRecreate:
81+
if !features.Enabled(features.InPlaceOrRecreate) {
82+
return utils.InPlaceEvict
83+
}
84+
case vpa_types.UpdateModeInPlace:
85+
if !features.Enabled(features.InPlace) {
86+
return utils.InPlaceEvict
87+
}
88+
case vpa_types.UpdateModeAuto:
89+
// Auto mode is deprecated but still supports in-place updates
90+
// when the feature gate is enabled
91+
if !features.Enabled(features.InPlaceOrRecreate) {
92+
return utils.InPlaceEvict
93+
}
94+
default:
95+
// UpdateModeOff, UpdateModeInitial, UpdateModeRecreate, etc.
96+
return utils.InPlaceEvict
97+
}
98+
99+
cr, present := ip.podToReplicaCreatorMap[getPodID(pod)]
100+
if present {
101+
singleGroupStats, present := ip.creatorToSingleGroupStatsMap[cr]
102+
if pod.Status.Phase == apiv1.PodPending {
103+
return utils.InPlaceDeferred
104+
}
105+
if present {
106+
if isInPlaceUpdating(pod) {
107+
// For InPlace mode we wait indefinitely for Kubelet
108+
if updateMode == vpa_types.UpdateModeInPlace {
109+
klog.V(4).InfoS("Pod is updating, waiting for completion (InPlace mode)", "pod", klog.KObj(pod))
110+
return utils.InPlaceDeferred
111+
}
112+
// For InPlaceOrRecreate mode, check timeout
113+
canEvict := CanEvictInPlacingPod(pod, singleGroupStats, ip.lastInPlaceAttemptTimeMap, ip.clock)
114+
if canEvict {
110115
klog.V(2).InfoS("Pod update timed out, suggesting eviction",
111116
"pod", klog.KObj(pod))
112-
return utils.InPlaceEvict
113-
}
114-
return utils.InPlaceDeferred
115-
}
116-
if singleGroupStats.isPodDisruptable() {
117-
return utils.InPlaceApproved
118-
}
119-
}
120-
}
121-
klog.V(4).InfoS("Can't in-place update pod, waiting for next loop", "pod", klog.KObj(pod))
122-
return utils.InPlaceDeferred
117+
return utils.InPlaceEvict
118+
}
119+
return utils.InPlaceDeferred
120+
}
121+
if singleGroupStats.isPodDisruptable() {
122+
return utils.InPlaceApproved
123+
}
124+
}
125+
}
126+
klog.V(4).InfoS("Can't in-place update pod, waiting for next loop", "pod", klog.KObj(pod))
127+
return utils.InPlaceDeferred
123128
}
124129
```
125130

@@ -152,17 +157,28 @@ for _, pod := range podsForInPlace {
152157

153158

154159
Retry is handled entirely by the Kubelet based on pod conditions:
155-
- `PodResizePending` (reason: `Deferred`) - Kubelet will retry automatically
156-
- `PodResizePending` (reason: `Infeasible`) - Kubelet will never retry
157-
- `PodResizeInProgress` - Resize is being applied
160+
- `PodResizePending` (reason: `Deferred`) - Kubelet will retry automatically, , VPA continues to defer.
161+
- `PodResizePending` (reason: `Infeasible`) - Kubelet will never retry, but VPA will continue to defer (not evict) in InPlace mode.
162+
- `PodResizeInProgress` - Resize is being applied, VPA waits indefinitely in InPlace mode.
163+
164+
### Behavior when Feature Gate is Disabled
165+
166+
- When `InPlace` feature gate is disabled and a VPA is configured with `UpdateMode: InPlace`, the updater will skip processing that VPA entirely (not fall back to eviction).
167+
- In contrast, `InPlaceOrRecreate` with its feature gate disabled will fall back to eviction mode.
168+
169+
This design ensures that `InPlace` mode truly guarantees no evictions, even in misconfiguration scenarios.
170+
158171

159172
## Test Plan
160173

161174
The following test scenarios will be added to e2e tests. The InPlace mode will be tested in the following scenarios:
162175

163176
- Basic In-Place Update: Pod successfully updated in-place with InPlace mode
164-
- Failed Update - No Eviction: Update fails due to node capacity, verify no eviction occurs and pod remains running
177+
- No Eviction on Failure: Update fails due to node capacity, verify no eviction occurs and pod remains running
178+
- Feature Gate Disabled: Verify InPlace mode is rejected when feature gate is disabled
179+
- Indefinite Wait for In-Progress Updates: Update is in-progress for extended period, verify no timeout/eviction occurs (unlike `InPlaceOrRecreate`)
165180
- Failed Update - Retry Success: Update fails initially, conditions improve, verify successful retry
181+
- Infeasible Resize Handling: Pod resize marked as infeasible, verify pod is deferred (not evicted)
166182

167183
## Upgrade / Downgrade Strategy
168184

0 commit comments

Comments
 (0)