Reconcile Cluster Machine Deployment
func (dc *controller) reconcileClusterMachineDeployment(key string) error
- Gets the deployment name.
- Gets the
MachineDeployment
- TODO: WEIRD: freeze labels and deletion timestamp
- TODO: unclear why we do this
// Resync the MachineDeployment after 10 minutes to avoid missing out on missed out events
defer dc.enqueueMachineDeploymentAfter(deployment, 10*time.Minute)
- Add finalizers if deletion time stamp is nil
- TODO: Why is observed generation only updated conditionally in the below ? Shouldn't it be done always
everything := metav1.LabelSelector{}
if reflect.DeepEqual(d.Spec.Selector, &everything) {
dc.recorder.Eventf(d, v1.EventTypeWarning, "SelectingAll", "This deployment is selecting all machines. A non-empty selector is required.")
if d.Status.ObservedGeneration < d.Generation {
d.Status.ObservedGeneration = d.Generation
dc.controlMachineClient.MachineDeployments(d.Namespace).UpdateStatus(ctx, d, metav1.UpdateOptions{})
}
return nil
}
- Get
[]*v1alpha1.MachineSet
for this deployment usinggetMachineSetsForMachineDeployment
and assign tomachineSets
- if
deployment.DeletionTimestamp != nil
- if there are no finalizers on deployment return nil
- if
len(machineSets) == 0
delete the machine deployment finalizers and return nil - Call
dc.terminateMachineSets(ctx, machineSets)
Rollout Rolling
func (dc *controller) rolloutRolling(ctx context.Context,
d *v1alpha1.MachineDeployment,
msList []*v1alpha1.MachineSet,
machineMap map[types.UID]*v1alpha1.MachineList) error
1. Get new machine set corresponding to machine deployment and old machine sets
newMS, oldMSs, err := dc.getAllMachineSetsAndSyncRevision(ctx, d, msList, machineMap, true)
allMSs := append(oldMSs, newMS)
2. Taint the nodes backing the old machine sets.
This is a preference - the k8s scheduler will try to avoid placing a pod that does not tolerate thee taint on the node. Q: Why don't we use NoSchedule
instead ? Any pods scheduled on this node will need to be drained - more work to be done.
dc.taintNodesBackingMachineSets(
ctx,
oldISs, &v1.Taint{
Key: PreferNoScheduleKey,
Value: "True",
Effect: "PreferNoSchedule",
},
)
3. Add AutoScaler Scale-Down annotations to Nodes of Old Machine Sets
- Create the map. (TODO: Q: Why do we add 2 annotations ?)
clusterAutoscalerScaleDownAnnotations := make(map[string]string) clusterAutoscalerScaleDownAnnotations["cluster-autoscaler.kubernetes.io/scale-down-disabled"]="true" clusterAutoscalerScaleDownAnnotations["cluster-autoscaler.kubernetes.io/scale-down-disabled-by-mcm"]="true"
- Call
annotateNodesBackingMachineSets(ctx, allMSs, clusterAutoscalerScaleDownAnnotations)
4. Reconcile New Machine Set by calling reconcileNewMachineSet
scaledUp, err := dc.reconcileNewMachineSet(ctx, allISs, newIS, d)
func (dc *controller) reconcileNewMachineSet(ctx context.Context,
allMSs[]*v1alpha1.MachineSet,
newMS *v1alpha1.MachineSet,
deployment *v1alpha1.MachineDeployment)
(bool, error)
- if
newMS.Spec.Replicates == deployment.spec.Replicates
return - if
newMS.Spec.Replicas > deployment.Spec.Replicas
, we need to scale down. calldc.scaleMachineSet(ctx, newMS, deployment.Spec.Replicas, "down")
- Compute
newReplicasCount
usingNewMSNewReplicas(deployment, allMSs, newMS)
. - Call
dc.scaleMachineSet(ctx, newMS, newReplicasCount, "up")
Helper Methods
scaleMachineSet
func (dc *controller) scaleMachineSet(ctx context.Context,
ms *v1alpha1.MachineSet,
newScale int32,
deployment *v1alpha1.MachineDeployment,
scalingOperation string)
(bool, *v1alpha1.MachineSet, error) {
sizeNeedsUpdate := (ms.Spec.Replicas) != newScale
}
TODO: fill me in.
Get Machine Sets for Machine Deployment
func (dc *controller) getMachineSetsForMachineDeployment(ctx context.Context,
d *v1alpha1.MachineDeployment)
([]*v1alpha1.MachineSet, error)
- Get all machine sets using machine set lister.
NewMachineSetControllerRefManager
unclear
Get Machine Map for Machine Deployment
Returns a map from MachineSet UID to a list of Machines controlled by that MS, according to the Machine's ControllerRef.
func (dc *controller)
getMachineMapForMachineDeployment(d *v1alpha1.MachineDeployment,
machineSets []*v1alpha1.MachineSet)
(map[types.UID]*v1alpha1.MachineList, error) {
Terminate Machine Sets of Machine eDeployment
func (dc *controller) terminateMachineSets(ctx context.Context, machineSets []*v1alpha1.MachineSet)
Sync Deployment Status
func (dc *controller) syncStatusOnly(ctx context.Context,
d *v1alpha1.MachineDeployment,
msList []*v1alpha1.MachineSet,
machineMap map[types.UID]*v1alpha1.MachineList) error
Gets New and Old MachineSets and Sync Revision
func (dc *controller) getAllMachineSetsAndSyncRevision(ctx context.Context,
d *v1alpha1.MachineDeployment,
msList []*v1alpha1.MachineSet,
machineMap map[types.UID]*v1alpha1.MachineList,
createIfNotExisted bool)
(*v1alpha1.MachineSet, []*v1alpha1.MachineSet, error)
Overview
getAllMachineSetsAndSyncRevision
does the following:
- Get all old
MachineSets
theMachineDeployment:
d
targets, and calculate the max revision number among them (maxOldV
). - Get new
MachineSet
this deployment targets ie whose machine template matches the deployment's and updates new machine set's revision number to (maxOldV + 1
), This is done only if its revision number is smaller than(maxOldV + 1)
. If this step failed, we'll update it in the next deployment sync loop. - Copy new
MachineSet
's revision number to theMachineDeployment
(update deployment's revision). If this step failed, we'll update it in the next deployment sync loop.
Detail
- TODO: describe me
Annotate Nodes Backing Machine Sets
func (dc *controller) annotateNodesBackingMachineSets(
ctx context.Context,
machineSets []*v1alpha1.MachineSet,
annotations map[string]string) error
- Iterate through the
machineSets
. Loop variable:machineSet
- List all the machines. TODO: EXPENSIVE ??
allMachines, err := dc.machineLister.List(labels.Everything())
- Get the Selector for the Machine Set
selector, err := metav1.LabelSelectorAsSelector(machineSet.Spec.Selector)
- Claim the Machines for the given
machineSet
using the selector
filteredMachines, err = dc.claimMachines(ctx, machineSet, selector, allMachines)
- Iterate through
filteredMachines
, loop variable:machine
and ifNode
is not empty, add or update annotations on node.
if machine.Status.Node != "" {
err = AddOrUpdateAnnotationOnNode(
ctx,
dc.targetCoreClient,
machine.Status.Node,
annotations,
)
}
Claim Machines
Basically sets or unsets the owner reference of the machines matching selector to the deployment controller.
func (c *controller) claimMachines(ctx context.Context,
machineSet *v1alpha1.MachineSet,
selector labels.Selector,
allMachines []*v1alpha1.Machine)
([]*v1alpha1.Machine, error) {
TODO: delegates to MachineControllerRefManager.claimMachines
Sets or un-sets the owner reference of the machine object to the deployment controller.
Summary
- iterates through
allMachines
. Checks ifselector
matches the machine labels:m.Selector.Matches(labels.Set(machine.Labels)
- Gets the
controllerRef
of the machine usingmetav1.GetControllerOf(machine)
- If
controllerRef
is not nil and thecontrollerRef.UID
matches the - If so, then this is an adoption and calls
AdoptMachine
which patches the machines owner reference using the below:
addControllerPatch := fmt.Sprintf(
`{"metadata":{"ownerReferences":[{"apiVersion":"machine.sapcloud.io/v1alpha1","kind":"%s","name":"%s","uid":"%s","controller":true,"blockOwnerDeletion":true}],"uid":"%s"}}`,
m.controllerKind.Kind,
m.Controller.GetName(), m.Controller.GetUID(), machine.UID)
err := m.machineControl.PatchMachine(ctx, machine.Namespace, machine.Name, []byte(addControllerPatch))
err := m.machineControl.PatchMachine(ctx, machine.Namespace, machine.Name, []byte(addControllerPatch))
Helper Functions
Compute New Machine Set New Replicas
NewMSNewReplicas
calculates the number of replicas a deployment's new machine set should have.
- The new MS is saturated: newMS's replicas == deployment's replicas
- Max number of machines allowed is reached: deployment's replicas + maxSurge == allMS's replicas
func NewMSNewReplicas(deployment *v1alpha1.MachineDeployment,
allMSs []*v1alpha1.MachineSet,
newMS *v1alpha1.MachineSet) (int32, error)
// MS was called IS earlier (instance set)
- Get the
maxSurge
maxSurge, err = intstr.GetValueFromIntOrPercent(
deployment.Spec.Strategy.RollingUpdate.MaxSurge,
int(deployment.Spec.Replicas),
true
)
- Compute the
currentMachineCount
: iterate through all machine sets and sum upmachineset.Status.Replicas
maxTotalMachines = deployment.Spec.Replicas + maxSurge
if currentMachineCount >= maxTotalMachines return newMS.Spec.Replicas
// cannot scale up.- Compute
scaleUpCount := maxTotalMachines - currentMachineCount
- Make sure
scaleUpCount
does not exceed desired deployment replicasscaleUpCount = int32(integer.IntMin(int(scaleUpCount), int(deployment.Spec.Replicas -newMS.Spec.Replicas))