Sign inSign up

henrystern/fj-bellows

By henrystern

โ€ขUpdated 4 months ago

Ephemeral Forgejo Actions runner autoscaler for cloud VMs. Only pay for the hours you actually use.

Image
0

6.2K

henrystern/fj-bellows repository overview

โ fj-bellows

On-demand, ephemeral Forgejo Actionsโ  runners on cloud VMs โ€” warm only for the billing hour you've already paid for.

Like a bellows stoking a forge: fj-bellows breathes compute into your CI when there's work, and lets it die down when there isn't. It watches your Forgejo job queue, spins up a cloud VM on demand, runs ephemeral one-job runners on it, keeps the VM warm for the rest of the hour you've already been billed for, and tears it down at the :55 mark if it's idle โ€” so you never pay for an idle hour, and jobs after the first start instantly.

โ How it works

  1. Polls the Forgejo Actions job queue for waiting jobs.
  2. When work is queued and the pool is under capacity, provisions a cloud VM (cloud-init bootstrap).
  3. Runs a fresh ephemeral runner per job (register {ephemeral:true} โ†’ one-job) โ€” credentials are invalidated by Forgejo after each job.
  4. Keeps the VM warm to absorb more jobs in the hour you've already paid for; busy jobs roll into the next hour.
  5. Idle-kills at the billing-hour boundary (or a short idle timeout on per-second clouds).
  6. A reconcile/orphan sweep destroys any leaked or unknown instance, so a crash never leaves a VM billing.

โ Features

  • ๐Ÿ’ธ Billing-aware teardown โ€” fills the hour you've paid for on hourly-rounded clouds; plain idle timeout on per-second clouds. The policy adapts to each provider.
  • ๐Ÿ”ฅ Ephemeral per-job runners โ€” fresh credentials per job, auto-invalidated.
  • ๐Ÿ”Œ Pluggable cloud providers โ€” Linode today; AWS / GCP / Azure / others via a small in-tree interface and an opaque YAML config block.
  • ๐Ÿ“ˆ Scale-to-N with a configurable max (start at 1).
  • ๐Ÿงน Orphan sweep โ€” tagged instances, reconciled every tick; no leaked VMs.
  • ๐Ÿชถ Single static binary, no Kubernetes required.
docker run -d --name fj-bellows \
  -v /etc/fj-bellows/config.yaml:/etc/fj-bellows/config.yaml:ro \
  -v /etc/fj-bellows/id_ed25519:/etc/fj-bellows/id_ed25519:ro \ 
  henrystern/fj-bellows:latest
# config.yaml  (holds secrets inline โ€” keep it chmod 600)
forgejo:
  url: https://git.example.com
  token: <forgejo-admin-token>   # admin token; mints runner registrations
  scope: orgs/example            # or repos/owner/name
  labels: [ubuntu-latest]        
scale:
  max: 1
provider: linode
provider_config:                 # opaque to the core; decoded by the linode provider
  region: us-ord                 
  type: g6-nanode-1
  image: linode/debian12
  token: <linode-api-token>
ssh:
  private_key_file: /etc/fj-bellows/id_ed25519   # public half injected into each worker

โ Requirements

  • Forgejo โ‰ฅ v15.0 (ephemeral runner registration) and forgejo-runner > 12.5 (one-job).
  • A Forgejo admin token and credentials for your cloud provider.

Status: early โ€” interfaces may change. Issues and provider contributions welcome.

Tag summary

Content type

Image

Digest

sha256:8dd9ae2e9โ€ฆ

Size

8.3 MB

Last updated

4 months ago

docker pull henrystern/fj-bellows