Skip to content

Commit 18fbeb6

Browse files
committed
feat: support TalosControlPlane rolling upgrade
Track Kubernetes version changes in `TalosControlPlane` resource. When changed recreate nodes one by one until all nodes have the desired Kubernetes version. The same happens when `infrastructureTemplate` is updated. Added new parameters to the `TalosControlPlane` resource which specify controlplanes rollout strategy and strategy configuration. Enable `Defaulter` webhook to populate all created/updated `TalosControlPlane` resources rollout strategy. Signed-off-by: Artem Chernyshev <[email protected]>
1 parent 28d3eab commit 18fbeb6

19 files changed

+722
-222
lines changed

Dockerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ ARG NAME
4040
RUN --mount=type=cache,target=/.cache controller-gen crd:crdVersions=v1 paths="./api/..." output:crd:dir=config/crd/bases output:webhook:dir=config/webhook webhook
4141
RUN --mount=type=cache,target=/.cache controller-gen rbac:roleName=manager-role paths="./controllers/..." output:rbac:dir=config/rbac
4242
FROM scratch AS manifests
43-
COPY --from=manifests-build /src/config/crd /config/crd
44-
COPY --from=manifests-build /src/config/rbac /config/rbac
43+
COPY --from=manifests-build /src/config /config
4544

4645
FROM build AS generate-build
4746
RUN --mount=type=cache,target=/.cache controller-gen object:headerFile=./hack/boilerplate.go.txt paths="./..."

api/v1alpha3/conditions.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ const (
3838
InvalidControlPlaneConfigReason = "InvalidControlPlaneConfig"
3939
)
4040

41+
const (
42+
// MachinesSpecUpToDateCondition documents that the spec of the machines controlled by the TalosControlPlane
43+
// is up to date. When this condition is false, the TalosControlPlane is executing a rolling upgrade.
44+
MachinesSpecUpToDateCondition clusterv1.ConditionType = "MachinesSpecUpToDate"
45+
46+
// RollingUpdateInProgressReason (Severity=Warning) documents a TalosControlPlane object executing a
47+
// rolling upgrade for aligning the machines spec to the desired state.
48+
RollingUpdateInProgressReason = "RollingUpdateInProgress"
49+
)
50+
4151
const (
4252
// ResizedCondition documents a TalosControlPlane that is resizing the set of controlled machines.
4353
ResizedCondition clusterv1.ConditionType = "Resized"

api/v1alpha3/taloscontrolplane_types.go

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
cabptv1 "github.com/talos-systems/cluster-api-bootstrap-provider-talos/api/v1alpha3"
99
corev1 "k8s.io/api/core/v1"
1010
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+
"k8s.io/apimachinery/pkg/util/intstr"
1112
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
1213
)
1314

@@ -21,6 +22,15 @@ type ControlPlaneConfig struct {
2122
ControlPlaneConfig cabptv1.TalosConfigSpec `json:"controlplane"`
2223
}
2324

25+
// RolloutStrategyType defines the rollout strategies for a KubeadmControlPlane.
26+
type RolloutStrategyType string
27+
28+
const (
29+
// RollingUpdateStrategyType replaces the old control planes by new one using rolling update
30+
// i.e. gradually scale up or down the old control planes and scale up or down the new one.
31+
RollingUpdateStrategyType RolloutStrategyType = "RollingUpdate"
32+
)
33+
2434
// TalosControlPlaneSpec defines the desired state of TalosControlPlane
2535
type TalosControlPlaneSpec struct {
2636
// Number of desired machines. Defaults to 1. When stacked etcd is used only
@@ -41,6 +51,39 @@ type TalosControlPlaneSpec struct {
4151
// ControlPlaneConfig is a two TalosConfigSpecs
4252
// to use for initializing and joining machines to the control plane.
4353
ControlPlaneConfig ControlPlaneConfig `json:"controlPlaneConfig"`
54+
55+
// The RolloutStrategy to use to replace control plane machines with
56+
// new ones.
57+
// +optional
58+
// +kubebuilder:default={type: "RollingUpdate", rollingUpdate: {maxSurge: 1}}
59+
RolloutStrategy *RolloutStrategy `json:"rolloutStrategy,omitempty"`
60+
}
61+
62+
// RolloutStrategy describes how to replace existing machines
63+
// with new ones.
64+
type RolloutStrategy struct {
65+
// Rolling update config params. Present only if
66+
// RolloutStrategyType = RollingUpdate.
67+
// +optional
68+
RollingUpdate *RollingUpdate `json:"rollingUpdate,omitempty"`
69+
70+
// Type of rollout. Currently the only supported strategy is
71+
// "RollingUpdate".
72+
// Default is RollingUpdate.
73+
// +optional
74+
Type RolloutStrategyType `json:"type,omitempty"`
75+
}
76+
77+
// RollingUpdate is used to control the desired behavior of rolling update.
78+
type RollingUpdate struct {
79+
// The maximum number of control planes that can be scheduled above or under the
80+
// desired number of control planes.
81+
// Value can be an absolute number 1 or 0.
82+
// Defaults to 1.
83+
// Example: when this is set to 1, the control plane can be scaled
84+
// up immediately when the rolling update starts.
85+
// +optional
86+
MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty"`
4487
}
4588

4689
// TalosControlPlaneStatus defines the observed state of TalosControlPlane
@@ -126,13 +169,13 @@ type TalosControlPlane struct {
126169
}
127170

128171
// GetConditions returns the set of conditions for this object.
129-
func (in *TalosControlPlane) GetConditions() clusterv1.Conditions {
130-
return in.Status.Conditions
172+
func (r *TalosControlPlane) GetConditions() clusterv1.Conditions {
173+
return r.Status.Conditions
131174
}
132175

133176
// SetConditions sets the conditions on this object.
134-
func (in *TalosControlPlane) SetConditions(conditions clusterv1.Conditions) {
135-
in.Status.Conditions = conditions
177+
func (r *TalosControlPlane) SetConditions(conditions clusterv1.Conditions) {
178+
r.Status.Conditions = conditions
136179
}
137180

138181
// +kubebuilder:object:root=true
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,61 @@
11
package v1alpha3
22

33
import (
4+
"strings"
5+
6+
"k8s.io/apimachinery/pkg/util/intstr"
47
ctrl "sigs.k8s.io/controller-runtime"
8+
"sigs.k8s.io/controller-runtime/pkg/webhook"
59
)
610

11+
// SetupWebhookWithManager implements webhook methods.
712
func (r *TalosControlPlane) SetupWebhookWithManager(mgr ctrl.Manager) error {
813
return ctrl.NewWebhookManagedBy(mgr).
914
For(r).
1015
Complete()
1116
}
17+
18+
// +kubebuilder:webhook:verbs=create;update,path=/mutate-controlplane-cluster-x-k8s-io-v1beta1-kubeadmcontrolplane,mutating=true,failurePolicy=fail,matchPolicy=Equivalent,groups=controlplane.cluster.x-k8s.io,resources=kubeadmcontrolplanes,versions=v1beta1,name=default.kubeadmcontrolplane.controlplane.cluster.x-k8s.io,sideEffects=None,admissionReviewVersions=v1;v1beta1
19+
20+
var _ webhook.Defaulter = &TalosControlPlane{}
21+
22+
// Default implements webhook.Defaulter so a webhook will be registered for the type.
23+
func (r *TalosControlPlane) Default() {
24+
defaultTalosControlPlaneSpec(&r.Spec, r.Namespace)
25+
}
26+
27+
func defaultTalosControlPlaneSpec(s *TalosControlPlaneSpec, namespace string) {
28+
if s.Replicas == nil {
29+
replicas := int32(1)
30+
s.Replicas = &replicas
31+
}
32+
33+
if !strings.HasPrefix(s.Version, "v") {
34+
s.Version = "v" + s.Version
35+
}
36+
37+
s.RolloutStrategy = defaultRolloutStrategy(s.RolloutStrategy)
38+
}
39+
40+
func defaultRolloutStrategy(rolloutStrategy *RolloutStrategy) *RolloutStrategy {
41+
ios1 := intstr.FromInt(1)
42+
43+
if rolloutStrategy == nil {
44+
rolloutStrategy = &RolloutStrategy{}
45+
}
46+
47+
// Enforce RollingUpdate strategy and default MaxSurge if not set.
48+
if rolloutStrategy != nil {
49+
if len(rolloutStrategy.Type) == 0 {
50+
rolloutStrategy.Type = RollingUpdateStrategyType
51+
}
52+
if rolloutStrategy.Type == RollingUpdateStrategyType {
53+
if rolloutStrategy.RollingUpdate == nil {
54+
rolloutStrategy.RollingUpdate = &RollingUpdate{}
55+
}
56+
rolloutStrategy.RollingUpdate.MaxSurge = intstr.ValueOrDefault(rolloutStrategy.RollingUpdate.MaxSurge, ios1)
57+
}
58+
}
59+
60+
return rolloutStrategy
61+
}

api/v1alpha3/zz_generated.deepcopy.go

Lines changed: 46 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/controlplane.cluster.x-k8s.io_taloscontrolplanes.yaml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,34 @@ spec:
183183
This is a pointer to distinguish between explicit zero and not specified.
184184
format: int32
185185
type: integer
186+
rolloutStrategy:
187+
default:
188+
rollingUpdate:
189+
maxSurge: 1
190+
type: RollingUpdate
191+
description: The RolloutStrategy to use to replace control plane machines
192+
with new ones.
193+
properties:
194+
rollingUpdate:
195+
description: Rolling update config params. Present only if RolloutStrategyType
196+
= RollingUpdate.
197+
properties:
198+
maxSurge:
199+
anyOf:
200+
- type: integer
201+
- type: string
202+
description: 'The maximum number of control planes that can
203+
be scheduled above or under the desired number of control
204+
planes. Value can be an absolute number 1 or 0. Defaults
205+
to 1. Example: when this is set to 1, the control plane
206+
can be scaled up immediately when the rolling update starts.'
207+
x-kubernetes-int-or-string: true
208+
type: object
209+
type:
210+
description: Type of rollout. Currently the only supported strategy
211+
is "RollingUpdate". Default is RollingUpdate.
212+
type: string
213+
type: object
186214
version:
187215
description: Version defines the desired Kubernetes version.
188216
minLength: 2

config/default/kustomization.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ bases:
1818

1919
patchesStrategicMerge:
2020
- manager_webhook_patch.yaml
21-
# - webhookcainjection_patch.yaml
21+
- webhookcainjection_patch.yaml
2222

2323
vars:
2424
- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
# This patch add annotation to admission webhook config and
22
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
3-
apiVersion: admissionregistration.k8s.io/v1beta1
3+
apiVersion: admissionregistration.k8s.io/v1
44
kind: MutatingWebhookConfiguration
55
metadata:
66
name: mutating-webhook-configuration
77
annotations:
88
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
9-
---
10-
apiVersion: admissionregistration.k8s.io/v1beta1
11-
kind: ValidatingWebhookConfiguration
12-
metadata:
13-
name: validating-webhook-configuration
14-
annotations:
15-
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)

config/webhook/manifests.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
apiVersion: admissionregistration.k8s.io/v1
3+
kind: MutatingWebhookConfiguration
4+
metadata:
5+
creationTimestamp: null
6+
name: mutating-webhook-configuration
7+
webhooks:
8+
- admissionReviewVersions:
9+
- v1
10+
- v1beta1
11+
clientConfig:
12+
service:
13+
name: webhook-service
14+
namespace: system
15+
path: /mutate-controlplane-cluster-x-k8s-io-v1beta1-kubeadmcontrolplane
16+
failurePolicy: Fail
17+
matchPolicy: Equivalent
18+
name: default.kubeadmcontrolplane.controlplane.cluster.x-k8s.io
19+
rules:
20+
- apiGroups:
21+
- controlplane.cluster.x-k8s.io
22+
apiVersions:
23+
- v1beta1
24+
operations:
25+
- CREATE
26+
- UPDATE
27+
resources:
28+
- kubeadmcontrolplanes
29+
sideEffects: None

config/webhook/service.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
1+
---
22
apiVersion: v1
33
kind: Service
44
metadata:

0 commit comments

Comments
 (0)