Skip to content

Commit 056778d

Browse files
committed
Add support for scaling kubernetes stateful sets
1 parent 030bb99 commit 056778d

File tree

4 files changed

+118
-41
lines changed

4 files changed

+118
-41
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ combination with [Buildbarn Remote Execution](https://github.com/buildbarn/bb-re
55
to automatically adjust the size of Amazon EC2
66
[Auto Scaling Groups (ASGs)](https://docs.aws.amazon.com/autoscaling/ec2/userguide/AutoScalingGroup.html),
77
EKS [Managed Node Groups](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html),
8-
or [Kubernetes deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
8+
or Kubernetes [deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)/
9+
[stateful sets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/)
910
of Buildbarn workers based on load. Load metrics are obtained by
1011
querying Prometheus, which in its turn extracts metrics from
1112
`bb_scheduler`. It relies on Prometheus to normalize the load metrics

cmd/bb_autoscaler/main.go

+50-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func main() {
104104
autoScalingClient = autoscaling.NewFromConfig(cfg)
105105
eksClient = eks.NewFromConfig(cfg)
106106
}
107-
case *bb_autoscaler.NodeGroupConfiguration_KubernetesDeployment:
107+
case *bb_autoscaler.NodeGroupConfiguration_KubernetesDeployment, *bb_autoscaler.NodeGroupConfiguration_KubernetesStatefulSet:
108108
if kubernetesClientset == nil {
109109
config, err := rest.InClusterConfig()
110110
if err != nil {
@@ -116,7 +116,7 @@ func main() {
116116
}
117117
}
118118
default:
119-
return status.Error(codes.InvalidArgument, "No ASG, EKS managed node group, or Kubernetes deployment name specified")
119+
return status.Error(codes.InvalidArgument, "No ASG, EKS managed node group, Kubernetes deployment, or Kubernetes stateful set specified")
120120
}
121121
}
122122

@@ -174,6 +174,9 @@ func main() {
174174
case *bb_autoscaler.NodeGroupConfiguration_KubernetesDeployment:
175175
minSize = kind.KubernetesDeployment.MinimumReplicas
176176
maxSize = kind.KubernetesDeployment.MaximumReplicas
177+
case *bb_autoscaler.NodeGroupConfiguration_KubernetesStatefulSet:
178+
minSize = kind.KubernetesStatefulSet.MinimumReplicas
179+
maxSize = kind.KubernetesStatefulSet.MaximumReplicas
177180
default:
178181
panic("Incomplete switch on node group kind")
179182
}
@@ -250,6 +253,38 @@ func main() {
250253
}); err != nil {
251254
return util.StatusWrapf(err, "Failed to change number of replicas of Kubernetes deployment %#v in namespace %#v", name, namespace)
252255
}
256+
case *bb_autoscaler.NodeGroupConfiguration_KubernetesStatefulSet:
257+
namespace := kind.KubernetesStatefulSet.Namespace
258+
name := kind.KubernetesStatefulSet.Name
259+
metaKind := "StatefulSet"
260+
metaAPIVersion := "apps/v1"
261+
if _, err := kubernetesClientset.
262+
AppsV1().
263+
StatefulSets(namespace).
264+
Apply(
265+
ctx,
266+
&appsv1_apply.StatefulSetApplyConfiguration{
267+
TypeMetaApplyConfiguration: metav1_apply.TypeMetaApplyConfiguration{
268+
Kind: &metaKind,
269+
APIVersion: &metaAPIVersion,
270+
},
271+
ObjectMetaApplyConfiguration: &metav1_apply.ObjectMetaApplyConfiguration{
272+
Name: &name,
273+
Namespace: &namespace,
274+
Annotations: map[string]string{
275+
"kubernetes.io/change-cause": "replicas updated by bb_autoscaler",
276+
},
277+
},
278+
Spec: &appsv1_apply.StatefulSetSpecApplyConfiguration{
279+
Replicas: &newDesiredCapacity,
280+
},
281+
},
282+
metav1.ApplyOptions{
283+
FieldManager: "bb_autoscaler",
284+
Force: true,
285+
}); err != nil {
286+
return util.StatusWrapf(err, "Failed to change number of replicas of Kubernetes stateful set %#v in namespace %#v", name, namespace)
287+
}
253288
default:
254289
panic("Incomplete switch on node group kind")
255290
}
@@ -261,3 +296,16 @@ func main() {
261296
return nil
262297
})
263298
}
299+
300+
func createKubernetesClient() (*kubernetes.Clientset, error) {
301+
config, err := rest.InClusterConfig()
302+
if err != nil {
303+
return nil, util.StatusWrap(err, "Failed to create Kubernetes client configuration")
304+
}
305+
kubernetesClientset, err := kubernetes.NewForConfig(config)
306+
if err != nil {
307+
return nil, util.StatusWrap(err, "Failed to create Kubernetes client")
308+
}
309+
310+
return kubernetesClientset, nil
311+
}

pkg/proto/configuration/bb_autoscaler/bb_autoscaler.pb.go

+61-36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/proto/configuration/bb_autoscaler/bb_autoscaler.proto

+5-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ message EKSManagedNodeGroupConfiguration {
5959
string node_group_name = 2;
6060
}
6161

62-
message KubernetesDeploymentConfiguration {
62+
message KubernetesReplicaSetConfiguration {
6363
// Namespace containing the deployment whose replicas count should be
6464
// adjusted.
6565
string namespace = 1;
@@ -101,7 +101,10 @@ message NodeGroupConfiguration {
101101
EKSManagedNodeGroupConfiguration eks_managed_node_group = 5;
102102

103103
// Kubernetes deployment whose replicas count should be adjusted.
104-
KubernetesDeploymentConfiguration kubernetes_deployment = 7;
104+
KubernetesReplicaSetConfiguration kubernetes_deployment = 7;
105+
106+
// Kubernetes stateful set whose replicas count should be adjusted.
107+
KubernetesReplicaSetConfiguration kubernetes_stateful_set = 9;
105108
}
106109

107110
// The number of workers that constitute to a single unit of capacity.

0 commit comments

Comments
 (0)