mrframe/swarm-hpa

By mrframe

Updated 8 days ago

Horizontal autoscaling and stuck-task healing for Docker Swarm

Image
Integration & delivery
Developer tools
Monitoring & observability
0

5.1K

mrframe/swarm-hpa repository overview

Swarm HPA & Task Healer

Horizontal autoscaling and stuck-task healing for Docker Swarm — opt-in, dry-run by default, fully logged.

Docker Pulls Docker Image Version Image Size License

A small Go daemon that adds two things Swarm lacks out of the box:

  1. Horizontal autoscaling (HPA) — scales opt-in services between min/max replicas by a target metric (a Kubernetes HPA analogue for Swarm).
  2. Stuck-task healing — recovers tasks stuck in pending under a placement constraint after a node recovers (moby/moby#42215), which otherwise needs a manual docker service update --force.

It manages real production services, so every mutating action is opt-in (via labels), gated by dry-run + cooldown, and emits a structured log + Prometheus metric.

Features

  • Pluggable metrics, chosen per service: Docker stats (CPU/memory, no deps) or Prometheus (arbitrary PromQL — RPS, p95 latency, queue depth).
  • Anti-flapping — direction-aware scale-up/down cooldowns, step limits, and a scale-down stabilization window (mirrors K8s HPA).
  • Opt-in boundary — a service is touched only when it carries swarm.autoscaler.* labels.
  • Dry-run by default — out of the box it only logs intended actions.
  • Self-observability — exposes its own /metrics endpoint (:9095).
  • Hardened image — multi-stage, CGO-free static build, runs as non-root (uid 65532).

Architectures: linux/amd64, linux/arm64 (multi-arch manifest).

Also published on GHCR: ghcr.io/aleksey512/swarm-hpa.

Quick start

The daemon must run on a Swarm manager node (the services/tasks/nodes APIs are manager-only). It stays in dry-run until you explicitly enable mutations.

# Check the build
docker run --rm mrframe/swarm-hpa:0.1.0 --version

# Run on a manager (dry-run: logs decisions, mutates nothing)
docker service create \
  --name swarm-hpa \
  --constraint 'node.role==manager' \
  --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  mrframe/swarm-hpa:0.1.0

Opt a service in, then enable real scaling with DRY_RUN=false:

docker service update \
  --label-add swarm.autoscaler.enabled=true \
  --label-add swarm.autoscaler.min=2 \
  --label-add swarm.autoscaler.max=10 \
  --label-add swarm.autoscaler.metric=cpu \
  --label-add swarm.autoscaler.target=70 \
  web

For a hardened, non-root setup with no socket mount (via docker-socket-proxy), use the deploy/stack.proxy.yml stack from the repo.

Configuration (common)

Precedence: flag > environment > default. Full reference in the docs.

EnvDefaultDescription
DRY_RUNtrueLog intended mutations without applying them. Safety default.
POLL_INTERVAL15sReconcile loop interval.
METRICS_PROVIDERdockerstatsGlobal metric source: dockerstats | prometheus.
PROMETHEUS_URL(empty)Required for any Prometheus-backed metric.
LOG_LEVELinfodebug | info | warn | error.
METRICS_ADDR:9095Listen address for the daemon's own /metrics.

Per-service policy is set with swarm.autoscaler.* labels (enabled, min, max, metric, target, optional source, query).

Documentation

License

MIT

Tag summary

Content type

Image

Digest

sha256:e8b156b6d

Size

21.1 MB

Last updated

8 days ago

docker pull mrframe/swarm-hpa