Skip to content

Commit

Permalink
update api for future bluegreen (#214)
Browse files Browse the repository at this point in the history
add status conversion



nextStepIndex default value from 0 to -1



restore the enableExtra field in BR

Signed-off-by: yunbo <[email protected]>
Co-authored-by: yunbo <[email protected]>
  • Loading branch information
myname4423 and Funinu authored Jun 12, 2024
1 parent 62794dc commit 1e8af4a
Show file tree
Hide file tree
Showing 23 changed files with 1,136 additions and 122 deletions.
10 changes: 10 additions & 0 deletions api/v1alpha1/batchrelease_plan_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,16 @@ type ReleasePlan struct {
// only support for canary deployment
// +optional
PatchPodTemplateMetadata *PatchPodTemplateMetadata `json:"patchPodTemplateMetadata,omitempty"`
// RollingStyle can be "Canary", "Partiton" or "BlueGreen"
RollingStyle RollingStyleType `json:"rollingStyle,omitempty"`
// EnableExtraWorkloadForCanary indicates whether to create extra workload for canary
// True corresponds to RollingStyle "Canary".
// False corresponds to RollingStyle "Partiton".
// Ignored in BlueGreen-style.
// This field is about to deprecate, use RollingStyle instead.
// If both of them are set, controller will only consider this
// filed when RollingStyle is empty
EnableExtraWorkloadForCanary bool `json:"enableExtraWorkloadForCanary"`
}

type FinalizingPolicyType string
Expand Down
55 changes: 35 additions & 20 deletions api/v1alpha1/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,18 +104,22 @@ func (src *Rollout) ConvertTo(dst conversion.Hub) error {
return nil
}
obj.Status.CanaryStatus = &v1beta1.CanaryStatus{
ObservedWorkloadGeneration: src.Status.CanaryStatus.ObservedWorkloadGeneration,
ObservedRolloutID: src.Status.CanaryStatus.ObservedRolloutID,
RolloutHash: src.Status.CanaryStatus.RolloutHash,
StableRevision: src.Status.CanaryStatus.StableRevision,
CanaryRevision: src.Status.CanaryStatus.CanaryRevision,
PodTemplateHash: src.Status.CanaryStatus.PodTemplateHash,
CanaryReplicas: src.Status.CanaryStatus.CanaryReplicas,
CanaryReadyReplicas: src.Status.CanaryStatus.CanaryReadyReplicas,
CurrentStepIndex: src.Status.CanaryStatus.CurrentStepIndex,
CurrentStepState: v1beta1.CanaryStepState(src.Status.CanaryStatus.CurrentStepState),
Message: src.Status.CanaryStatus.Message,
LastUpdateTime: src.Status.CanaryStatus.LastUpdateTime,
CommonStatus: v1beta1.CommonStatus{
ObservedWorkloadGeneration: src.Status.CanaryStatus.ObservedWorkloadGeneration,
ObservedRolloutID: src.Status.CanaryStatus.ObservedRolloutID,
RolloutHash: src.Status.CanaryStatus.RolloutHash,
StableRevision: src.Status.CanaryStatus.StableRevision,
PodTemplateHash: src.Status.CanaryStatus.PodTemplateHash,
CurrentStepIndex: src.Status.CanaryStatus.CurrentStepIndex,
CurrentStepState: v1beta1.CanaryStepState(src.Status.CanaryStatus.CurrentStepState),
Message: src.Status.CanaryStatus.Message,
LastUpdateTime: src.Status.CanaryStatus.LastUpdateTime,
FinalisingStep: v1beta1.FinalisingStepType(src.Status.CanaryStatus.FinalisingStep),
NextStepIndex: src.Status.CanaryStatus.NextStepIndex,
},
CanaryRevision: src.Status.CanaryStatus.CanaryRevision,
CanaryReplicas: src.Status.CanaryStatus.CanaryReplicas,
CanaryReadyReplicas: src.Status.CanaryStatus.CanaryReadyReplicas,
}
return nil
default:
Expand Down Expand Up @@ -167,7 +171,9 @@ func (dst *Rollout) ConvertFrom(src conversion.Hub) error {
case *v1beta1.Rollout:
srcV1beta1 := src.(*v1beta1.Rollout)
dst.ObjectMeta = srcV1beta1.ObjectMeta

if !srcV1beta1.Spec.Strategy.IsCanaryStragegy() {
return fmt.Errorf("v1beta1 Rollout with %s strategy cannot be converted to v1alpha1", srcV1beta1.Spec.Strategy.GetRollingStyle())
}
// spec
dst.Spec = RolloutSpec{
ObjectRef: ObjectRef{
Expand Down Expand Up @@ -254,6 +260,8 @@ func (dst *Rollout) ConvertFrom(src conversion.Hub) error {
CurrentStepState: CanaryStepState(srcV1beta1.Status.CanaryStatus.CurrentStepState),
Message: srcV1beta1.Status.CanaryStatus.Message,
LastUpdateTime: srcV1beta1.Status.CanaryStatus.LastUpdateTime,
FinalisingStep: FinalizeStateType(srcV1beta1.Status.CanaryStatus.FinalisingStep),
NextStepIndex: srcV1beta1.Status.CanaryStatus.NextStepIndex,
}
return nil
default:
Expand Down Expand Up @@ -338,9 +346,18 @@ func (src *BatchRelease) ConvertTo(dst conversion.Hub) error {
obj.Spec.ReleasePlan.PatchPodTemplateMetadata.Labels[k] = v
}
}
if !strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(PartitionRollingStyle)) {
obj.Spec.ReleasePlan.EnableExtraWorkloadForCanary = true

if strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(PartitionRollingStyle)) {
obj.Spec.ReleasePlan.RollingStyle = v1beta1.PartitionRollingStyle
}
if strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(CanaryRollingStyle)) {
obj.Spec.ReleasePlan.RollingStyle = v1beta1.CanaryRollingStyle
}
if strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(BlueGreenRollingStyle)) {
obj.Spec.ReleasePlan.RollingStyle = v1beta1.BlueGreenRollingStyle
}

obj.Spec.ReleasePlan.EnableExtraWorkloadForCanary = srcSpec.ReleasePlan.EnableExtraWorkloadForCanary

// status
obj.Status = v1beta1.BatchReleaseStatus{
Expand Down Expand Up @@ -417,11 +434,9 @@ func (dst *BatchRelease) ConvertFrom(src conversion.Hub) error {
if dst.Annotations == nil {
dst.Annotations = map[string]string{}
}
if srcV1beta1.Spec.ReleasePlan.EnableExtraWorkloadForCanary {
dst.Annotations[RolloutStyleAnnotation] = strings.ToLower(string(CanaryRollingStyle))
} else {
dst.Annotations[RolloutStyleAnnotation] = strings.ToLower(string(PartitionRollingStyle))
}
dst.Annotations[RolloutStyleAnnotation] = strings.ToLower(string(srcV1beta1.Spec.ReleasePlan.RollingStyle))
dst.Spec.ReleasePlan.RollingStyle = RollingStyleType(srcV1beta1.Spec.ReleasePlan.RollingStyle)
dst.Spec.ReleasePlan.EnableExtraWorkloadForCanary = srcV1beta1.Spec.ReleasePlan.EnableExtraWorkloadForCanary

// status
dst.Status = BatchReleaseStatus{
Expand Down
4 changes: 3 additions & 1 deletion api/v1alpha1/deployment_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ const (
PartitionRollingStyle RollingStyleType = "Partition"
// CanaryRollingStyle means rolling in canary way, and will create a canary Deployment.
CanaryRollingStyle RollingStyleType = "Canary"
// BlueGreenRollingStyle means rolling in blue-green way, and will NOT create a canary Deployment.
BlueGreenRollingStyle RollingStyleType = "BlueGreen"
)

// DeploymentExtraStatus is extra status field for Advanced Deployment
Expand All @@ -74,7 +76,7 @@ type DeploymentExtraStatus struct {
}

func SetDefaultDeploymentStrategy(strategy *DeploymentStrategy) {
if strategy.RollingStyle == CanaryRollingStyle {
if strategy.RollingStyle != PartitionRollingStyle {
return
}
if strategy.RollingUpdate == nil {
Expand Down
24 changes: 18 additions & 6 deletions api/v1alpha1/rollout_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,16 +242,28 @@ type CanaryStatus struct {
CanaryReplicas int32 `json:"canaryReplicas"`
// CanaryReadyReplicas the numbers of ready canary revision pods
CanaryReadyReplicas int32 `json:"canaryReadyReplicas"`
// CurrentStepIndex defines the current step of the rollout is on. If the current step index is null, the
// controller will execute the rollout.
// NextStepIndex defines the next step of the rollout is on.
// In normal case, NextStepIndex is equal to CurrentStepIndex + 1
// If the current step is the last step, NextStepIndex is equal to -1
// Before the release, NextStepIndex is also equal to -1
// 0 is not used and won't appear in any case
// It is allowed to patch NextStepIndex by design,
// e.g. if CurrentStepIndex is 2, user can patch NextStepIndex to 3 (if exists) to
// achieve batch jump, or patch NextStepIndex to 1 to implement a re-execution of step 1
// Patching it with a non-positive value is meaningless, which will be corrected
// in the next reconciliation
// achieve batch jump, or patch NextStepIndex to 1 to implement a re-execution of step 1
NextStepIndex int32 `json:"nextStepIndex"`
// +optional
CurrentStepIndex int32 `json:"currentStepIndex"`
CurrentStepState CanaryStepState `json:"currentStepState"`
Message string `json:"message,omitempty"`
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
CurrentStepIndex int32 `json:"currentStepIndex"`
CurrentStepState CanaryStepState `json:"currentStepState"`
Message string `json:"message,omitempty"`
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
FinalisingStep FinalizeStateType `json:"finalisingStep"`
}

type CanaryStepState string
type FinalizeStateType string

const (
CanaryStepStateUpgrade CanaryStepState = "StepUpgrade"
Expand Down
12 changes: 9 additions & 3 deletions api/v1beta1/batchrelease_plan_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,15 @@ type ReleasePlan struct {
// only support for canary deployment
// +optional
PatchPodTemplateMetadata *PatchPodTemplateMetadata `json:"patchPodTemplateMetadata,omitempty"`
// If true, then it will create new deployment for canary, such as: workload-demo-canary.
// When user verifies that the canary version is ready, we will remove the canary deployment and release the deployment workload-demo in full.
// Current only support k8s native deployment
// RollingStyle can be "Canary", "Partiton" or "BlueGreen"
RollingStyle RollingStyleType `json:"rollingStyle,omitempty"`
// EnableExtraWorkloadForCanary indicates whether to create extra workload for canary
// True corresponds to RollingStyle "Canary".
// False corresponds to RollingStyle "Partiton".
// Ignored in BlueGreen-style.
// This field is about to deprecate, use RollingStyle instead.
// If both of them are set, controller will only consider this
// filed when RollingStyle is empty
EnableExtraWorkloadForCanary bool `json:"enableExtraWorkloadForCanary"`
}

Expand Down
80 changes: 79 additions & 1 deletion api/v1beta1/deployment_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ const (
// AdvancedDeploymentControlLabel is label for deployment,
// which labels whether the deployment is controlled by advanced-deployment-controller.
AdvancedDeploymentControlLabel = "rollouts.kruise.io/controlled-by-advanced-deployment-controller"

// OriginalDeploymentStrategyAnnotation is annotation for workload in BlueGreen Release,
// it will store the original setting of the workload, which will be used to restore the workload
OriginalDeploymentStrategyAnnotation = "rollouts.kruise.io/original-deployment-strategy"

// MaxProgressSeconds is the value we set for ProgressDeadlineSeconds
// MaxReadySeconds is the value we set for MinReadySeconds, which is one less than ProgressDeadlineSeconds
// MaxInt32: 2147483647, ≈ 68 years
MaxProgressSeconds = 1<<31 - 1
MaxReadySeconds = MaxProgressSeconds - 1
)

// DeploymentStrategy is strategy field for Advanced Deployment
Expand All @@ -52,13 +62,40 @@ type DeploymentStrategy struct {
Partition intstr.IntOrString `json:"partition,omitempty"`
}

// OriginalDeploymentStrategy stores part of the fileds of a workload,
// so that it can be restored when finalizing.
// It is only used for BlueGreen Release
// Similar to DeploymentStrategy, it is an annotation used in workload
// However, unlike DeploymentStrategy, it is only used to store and restore the user's strategy
type OriginalDeploymentStrategy struct {
// The deployment strategy to use to replace existing pods with new ones.
// +optional
// +patchStrategy=retainKeys
Strategy *apps.DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" protobuf:"bytes,4,opt,name=strategy"`

// Minimum number of seconds for which a newly created pod should be ready
// without any of its container crashing, for it to be considered available.
// Defaults to 0 (pod will be considered available as soon as it is ready)
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,5,opt,name=minReadySeconds"`

// The maximum time in seconds for a deployment to make progress before it
// is considered to be failed. The deployment controller will continue to
// process failed deployments and a condition with a ProgressDeadlineExceeded
// reason will be surfaced in the deployment status. Note that progress will
// not be estimated during the time a deployment is paused. Defaults to 600s.
ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty" protobuf:"varint,9,opt,name=progressDeadlineSeconds"`
}

type RollingStyleType string

const (
// PartitionRollingStyle means rolling in batches just like CloneSet, and will NOT create any extra Deployment;
PartitionRollingStyle RollingStyleType = "Partition"
// CanaryRollingStyle means rolling in canary way, and will create a canary Deployment.
CanaryRollingStyle RollingStyleType = "Canary"
// BlueGreenRollingStyle means rolling in blue-green way, and will NOT create a extra Deployment.
BlueGreenRollingStyle RollingStyleType = "BlueGreen"
)

// DeploymentExtraStatus is extra status field for Advanced Deployment
Expand All @@ -74,7 +111,7 @@ type DeploymentExtraStatus struct {
}

func SetDefaultDeploymentStrategy(strategy *DeploymentStrategy) {
if strategy.RollingStyle == CanaryRollingStyle {
if strategy.RollingStyle != PartitionRollingStyle {
return
}
if strategy.RollingUpdate == nil {
Expand All @@ -101,3 +138,44 @@ func SetDefaultDeploymentStrategy(strategy *DeploymentStrategy) {
}
}
}

func SetDefaultSetting(setting *OriginalDeploymentStrategy) {
if setting.ProgressDeadlineSeconds == nil {
setting.ProgressDeadlineSeconds = new(int32)
*setting.ProgressDeadlineSeconds = 600
}
if setting.Strategy == nil {
setting.Strategy = &apps.DeploymentStrategy{}
}
if setting.Strategy.Type == "" {
setting.Strategy.Type = apps.RollingUpdateDeploymentStrategyType
}
if setting.Strategy.Type == apps.RecreateDeploymentStrategyType {
return
}
strategy := setting.Strategy
if strategy.RollingUpdate == nil {
strategy.RollingUpdate = &apps.RollingUpdateDeployment{}
}
if strategy.RollingUpdate.MaxUnavailable == nil {
// Set MaxUnavailable as 25% by default
maxUnavailable := intstr.FromString("25%")
strategy.RollingUpdate.MaxUnavailable = &maxUnavailable
}
if strategy.RollingUpdate.MaxSurge == nil {
// Set MaxSurge as 25% by default
maxSurge := intstr.FromString("25%")
strategy.RollingUpdate.MaxUnavailable = &maxSurge
}

// Cannot allow maxSurge==0 && MaxUnavailable==0, otherwise, no pod can be updated when rolling update.
maxSurge, _ := intstr.GetScaledValueFromIntOrPercent(strategy.RollingUpdate.MaxSurge, 100, true)
maxUnavailable, _ := intstr.GetScaledValueFromIntOrPercent(strategy.RollingUpdate.MaxUnavailable, 100, true)
if maxSurge == 0 && maxUnavailable == 0 {
strategy.RollingUpdate = &apps.RollingUpdateDeployment{
MaxSurge: &intstr.IntOrString{Type: intstr.Int, IntVal: 0},
MaxUnavailable: &intstr.IntOrString{Type: intstr.Int, IntVal: 1},
}
}

}
Loading

0 comments on commit 1e8af4a

Please sign in to comment.