Repository navigation
model-serving: add rolloutStrategy.updateMethod and in-place eligibility checks - #1882
Conversation
| // It includes any wait before the images are patched. | ||
| // When the deadline passes, the update of the unit has failed, and its Pods that are not ready on the target image follow the RecoveryPolicy. | ||
| // It only applies when updateMethod is InPlace, and is ignored otherwise. | ||
| // The controller defaults it to 1800 seconds. |
There was a problem hiding this comment.
If it is set to +kubebuilder:default=1800, it will take effect under the rolloutStrategy field and updateMethod will be ignored; therefore, it will also be applied to Recreate. progressDeadlineSeconds itself only applies to Inplace.
|
/cc @acsoto |
| if inplace.UpdateMethodOf(oldMS) != workloadv1alpha1.InPlaceUpdateMethod { | ||
| allErrs = append(allErrs, validateRolloutComplete(oldMS)...) | ||
| } else if revisionChanged(oldMS, ms) { | ||
| allErrs = append(allErrs, validateNoUnitInUpdate(oldMS)...) |
There was a problem hiding this comment.
Is blocking all image changes during an unfinished rollout temporary? This also rejects reverting a bad image, while #1829 relies on retargeting failed units for in-place rollback.
| if err != nil { | ||
| return false | ||
| } | ||
| return !bytes.Equal(oldData, newData) |
There was a problem hiding this comment.
How will this check align with #1799's semantic revision comparison so admission and the controller agree on what constitutes a new revision?
| // The controller defaults it to 1800 seconds. | ||
| // +kubebuilder:validation:Minimum=60 | ||
| // +optional | ||
| ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty"` |
There was a problem hiding this comment.
@VanderChen
I believe we still need a time interval that is different from RestartGracePeriodSeconds. This is because the cold start time for an LLM pod and the pod error tolerance period are two distinct concepts, and the time required for each is difficult to measure using a single time interval.
LiZhenCheng9527
left a comment
There was a problem hiding this comment.
I think your webhook is too redundant. Moreover, many of the restrictions are unreasonable.
You just need to specify in reconcile that when updateMethod is set to Inplace, you should use the Inplace upgrade only when the pod image has been modified. If any of the above conditions are not met, fall back to the recreate upgrade.
| strategyPath := field.NewPath("spec", "rolloutStrategy") | ||
| if strategy.Type == workloadv1alpha1.RoleRollingUpdate { | ||
| allErrs = append(allErrs, field.Forbidden(strategyPath.Child("type"), | ||
| "RoleRollingUpdate cannot be combined with rolloutStrategy.updateMethod InPlace")) |
There was a problem hiding this comment.
why?
If you're saying that your current implementation doesn't work, you need to explain why sg can use inplace but Role cannot.
There was a problem hiding this comment.
Role is also supported, it’s just not in the current plan.
There was a problem hiding this comment.
When will that plan be implemented?
Also, I'm curious about the difference between SG and Role in an in-place scenario—what makes it necessary to implement them separately? And this results in the need to add a validator.
There was a problem hiding this comment.
I want to add support for Role now too. I’ll go make the changes.
There was a problem hiding this comment.
When will that plan be implemented? Also, I'm curious about the difference between SG and Role in an in-place scenario—what makes it necessary to implement them separately? And this results in the need to add a validator.
Actually, the difference isn't that big—it's just the order in which they're implemented. hh
| allErrs = append(allErrs, validateInPlaceBudget(ms)...) | ||
| if len(ms.Spec.Plugins) > 0 { | ||
| allErrs = append(allErrs, field.Forbidden(field.NewPath("spec", "plugins"), | ||
| "plugins cannot be used with rolloutStrategy.updateMethod InPlace")) |
| return nil | ||
| } | ||
| var allErrs field.ErrorList | ||
| if inplace.UpdateMethodOf(oldMS) != workloadv1alpha1.InPlaceUpdateMethod { |
There was a problem hiding this comment.
How does this relate to the UpdateMethod in oldModelserving?
|
|
||
| // validateNoUnitInUpdate rejects a new revision until every ServingGroup outside the partition is updated. | ||
| // The target of an unfinished in-place update cannot change yet. | ||
| func validateNoUnitInUpdate(oldMS *workloadv1alpha1.ModelServing) field.ErrorList { |
There was a problem hiding this comment.
Why do this?
If this restriction is implemented, and an inplace update operation never completes due to an error, will ModelServing be unable to modify the configuration forever?
okay, i will fix it. |
89788bc to
3be54cf
Compare
3be54cf to
73bf24e
Compare
|
@LiZhenCheng9527 @acsoto PTAL. |
| // It only applies to in-place updates, and defaults to 1800 seconds. | ||
| // +kubebuilder:validation:Minimum=60 | ||
| // +optional | ||
| ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty"` |
There was a problem hiding this comment.
What should happen when this deadline expires, and why do we need a separate timeout rather than leaving a stalled update for the user to resolve?
There was a problem hiding this comment.
After the timeout, a Warning event named ProgressDeadlineExceeded is emitted first, and then the RecoverPolicy is applied.
There was a problem hiding this comment.
@VanderChen
I believe we still need a time interval that is different from RestartGracePeriodSeconds. This is because the cold start time for an LLM pod and the pod error tolerance period are two distinct concepts, and the time required for each is difficult to measure using a single time interval.
This is the explanation.
Our previous consideration was that we only need to wait for a RestartGracePeriodSeconds timeout and then proceed with the RecoveryPolicy.
|
/lgtm |
LiZhenCheng9527
left a comment
There was a problem hiding this comment.
I have an idea to verify whether ModelServing modifies only the pod.image. I would replace the old pod.Spec.image with the new one, calculate the hash value, and compare it with the hash value of the new ModelServing. If they match, it means only the pod.Spec.image was modified.
Let's discuss it at tomorrow's community meeting.
The current implementation of RBG's approach only accepts replacement operations whose paths match the /spec/containers/N/image regex. Our revision data, however, has two layouts: the old one is a wrapper list of complete Roles containing replicas, while the new one has entryTemplate and workerTemplate for each Role. Therefore, we need to write our own regex for each layout and add a replicas filter, which increases complexity. |
…ity checks Signed-off-by: kube-gopher <jzlyy68@gmail.com>
73bf24e to
44b1ddd
Compare
LiZhenCheng9527
left a comment
There was a problem hiding this comment.
It looks like everything's fine now.
/lgtm
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: LiZhenCheng9527 The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
What type of PR is this?
/kind feature
What this PR does / why we need it
API (
RolloutStrategy):updateMethod:Recreate(default) orInPlace. UnderInPlace, the controller patches container images on existing Pods when only regular-container images change. Otherwise it recreates the ServingGroup, or the Role instance underRoleRollingUpdate, and anInPlaceUpdateFallbackevent reports why.progressDeadlineSeconds: minimum 60. The controller applies the 1800s default. It is the maximum time for a ServingGroup or Role instance updated in place to become ready on the target image. After it passes, Pods that are not ready follow the RecoveryPolicy. It only applies to in-place updates.Eligibility (
pkg/model-serving-controller/inplace/eligibility.go):CheckEligibility(old, new)lists every change from one revision to another that an image patch cannot apply. Only regular-container images may change. Changes toschedulerName,plugins,gangPolicy,networkTopology, Role names,workerReplicas, container names or order, or any other Pod template field are reported.CheckRoleEligibility(old, new, role)checks one Role, forRoleRollingUpdate.restartPolicymust resolve toAlways, and no regular container may setrestartPolicyorrestartPolicyRules, because the update relies on kubelet restarting the patched container.imagePullPolicyis resolved the way the API server defaults it. A tag change that would change the effective pull policy is reported, so users can set it explicitly.Which issue(s) this PR fixes:
Part of #1829
Bug evidence (required for bug-related PRs):
Special notes for your reviewer:
Does this PR introduce a user-facing change?: