Skip to content

Commit 124ecf2

Browse files
CKS: restart the nodes of a cluster with new node settings, a few at a time
A CloudManaged Kubernetes cluster could get a new service offering only through a scale, which changes every node at once with no drain, its affinity groups only while stopped, and its root disk size not at all. updateKubernetesCluster sets, for each node type (control, worker, etcd), the service offering, the root disk size and the affinity groups. The nodes created from then on get them. A cluster created before its node types had settings of their own first gets the service offering of the cluster copied to them; templates are left as they are. With rollout=true, the nodes that differ from the settings of their type are restarted with them: the external etcd nodes, then the control nodes, one at a time, then the worker nodes, maxunavailable at a time (1 by default, and always leaving a worker running). For each batch: - every other node must be running and Ready, and a control or etcd node is only taken down if the others keep a quorum - each Kubernetes node is annotated with its boot ID, unless someone else cordoned it, then cordoned and drained - its VM is stopped, given the offering, a larger root disk and the affinity groups, and started, which places it by its new groups; cloud-init grows the root partition and file system at boot - once it is Ready with another boot ID, and etcd is healthy, it is uncordoned and the annotation removed A control or etcd node type with too few nodes to lose one (a single control node, a 2-node stacked control plane, 2 etcd nodes) can not be rolled: a rollout=true that would make one of its nodes differ from the settings is refused, and its nodes that differ anyway are left out and reported in lasterror, while the other types are still rolled. Nodes are restarted rather than changed live, which CloudStack can not do reliably for a KVM VM, and which would leave the guest and kubelet unaware of the new resources. Nothing else is recorded: the nodes that still differ, are stopped or carry the annotation are the work left, and go first when the rollout is run again, which is how one that failed is resumed. However a rollout ends, it uncordons the nodes that are back, leaving the others cordoned, counts the CPU cores and memory of the cluster from its VMs, and moves the cluster from the new Updating state to Running, or to Alert if it is not healthy. Why it stopped is shown as lasterror. cancelrollout=true stops a rollout between two batches. Other operations are refused while a cluster is Updating, and the state scanner moves a cluster left Updating by a management server that stopped to Alert. The response also shows the number of nodes of each type that differ from the settings of their type. Signed-off-by: Brad House <bhouse@nexthop.ai>
1 parent 8a8b89e commit 124ecf2

19 files changed

Lines changed: 3009 additions & 25 deletions

File tree

‎api/src/main/java/com/cloud/kubernetes/cluster/KubernetesCluster.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ enum Event {
4747
AddNodeRequested,
4848
RemoveNodeRequested,
4949
UpgradeRequested,
50+
UpdateRequested,
5051
OperationSucceeded,
5152
OperationFailed,
5253
CreateFailed,
@@ -62,6 +63,7 @@ enum State {
6263
Scaling("Transient state in which resources are either getting scaled up/down"),
6364
ScalingStoppedCluster("Transient state in which the service offerings of stopped clusters are getting scaled"),
6465
Upgrading("Transient state in which cluster is getting upgraded"),
66+
Updating("Transient state in which the nodes of the cluster are restarted with their stored settings, a few at a time"),
6567
Importing("Transient state in which additional nodes are added as worker nodes to a cluster"),
6668
RemovingNodes("Transient state in which additional nodes are removed from a cluster"),
6769
Alert("State to represent Kubernetes clusters which are not in expected desired state (operationally in active control place, stopped cluster VM's etc)."),
@@ -108,6 +110,12 @@ enum State {
108110
s_fsm.addTransition(State.Upgrading, Event.OperationSucceeded, State.Running);
109111
s_fsm.addTransition(State.Upgrading, Event.OperationFailed, State.Alert);
110112

113+
// a rollout ends in Running if the cluster is healthy, and in Alert otherwise
114+
s_fsm.addTransition(State.Running, Event.UpdateRequested, State.Updating);
115+
s_fsm.addTransition(State.Alert, Event.UpdateRequested, State.Updating);
116+
s_fsm.addTransition(State.Updating, Event.OperationSucceeded, State.Running);
117+
s_fsm.addTransition(State.Updating, Event.OperationFailed, State.Alert);
118+
111119
s_fsm.addTransition(State.Running, Event.AddNodeRequested, State.Importing);
112120
s_fsm.addTransition(State.Alert, Event.AddNodeRequested, State.Importing);
113121
s_fsm.addTransition(State.Importing, Event.OperationSucceeded, State.Running);
@@ -155,6 +163,9 @@ enum State {
155163
long getCores();
156164
long getMemory();
157165
long getNodeRootDiskSize();
166+
Long getControlNodeRootDiskSize();
167+
Long getWorkerNodeRootDiskSize();
168+
Long getEtcdNodeRootDiskSize();
158169
String getEndpoint();
159170
boolean isCheckForGc();
160171
@Override

‎api/src/main/java/org/apache/cloudstack/api/ApiConstants.java‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1324,6 +1324,16 @@ public class ApiConstants {
13241324
public static final String NODE_TYPE_OFFERING_MAP = "nodeofferings";
13251325
public static final String NODE_TYPE_TEMPLATE_MAP = "nodetemplates";
13261326
public static final String NODE_TYPE_AFFINITY_GROUP_MAP = "nodeaffinitygroups";
1327+
public static final String NODE_TYPE_ROOT_DISK_SIZE_MAP = "noderootdisksizes";
1328+
public static final String CONTROL_ROOT_DISK_SIZE = "controlrootdisksize";
1329+
public static final String WORKER_ROOT_DISK_SIZE = "workerrootdisksize";
1330+
public static final String ETCD_ROOT_DISK_SIZE = "etcdrootdisksize";
1331+
public static final String CONTROL_NODES_OUT_OF_DATE = "controlnodesoutofdate";
1332+
public static final String WORKER_NODES_OUT_OF_DATE = "workernodesoutofdate";
1333+
public static final String ETCD_NODES_OUT_OF_DATE = "etcdnodesoutofdate";
1334+
public static final String ROLLOUT = "rollout";
1335+
public static final String CANCEL_ROLLOUT = "cancelrollout";
1336+
public static final String MAX_UNAVAILABLE = "maxunavailable";
13271337
public static final String CONTROL_AFFINITY_GROUP_IDS = "controlaffinitygroupids";
13281338
public static final String CONTROL_AFFINITY_GROUP_NAMES = "controlaffinitygroupnames";
13291339
public static final String WORKER_AFFINITY_GROUP_IDS = "workeraffinitygroupids";

‎engine/schema/src/main/resources/META-INF/db/schema-42300to2400.sql‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,8 @@ CREATE TABLE IF NOT EXISTS `cloud`.`instance_boot_group_details` (
239239
PRIMARY KEY (`id`),
240240
CONSTRAINT `fk_instance_boot_group_details__group_id` FOREIGN KEY (`boot_group_id`) REFERENCES `instance_boot_group` (`id`) ON DELETE CASCADE
241241
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
242+
243+
-- CKS: root disk size per node type. When not set, the cluster wide node_root_disk_size is used, as before.
244+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster', 'control_node_root_disk_size', 'bigint unsigned DEFAULT NULL COMMENT "root disk size in GB of the control nodes, node_root_disk_size when not set"');
245+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster', 'worker_node_root_disk_size', 'bigint unsigned DEFAULT NULL COMMENT "root disk size in GB of the worker nodes, node_root_disk_size when not set"');
246+
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.kubernetes_cluster', 'etcd_node_root_disk_size', 'bigint unsigned DEFAULT NULL COMMENT "root disk size in GB of the etcd nodes, the size of the template when not set"');

‎plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterEventTypes.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ public class KubernetesClusterEventTypes {
2626
public static final String EVENT_KUBERNETES_CLUSTER_NODES_ADD = "KUBERNETES.CLUSTER.NODES.ADD";
2727
public static final String EVENT_KUBERNETES_CLUSTER_NODES_REMOVE = "KUBERNETES.CLUSTER.NODES.REMOVE";
2828
public static final String EVENT_KUBERNETES_CLUSTER_AFFINITY_UPDATE = "KUBERNETES.CLUSTER.AFFINITY.UPDATE";
29+
public static final String EVENT_KUBERNETES_CLUSTER_UPDATE = "KUBERNETES.CLUSTER.UPDATE";
2930
}

0 commit comments

Comments
 (0)