Scale your woodpecker agents automatically to the moon and back based on the current load.
If you are using docker-compose you can add the following to your docker-compose.yml file:
# docker-compose.yml
version: '3'
services:
woodpecker-server:
image: woodpeckerci/woodpecker-server:next
[...]
woodpecker-autoscaler:
image: woodpeckerci/autoscaler:next
restart: always
depends_on:
- woodpecker-server
environment:
- WOODPECKER_SERVER=https://your-woodpecker-server.tld # the url of your woodpecker server / could also be a public url
- WOODPECKER_TOKEN=${WOODPECKER_TOKEN} # the Personal Access Token you can get from the UI https://your-woodpecker-server.tld/user/cli-and-api
- WOODPECKER_MIN_AGENTS=0
- WOODPECKER_MAX_AGENTS=3
- WOODPECKER_WORKFLOWS_PER_AGENT=2 # the number of workflows each agent can run at the same time
- WOODPECKER_GRPC_ADDR=https://grpc.your-woodpecker-server.tld # the grpc address of your woodpecker server, publicly accessible from the agents
- WOODPECKER_GRPC_SECURE=true
- WOODPECKER_AGENT_ENV= # optional environment variables to pass to the agents
- WOODPECKER_PROVIDER=hetznercloud # set the provider, you can find all the available ones down below
- WOODPECKER_HETZNERCLOUD_API_TOKEN=${WOODPECKER_HETZNERCLOUD_API_TOKEN} # your api token for the Hetzner cloudThe agents will use WOODPECKER_GRPC_ADDR and an agent token automatically created on the server by the autoscaler to connect to the server. Therefore the WOODPECKER_GRPC_ADDR has to be publicly accessible from the newly created agents. Check for example how you could use caddy to expose the grpc connection.
Set WOODPECKER_PROVIDER=digitalocean and configure at least:
WOODPECKER_DIGITALOCEAN_API_TOKEN(orWOODPECKER_DIGITALOCEAN_API_TOKEN_FILE)
DigitalOcean support is currently experimental: it has not been tested by the project maintainers, as none of them have real provider access.
Useful optional settings:
WOODPECKER_DIGITALOCEAN_REGION(default:nyc1)WOODPECKER_DIGITALOCEAN_SIZE(default:s-1vcpu-1gb)WOODPECKER_DIGITALOCEAN_IMAGE(default:ubuntu-24-04-x64, slug or name)WOODPECKER_DIGITALOCEAN_SSH_KEYS(names or fingerprints; if unset, a key namedrandom-autoscaler-keyis created and reused, its private key is discarded)WOODPECKER_DIGITALOCEAN_TAGSWOODPECKER_DIGITALOCEAN_PUBLIC_IPV4_ENABLE(default:true; set tofalseto create private droplets without a public network interface, which requiresWOODPECKER_DIGITALOCEAN_NAT_GATEWAY)WOODPECKER_DIGITALOCEAN_NAT_GATEWAY(name or ID of an existing VPC NAT gateway; the agents are placed in the VPC it serves as default gateway so they can reach the server and pull images)WOODPECKER_DIGITALOCEAN_PUBLIC_IPV6_ENABLE(default:true, requires public IPv4)
Set WOODPECKER_PROVIDER=openstack. The prefix for all the following environment variables is WOODPECKER_OPENSTACK_.
You have to supply the AUTH_URL pointing to your Keystone. If necessary, you can also specifiy the DOMAIN_NAME, REGION and PROJECT_NAME.
Both USERNAME/PASSWORD authentication and application credentials via APPLICATION_CREDENTIAL_ID and APPLICATION_CREDENTIAL_SECRET are supported.
Credentials can also be read from files, to do so append _FILE to the appropriate variable name and set it to the file path.
You can select the flavor and image for the agent instances via FLAVOR/IMAGE_NAME or UUID reference (FLAVOR/IMAGE_REF).
The agent platform is taken from the image's hw_architecture (or architecture) property. Without it the platform is unknown, and workflows that set a platform label do not trigger scaling.
If you set VOLUME_SIZE, block storage volumes are used.
You can add your OpenStack SSH keypair via KEYPAIR.
Hetzner Cloud (WOODPECKER_HETZNERCLOUD_SERVER_TYPE), AWS (WOODPECKER_AWS_INSTANCE_TYPE), Scaleway (WOODPECKER_SCALEWAY_SERVER_TYPES) and Oracle Cloud (WOODPECKER_ORACLE_SHAPES) take an ordered list of server types. If a type is out of capacity, the next type of the same architecture is tried; any other error fails the deploy.
Limits:
- There is no fallback across architectures: x86 and arm types are separate pools, each with its own fallback order.
- Workflows without a
platformlabel are deployed on the architecture of the first listed type. - Workflows that ask for a platform none of the types provides do not trigger scaling.
Set WOODPECKER_PROVIDER=oracle and configure at least:
WOODPECKER_ORACLE_COMPARTMENT_OCIDWOODPECKER_ORACLE_SUBNET_OCID- credentials, either an API signing key (
WOODPECKER_ORACLE_TENANCY_OCID,WOODPECKER_ORACLE_USER_OCID,WOODPECKER_ORACLE_REGION,WOODPECKER_ORACLE_FINGERPRINT,WOODPECKER_ORACLE_PRIVATE_KEY) orWOODPECKER_ORACLE_USE_INSTANCE_PRINCIPAL=truewhen the autoscaler itself runs on an Oracle Cloud instance
Oracle Cloud support is currently experimental: it has not been tested by the project maintainers, as none of them have real provider access.
Useful optional settings:
WOODPECKER_ORACLE_AVAILABILITY_DOMAINS(default: every availability domain of the compartment; the agents are launched in the first one that has capacity, in the given order)WOODPECKER_ORACLE_SHAPES(default:VM.Standard.E4.Flex; ordered list, shapes with an Ampere or NVIDIA Grace processor such asVM.Standard.A1.Flexare arm64 and every other shape is amd64; each shape is looked up at startup, so a name that does not exist in the compartment fails immediately)WOODPECKER_ORACLE_OCPUS(default:1, only sent for flexible shapes)WOODPECKER_ORACLE_MEMORY_IN_GBS(default:8, only sent for flexible shapes)WOODPECKER_ORACLE_IMAGE_OCID(default: the most recent image matching the operating system settings below, looked up per shape; an explicit image must boot on every configured shape)WOODPECKER_ORACLE_IMAGE_OPERATING_SYSTEM(default:Canonical Ubuntu)WOODPECKER_ORACLE_IMAGE_OPERATING_SYSTEM_VERSION(default:24.04)WOODPECKER_ORACLE_BOOT_VOLUME_SIZE(default:50, Oracle Cloud rejects smaller boot volumes)WOODPECKER_ORACLE_ASSIGN_PUBLIC_IP(default:true; set tofalsefor a private subnet that reaches the server through a NAT gateway)WOODPECKER_ORACLE_SSH_KEYWOODPECKER_ORACLE_TAGS(comma separatedkey=valuefreeform tags; Oracle Cloud allows 10 per instance and the autoscaler already uses one of them to mark its pool)
Capacity is the common failure mode on Oracle Cloud, in particular for the free VM.Standard.A1.Flex shape. If a launch fails with an out-of-capacity error the next availability domain is tried, then the next shape of the same architecture, so listing more than one is worthwhile.
The subnet is checked at startup: a subnet bound to one availability domain limits the agents to that domain, and a private subnet requires WOODPECKER_ORACLE_ASSIGN_PUBLIC_IP=false.
The agents block the instance metadata service (169.254.169.254, and fd00:c1::a9fe:a9fe over IPv6) before the workflow steps start, so a step cannot read the agent token back out of user_data. Oracle Cloud also serves DNS (port 53) and NTP (UDP port 123) on that address, so instead of a blackhole route DNS and NTP are let through and every other packet to that address is dropped, which blocks the metadata API on port 80.
Only virtual machine shapes are billed per second with a one-minute minimum; bare metal shapes carry a one-hour minimum, which the per-second teardown policy below does not account for.
How idle agents are torn down depends on how the selected provider bills:
-
Per-second billing (e.g. AWS, Scaleway): an idle agent is drained and removed once it has been idle for
WOODPECKER_AGENT_IDLE_TIMEOUT. Holding an idle agent open buys nothing. -
Hourly-rounded-up billing (e.g. Linode, Hetzner Cloud, Vultr): a partial hour costs the same as a full one, so an idle agent is kept schedulable for the rest of the hour that has already been paid for and is only torn down just before its next hour boundary (anchored at its creation time). A busy agent simply rolls into the next paid hour; you never pay for an idle hour.
The teardown window is
WOODPECKER_AGENT_BILLING_TEARDOWN_MARGIN(default2m) plusWOODPECKER_RECONCILIATION_INTERVAL, so a reconciliation can never tick straight past the boundary. With the defaults (2mmargin,1minterval) an idle agent becomes eligible for teardown in the last 3 minutes of each paid hour.
The billing model is selected automatically by the provider, so no extra configuration is required to benefit from this.
- Add support for multiple providers
- Cleanup agents
- Remove agents which exist on the provider but are not in the server list (they wont be able to connect to the server anyway as their is no agent token for them)
- Remove agents from server list which do not exist on the provider
- Remove agents which have not connected for a long time
- Release as container image
- Add docs
- Support agent deployment with specific attributes (e.g. platforms, architectures, etc.)