You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: reintroduce DigitalOcean API metrics support for load balancer scaling (#2)
* feat: Implement DigitalOcean metrics client and MuxMetrics for routing metric requests
* docs: Enhance README to clarify support for both DigitalOcean API and Prometheus metrics, including updated examples and configuration options.
* feat: Add DigitalOcean Load Balancer configuration examples for HTTP and Network services
* feat: Add DO_API_TOKEN to deployment configuration
* docs: Update README with detailed instructions for creating a DigitalOcean API token, Kubernetes secret, and verifying controller functionality
* Update do_client.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
A lightweight Kubernetes controller that automatically scales a DigitalOcean Load Balancer node size (size unit) based on Prometheus metrics from your ingress controller.
5
+
A lightweight Kubernetes controller that automatically scales a DigitalOcean Load Balancer node size (size unit) based on metrics from either the DigitalOcean API or Prometheus.
6
6
7
7
## How it works
8
8
9
9
- Watches `Service` objects of type `LoadBalancer` that include required annotations.
10
-
- Periodically fetches the configured Prometheus query.
11
-
-`nginx_ingress_controller_requests` used as an example.
12
-
- Uses HTTP-style ingress metrics (e.g., total requests per second) to compute desired nodes.
10
+
- Periodically fetches metrics from either:
11
+
-**DigitalOcean API**: Direct load balancer metrics (e.g., throughput, requests)
12
+
-**Prometheus**: Custom queries for ingress/application metrics
13
+
- Uses the configured metric to compute desired nodes.
13
14
- Computes the desired `size_unit` with hysteresis and min/max bounds and writes it back to the Service annotation.
14
15
15
16
DigitalOcean Cloud Controller Manager applies annotation changes to the actual Load Balancer.
@@ -18,27 +19,46 @@ DigitalOcean Cloud Controller Manager applies annotation changes to the actual L
18
19
19
20
- Install from the DigitalOcean Kubernetes Marketplace:
-[Kubernetes Monitoring Stack](https://marketplace.digitalocean.com/apps/kubernetes-monitoring-stack) (kube-prometheus-stack) - *optional, only needed for Prometheus metrics*
22
23
-[Nginx Ingress Controller](https://marketplace.digitalocean.com/apps/nginx-ingress-controller) (optional, any ingress controller should work)
23
24
24
25
## Deploy
25
26
27
+
- Create a DigitalOcean API token with least privileges:
28
+
- Create a token with Custom Scopes following the official guide: [`Create a personal access token`](https://docs.digitalocean.com/reference/api/create-personal-access-token/)
29
+
- Grant only these scopes:
30
+
-`monitoring:read`
31
+
- Create a Kubernetes secret with your DigitalOcean API token:
Set the Prometheus URL via the `--prom-url` flag or `PROMETHEUS_URL` env var. The provided deployment sets `PROMETHEUS_URL` to `http://ingress-nginx-controller-metrics:9090` by default; adjust to your cluster.
44
+
### Configuration Options
45
+
46
+
The controller supports two metrics sources:
47
+
48
+
1.**DigitalOcean API** (default): Set `DO_API_TOKEN` environment variable or `--do-token` flag
49
+
2.**Prometheus**: Set `PROMETHEUS_URL` environment variable or `--prom-url` flag
50
+
51
+
You can configure both sources simultaneously - the controller will route requests based on the metric prefix.
34
52
35
53
## Required annotations
36
54
37
55
-`kubernetes.digitalocean.com/load-balancer-id`: the DO LB ID.
38
-
-`doks-lb-scale/metric`: the metric to use. Must be a Prometheus query prefixed with `promql:`.
39
-
-`doks-lb-scale/target-per-node`: REQUIRED: `req=<int>` (requests per second per node target)
40
-
41
-
Only HTTP/ingress metrics are supported.
56
+
-`doks-lb-scale/metric`: the metric to use:
57
+
-**DO API metrics**: Direct metric names (e.g., `nlb_tcp_network_throughput`, `requests_per_second`)
58
+
-**Prometheus metrics**: Must be prefixed with `promql:` (e.g., `promql:sum(rate(nginx_ingress_controller_requests[1m]))`)
59
+
-`doks-lb-scale/target-per-node`: REQUIRED:
60
+
-`req=<int>` for request-based metrics (HTTP requests, ingress metrics)
-`doks-lb-scale/scale-down-delay-minutes`: optional. If set to a positive integer, delays any scale-down by the specified number of minutes. The controller first sets a not-before timestamp and only applies the scale-down once that time has passed. Scaling up clears any pending delay.
48
68
-`service.beta.kubernetes.io/do-loadbalancer-size-unit`: set by controller.
doks-lb-scale/target-per-node: "req=8000"# requests per second per node
135
+
doks-lb-scale/hysteresis-percent: "20"
136
+
doks-lb-scale/min-nodes: "1"
137
+
doks-lb-scale/max-nodes: "50"
138
+
spec:
139
+
type: LoadBalancer
140
+
selector:
141
+
app: nginx
142
+
ports:
143
+
- port: 80
144
+
targetPort: 80
145
+
```
146
+
74
147
## Example ingress-nginx Helm values
75
148
76
149
Use the following Helm values to deploy `ingress-nginx` with a `LoadBalancer` Service, metrics enabled for Prometheus scraping, and the required annotations for doks-lb-scale to manage the Load Balancer size:
Pair this with the Prometheus-based example in the previous section (using `promql:sum(rate(nginx_ingress_controller_requests{ingress!="",status!=""}[1m]))`).
The controller automatically detects the metric category and validates that the target configuration matches.
102
190
103
191
## Notes
104
192
105
-
- The controller performs a Prometheus instant query via `/api/v1/query?query=...` and uses the value from the first result.
106
-
- Up to date LB service annotations: [DigitalOcean CCM annotations](https://github.com/digitalocean/digitalocean-cloud-controller-manager/blob/master/docs/controllers/services/annotations.md)
193
+
- **DO API metrics**: The controller performs a direct API call to DigitalOcean's monitoring endpoint.
194
+
- **Prometheus metrics**: The controller performs a Prometheus instant query via `/api/v1/query?query=...` and uses the value from the first result.
195
+
- For up-to-date LB service annotations, see [DigitalOcean CCM annotations](https://github.com/digitalocean/digitalocean-cloud-controller-manager/blob/master/docs/controllers/services/annotations.md).
196
+
- For documented DigitalOcean Load Balancer node limits and scaling details, see the [DigitalOcean Load Balancer pricing and limits documentation](https://docs.digitalocean.com/products/networking/load-balancers/details/pricing/#regional-load-balancers).
107
197
108
198
## Hysteresis examples
109
199
@@ -117,7 +207,125 @@ If desired is within [lower, upper], nothing changes.
117
207
Quick examples:
118
208
- current 10, pct 20% → window [8,12]; desired 12 = no change; 13 = scale up; 7 = scale down
119
209
- current 5, pct 10% → window [4,5]; desired 4 = no change; 6 = scale up; 3 = scale down
120
-
- current 1, pct 20% → window [0,1]; desired 1 = no change; ≥2 = scale up (min-nodes still applies)`
210
+
- current 1, pct 20% → window [0,1]; desired 1 = no change; ≥2 = scale up (min-nodes still applies)
211
+
212
+
## Verifying the Controller is Working
213
+
214
+
To verify that the doks-lb-scale controller is working properly, check the controller logs and monitor the service annotations.
215
+
216
+
### Check Controller Logs
217
+
218
+
View the controller logs to see the reconciliation process:
The controller will show the delay being scheduled and then count down the remaining time until the scale-down can occur. If traffic increases during the delay period, the pending scale-down will be cancelled.
305
+
306
+
### Monitor Service Annotations
307
+
308
+
Check that the controller is updating the service annotation:
309
+
310
+
```bash
311
+
kubectl get service <your-service-name> -o yaml | grep -A 5 -B 5 "do-loadbalancer-size-unit"
312
+
```
313
+
314
+
You should see the `service.beta.kubernetes.io/do-loadbalancer-size-unit` annotation being updated as the controller scales the load balancer.
315
+
316
+
### Troubleshooting
317
+
318
+
If you don't see the expected logs:
319
+
320
+
1. **Check if the controller is running:**
321
+
```bash
322
+
kubectl get pods -n kube-system | grep doks-lb-scale
323
+
```
324
+
325
+
2. **Verify the service has the required annotations:**
326
+
```bash
327
+
kubectl get service <your-service-name> -o yaml | grep -A 10 -B 10 "doks-lb-scale"
0 commit comments