A small rust program that uses the Hetzner and Woodpecker/Drone APIs to enable starting servers to run CI tasks for.
Find a file
ljoonal d5fcfb2649
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Fix spelling of hetzner
2023-01-02 05:40:52 +02:00
src Fix spelling of hetzner 2023-01-02 05:40:52 +02:00
.dockerignore Initial commit 2022-10-17 22:49:03 +03:00
.gitignore Initial commit 2022-10-17 22:49:03 +03:00
.woodpecker.yml Woodpeckerify pipeline config 2022-12-30 15:08:26 +02:00
Cargo.lock 0.3.0 release 2022-12-31 16:39:46 +02:00
Cargo.toml 0.3.0 release 2022-12-31 16:39:46 +02:00
docker-compose.example.yml Fix spelling of hetzner 2023-01-02 05:40:52 +02:00
Dockerfile Better woodpecker compatibility 2022-12-30 14:16:36 +02:00
LICENSE.md Initial commit 2022-10-17 22:49:03 +03:00
README.md Fix spelling of hetzner 2023-01-02 05:40:52 +02:00
rustfmt.toml Initial commit 2022-10-17 22:49:03 +03:00

Hetzner CI autoscaling

A small rust program that uses the Hetzner's API along with Woodpecker / Drone to enable starting servers to run CI tasks for.

Note that scaling down currently only happens when there's no pending or running builds, as determining which runner has builds isn't doable with the current woodpecker / drone API. While some kind of a "nice" shutdown request method could be built for that, it was outside of my initial few hours implementation scope for this.

It's also set up to ramp up conservatively, and request a max 1 server per poll loop. So to summarize, it's made for small instances. If you need to do mass scaling you'd probably be willing pay Harness for their scaling solution anyways.

Or you might want to check out picus for Woodpecker, which I only found after already having implemented this. On a quick glance, I'd say the main differences are that this project is focused on being small & lightweight (at the time of writing, this project's docker image is less than 2MB). This project tries to avoid dependencies, and thusly the whole async rust ecosystem in general due to it usually resulting in larger executables. Whereas picus seems like it's got a bit more abstractions, tests, and options, whilst also using more crates & relying on async code, and thusly it'll probably be easier to adapt to other needs as well.

Usage

Run cargo run for local dev builds. For production usage I personally would recommend building the docker image yourself. See the docker-compose.example.yml file for the configuration env vars.

I do have the container image published to my own container registry, but I wouldn't recommend others to rely on it. Also to note that the latest tag is always updated directly whenever the CI build passes, so don't trust it to ever be stable. Breaking changes can and do happen, though I generally do try to respect Rust's semver. Additionally I don't really feel like writing a changelog file for this weekend project, but you can check the diffs (for example v0.2.0 vs v0.3.0)

Why

Because the official implementation is not Open Source and doesn't work anyways with the latest Drone.IO OSS version. And because I used a private Gitea instance with Drone integration, where CI build jobs are very rare, and nowadays have upgaded it to Woodpecker and Forgejo. I don't personally run CI jobs that often, but when they do happen, they're usually quite bursty (tens of builds in a few hours). So instead of wasting my resources with upgrading my servers to account for the bursty nature... Thanks to Hetzner Cloud's hourly billing I can just pay a few cents for a way more powerful server only for the time I actually use it.

Note to self

Use the standard rust docker container images instead of my own custom one. Since bootstrapping the CI would be even more difficult if both the autoscaler and the CI image generation required each other.