Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/CloneSet supports hot-standy pods management #1763

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions apis/apps/v1alpha1/cloneset_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ type CloneSetSpec struct {
// If unspecified, defaults to 1.
Replicas *int32 `json:"replicas,omitempty"`

// HotStandbyReplicas is the desired number of hot-standby replicas of the given Template.
// These are replicas in the sense that they are instantiations of the
// same Template.
// If unspecified, defaults to 0.
HotStandbyReplicas *int32 `json:"hotStandbyReplicas,omitempty"`

// Selector is a label query over pods that should match the replica count.
// It must match the pod template's labels.
// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
Expand Down Expand Up @@ -184,6 +190,31 @@ type CloneSetStatus struct {
// This field is calculated via Replicas - Partition.
ExpectedUpdatedReplicas int32 `json:"expectedUpdatedReplicas,omitempty"`

// HotStandbyReplicas is the number of hot-standby Pods created by the CloneSet controller.
HotStandbyReplicas int32 `json:"hotStandbyReplicas,omitempty"`

// HotStandbyReadyReplicas is the number of hot-standby Pods created by the CloneSet controller that have a Ready Condition.
HotStandbyReadyReplicas int32 `json:"hotStandbyReadyReplicas,omitempty"`

// HotStandbyAvailableReplicas is the number of hot-standby Pods created by the CloneSet controller that have a Ready Condition for at least minReadySeconds.
HotStandbyAvailableReplicas int32 `json:"hotStandbyAvailableReplicas,omitempty"`

// HotStandbyUpdatedReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
// indicated by updateRevision.
HotStandbyUpdatedReplicas int32 `json:"hotStandbyUpdatedReplicas,omitempty"`

// HotStandbyUpdatedReadyReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
// indicated by updateRevision and have a Ready Condition.
HotStandbyUpdatedReadyReplicas int32 `json:"hotStandbyUpdatedReadyReplicas,omitempty"`

// HotStandbyUpdatedAvailableReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
// indicated by updateRevision and have a Ready Condition for at least minReadySeconds.
HotStandbyUpdatedAvailableReplicas int32 `json:"hotStandbyUpdatedAvailableReplicas,omitempty"`

// HotStandbyExpectedUpdatedReplicas is the number of hot-standby Pods that should be updated by CloneSet controller.
// This field is calculated via Replicas - Partition.
HotStandbyExpectedUpdatedReplicas int32 `json:"hotStandbyExpectedUpdatedReplicas,omitempty"`

// UpdateRevision, if not empty, indicates the latest revision of the CloneSet.
UpdateRevision string `json:"updateRevision,omitempty"`

Expand All @@ -210,6 +241,10 @@ const (
CloneSetConditionFailedScale CloneSetConditionType = "FailedScale"
// CloneSetConditionFailedUpdate indicates cloneset controller failed to update pods.
CloneSetConditionFailedUpdate CloneSetConditionType = "FailedUpdate"
// CloneSetConditionHotStandbyFailedScale indicates cloneset controller failed to create or delete hot-standby pods/pvc.
CloneSetConditionHotStandbyFailedScale CloneSetConditionType = "HotStandbyFailedScale"
// CloneSetConditionHotStandbyFailedUpdate indicates cloneset controller failed to update hot-standby pods.
CloneSetConditionHotStandbyFailedUpdate CloneSetConditionType = "HotStandbyFailedUpdate"
)

// CloneSetCondition describes the state of a CloneSet at a certain point.
Expand Down
5 changes: 5 additions & 0 deletions apis/apps/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions config/crd/bases/apps.kruise.io_clonesets.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ spec:
If unspecified, defaults to 1.
format: int32
type: integer
hotStandbyReplicas:
description: |-
Replicas is the desired number of hot-standby replicas of the given Template.
These are replicas in the sense that they are instantiations of the
same Template.
If unspecified, defaults to 0.
format: int32
type: integer
revisionHistoryLimit:
description: |-
RevisionHistoryLimit is the maximum number of revisions that will
Expand Down Expand Up @@ -526,6 +534,44 @@ spec:
indicated by updateRevision.
format: int32
type: integer
hotStandbyReplicas:
description: HotStandbyReplicas is the number of hot-standby Pods created by the CloneSet controller.
format: int32
type: integer
hotStandbyReadyReplicas:
description: HotStandbyReadyReplicas is the number of hot-standby Pods created by the
CloneSet controller that have a Ready Condition.
format: int32
type: integer
hotStandbyAvailableReplicas:
description: HotStandbyAvailableReplicas is the number of hot-standby Pods created by the
CloneSet controller that have a Ready Condition for at least minReadySeconds.
format: int32
type: integer
hotStandbyUpdatedReplicas:
description: |-
HotStandbyUpdatedReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
indicated by updateRevision.
format: int32
type: integer
hotStandbyUpdatedReadyReplicas:
description: |-
HotStandbyUpdatedReadyReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
indicated by updateRevision and have a Ready Condition.
format: int32
type: integer
HotStandbyUpdatedAvailableReplicas:
description: |-
HotStandbyUpdatedAvailableReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
indicated by updateRevision and have a Ready Condition for at least minReadySeconds.
format: int32
type: integer
hotStandbyExpectedUpdatedReplicas:
description: |-
HotStandbyUpdatedReplicas is the number of hot-standby Pods created by the CloneSet controller from the CloneSet version
indicated by updateRevision.
format: int32
type: integer
required:
- availableReplicas
- readyReplicas
Expand Down
69 changes: 51 additions & 18 deletions pkg/controller/cloneset/cloneset_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package cloneset
import (
"context"
"fmt"
"github.com/openkruise/kruise/pkg/util/hotstandby"

appsv1alpha1 "github.com/openkruise/kruise/apis/apps/v1alpha1"
clonesetcore "github.com/openkruise/kruise/pkg/controller/cloneset/core"
Expand Down Expand Up @@ -81,35 +82,67 @@ func (r *realStatusUpdater) inconsistentStatus(cs *appsv1alpha1.CloneSet, newSta
newStatus.ExpectedUpdatedReplicas != oldStatus.ExpectedUpdatedReplicas ||
newStatus.UpdateRevision != oldStatus.UpdateRevision ||
newStatus.CurrentRevision != oldStatus.CurrentRevision ||
newStatus.LabelSelector != oldStatus.LabelSelector
newStatus.LabelSelector != oldStatus.LabelSelector ||
newStatus.HotStandbyReplicas != oldStatus.HotStandbyReplicas ||
newStatus.HotStandbyReadyReplicas != oldStatus.HotStandbyReadyReplicas ||
newStatus.HotStandbyAvailableReplicas != oldStatus.HotStandbyAvailableReplicas ||
newStatus.HotStandbyUpdatedReadyReplicas != oldStatus.HotStandbyUpdatedReadyReplicas ||
newStatus.HotStandbyUpdatedReplicas != oldStatus.HotStandbyUpdatedReplicas ||
newStatus.HotStandbyUpdatedAvailableReplicas != oldStatus.HotStandbyUpdatedAvailableReplicas ||
newStatus.HotStandbyExpectedUpdatedReplicas != oldStatus.HotStandbyExpectedUpdatedReplicas
}

func (r *realStatusUpdater) calculateStatus(cs *appsv1alpha1.CloneSet, newStatus *appsv1alpha1.CloneSetStatus, pods []*v1.Pod) {
coreControl := clonesetcore.New(cs)
for _, pod := range pods {
newStatus.Replicas++
if coreControl.IsPodUpdateReady(pod, 0) {
newStatus.ReadyReplicas++
}
if sync.IsPodAvailable(coreControl, pod, cs.Spec.MinReadySeconds) {
newStatus.AvailableReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) {
newStatus.UpdatedReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) && coreControl.IsPodUpdateReady(pod, 0) {
newStatus.UpdatedReadyReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) && sync.IsPodAvailable(coreControl, pod, cs.Spec.MinReadySeconds) {
newStatus.UpdatedAvailableReplicas++
if !hotstandby.IsHotStandbyPod(pod) {
newStatus.Replicas++
if coreControl.IsPodUpdateReady(pod, 0) {
newStatus.ReadyReplicas++
}
if sync.IsPodAvailable(coreControl, pod, cs.Spec.MinReadySeconds) {
newStatus.AvailableReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) {
newStatus.UpdatedReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) && coreControl.IsPodUpdateReady(pod, 0) {
newStatus.UpdatedReadyReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) && sync.IsPodAvailable(coreControl, pod, cs.Spec.MinReadySeconds) {
newStatus.UpdatedAvailableReplicas++
}
} else {
newStatus.HotStandbyReplicas++
if coreControl.IsPodUpdateReady(pod, 0) {
newStatus.HotStandbyReadyReplicas++
}
if sync.IsPodAvailable(coreControl, pod, cs.Spec.MinReadySeconds) {
newStatus.HotStandbyAvailableReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) {
newStatus.HotStandbyUpdatedReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) && coreControl.IsPodUpdateReady(pod, 0) {
newStatus.HotStandbyUpdatedReadyReplicas++
}
if clonesetutils.EqualToRevisionHash("", pod, newStatus.UpdateRevision) && sync.IsPodAvailable(coreControl, pod, cs.Spec.MinReadySeconds) {
newStatus.HotStandbyUpdatedAvailableReplicas++
}
}

}
// Consider the update revision as stable if revisions of all pods are consistent to it and have the expected number of replicas, no need to wait all of them ready
if newStatus.UpdatedReplicas == newStatus.Replicas && newStatus.Replicas == *cs.Spec.Replicas {
// Consider the update revision as stable if revisions of all normal pods and hot-standby pods are consistent to it.
// no need to wait all of them ready
if newStatus.UpdatedReplicas == newStatus.Replicas && newStatus.Replicas == *cs.Spec.Replicas && newStatus.HotStandbyUpdatedReplicas == newStatus.HotStandbyReplicas {
newStatus.CurrentRevision = newStatus.UpdateRevision
}

if partition, err := util.CalculatePartitionReplicas(cs.Spec.UpdateStrategy.Partition, cs.Spec.Replicas); err == nil {
newStatus.ExpectedUpdatedReplicas = *cs.Spec.Replicas - int32(partition)
}

if cs.Spec.HotStandbyReplicas != nil {
newStatus.HotStandbyExpectedUpdatedReplicas = *cs.Spec.HotStandbyReplicas
}
}
Loading
Loading