mirror of https://github.com/kubernetes/kops.git
Add EC2 instance lifecycle label to nodes
When using a "mixed instance policy"[1] instance group spot and onDemand nodes are part of the same ASG. The ASG handles the percentage of spot vs onDemand instances. There are no annotations, EC2 tags or labels to identify which instances are onDemand vs spot. There is a field called `InstanceLifecycle` accessible through `EC2.DescribeInstances`. The field `InstanceLifecycle` is available only in `spot` and `scheduled` AWS EC2 instance types. This PR introduces a new label to be attached on AWS EC2 spot nodes. The label is: ``` node-role.kubernetes.io/spot-worker: "true" ``` or ``` node-role.kubernetes.io/scheduled-worker: "true" ``` [^1]: https://github.com/kubernetes/kops/blob/master/docs/instance_groups.md#mixedinstancepolicy-aws-only
This commit is contained in:
parent
de7cc70c3d
commit
31acabf8cd
|
@ -119,6 +119,15 @@ func (r *NodeReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
|
|||
return ctrl.Result{}, fmt.Errorf("unable to build config for node %s: %v", node.Name, err)
|
||||
}
|
||||
|
||||
lifecycle, err := r.getInstanceLifecycle(ctx, node)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("unable to get instance lifecycle %s: %v", node.Name, err)
|
||||
}
|
||||
|
||||
if len(lifecycle) > 0 {
|
||||
labels[fmt.Sprintf("node-role.kubernetes.io/%s-worker", lifecycle)] = "true"
|
||||
}
|
||||
|
||||
updateLabels := make(map[string]string)
|
||||
for k, v := range labels {
|
||||
actual, found := node.Labels[k]
|
||||
|
@ -188,6 +197,17 @@ func (r *NodeReconciler) getClusterForNode(node *corev1.Node) (*kops.Cluster, er
|
|||
return cluster, nil
|
||||
}
|
||||
|
||||
// getInstanceLifecycle returns InstanceLifecycle string object
|
||||
func (r *NodeReconciler) getInstanceLifecycle(ctx context.Context, node *corev1.Node) (string, error) {
|
||||
|
||||
identity, err := r.identifier.IdentifyNode(ctx, node)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error identifying node %q: %v", node.Name, err)
|
||||
}
|
||||
|
||||
return identity.InstanceLifecycle, nil
|
||||
}
|
||||
|
||||
// getInstanceGroupForNode returns the kops.InstanceGroup object for the node
|
||||
func (r *NodeReconciler) getInstanceGroupForNode(ctx context.Context, node *corev1.Node) (*kops.InstanceGroup, error) {
|
||||
// We assume that if the instancegroup label is set, that it is correct
|
||||
|
|
|
@ -102,6 +102,11 @@ func (i *nodeIdentifier) IdentifyNode(ctx context.Context, node *corev1.Node) (*
|
|||
return nil, fmt.Errorf("found instance %q, but state is %q", instanceID, instanceState)
|
||||
}
|
||||
|
||||
lifecycle := ""
|
||||
if instance.InstanceLifecycle != nil {
|
||||
lifecycle = *instance.InstanceLifecycle
|
||||
}
|
||||
|
||||
// TODO: Should we traverse to the ASG to confirm the tags there?
|
||||
igName := getTag(instance.Tags, CloudTagInstanceGroupName)
|
||||
if igName == "" {
|
||||
|
@ -110,6 +115,7 @@ func (i *nodeIdentifier) IdentifyNode(ctx context.Context, node *corev1.Node) (*
|
|||
|
||||
info := &nodeidentity.Info{}
|
||||
info.InstanceGroup = igName
|
||||
info.InstanceLifecycle = lifecycle
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
|
|
@ -27,5 +27,6 @@ type Identifier interface {
|
|||
}
|
||||
|
||||
type Info struct {
|
||||
InstanceGroup string
|
||||
InstanceGroup string
|
||||
InstanceLifecycle string
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue