Sign inSign up

cplieger/docker-renovate-scheduler

By cplieger

Updated about 1 hour ago

Always-on Renovate in a Go scheduler wrapping the official image

Image
Security
Integration & delivery
Developer tools
0

50K+

cplieger/docker-renovate-scheduler repository overview

docker-renovate-scheduler

Run Renovate as a resident, always-on container instead of a one-shot job, driven by a built-in interval scheduler or an external trigger. A tiny Go wrapper around the official renovate/renovate image; structured logs, no metrics, no open ports.

Why this exists

The Renovate CLI is designed to run once and exit; the usual self-hosted patterns schedule it with cron or a Kubernetes CronJob. If your stack schedules every other workload with always-on containers and external triggers (Ofelia, a webhook, a central orchestrator), an ephemeral docker run per cycle is the odd one out. This image keeps Renovate resident and lets you drive it the same way as everything else, while reusing the upstream image's runtime.

It deliberately has no built-in HTTP/webhook server; triggering is delegated to whatever already schedules your containers (docker exec, Ofelia, a webhook-driven action on a release, …).

Not distroless, on purpose

Renovate is a Node.js application that shells out to git and, for lockfile maintenance, to language package managers; its default binarySource=install installs those toolchains at runtime via containerbase. There is no static, dependency-free form to drop on scratch. So this image builds on the official renovate/renovate image (the default image, which Renovate recommends for most users and which installs tools at runtime) and adds only the scheduler binary on top.

One deliberate trim: the bundled docker CLI is removed. Renovate invokes it only under binarySource=docker, which is deprecated upstream and not supported by this image; dropping the unused ~42 MB binary cuts attack surface and the CVE noise image scanners report against it.

What it does

  • Runs renovate on a built-in interval (RUN_INTERVAL=6h): one run at startup when no successful run completed within the interval (the last-run record on /data survives restarts), then every interval. Or set RUN_INTERVAL=off and trigger each run externally (docker exec … run).
  • The daemon owns every run. It executes Renovate as its own child process, whichever trigger asked. The run subcommand is a thin client that submits the request over an in-container unix socket, forwarding its repo arguments and its environment (a docker exec -e RENOVATE_X=… … run override reaches Renovate intact), and exits with that run's true result.
  • One run at a time, every request served. Requests queue in order behind an in-flight run; each gets its own run and its own exit code. See One run at a time.
  • File-marker healthcheck via github.com/cplieger/health: unhealthy when the last run failed, recovers on the next clean run.
  • Streams Renovate's own structured logs straight through to the container's stdout/stderr (set LOG_FORMAT=json) for collection by Alloy/Promtail/Loki, in both scheduling modes. The scheduler neither captures nor parses Renovate's output; it emits only its own lifecycle lines, with UTC timestamps regardless of the container's TZ.

Pull

docker pull cplieger/docker-renovate-scheduler:latest

Also published to ghcr.io/cplieger/docker-renovate-scheduler with identical images and tags. Release versions are tagged vX.Y.Z alongside latest.

Quick start

# Example compose for docker-renovate-scheduler. See the README for all configuration options and hardening.
services:
  renovate:
    image: ghcr.io/cplieger/docker-renovate-scheduler:latest
    container_name: renovate
    restart: unless-stopped
    stop_grace_period: 10m  # let an in-flight run drain on stop instead of exit 137; see README "Graceful shutdown"

    environment:
      RUN_INTERVAL: "6h"  # built-in cadence (Go duration); "off" = external trigger; see README "Scheduling modes"
      LOG_FORMAT: "json"  # Renovate's own knob, not the scheduler's: structured logs for Alloy/Loki; see README "What it does"
      # Renovate's own config (RENOVATE_*) is passed straight through:
      RENOVATE_PLATFORM: "github"
      RENOVATE_AUTODISCOVER: "true"  # or set RENOVATE_REPOSITORIES
      RENOVATE_TOKEN: "${RENOVATE_TOKEN}"
      RENOVATE_GITHUB_COM_TOKEN: "${RENOVATE_GITHUB_COM_TOKEN}"  # changelogs + dodge rate limits
      RENOVATE_PERSIST_REPO_DATA: "true"  # persist /data so runs git fetch, not clone
      RENOVATE_REPOSITORY_CACHE: "enabled"
      RENOVATE_X_SQLITE_PACKAGE_CACHE: "true"  # bounded package cache for an always-on container; see README "Memory and the package cache"

    volumes:
      - "./data:/data"  # persist clones, caches + the last-run record; create ./data owned by UID 12021 first (see README "Volumes")

Documentation

License

Apache-2.0. See LICENSE. The image carries the license text of every bundled component under /usr/share/licenses/.

The runtime base is the official renovate/renovate image, which packages Renovate under AGPL-3.0. The version and digest that base is pinned to are in the Dockerfile's FROM line, and Renovate's license and the corresponding source for that version are in the upstream repository at the matching release tag (https://github.com/renovatebot/renovate/releases/tag/<version>). The build applies no patches to Renovate, so this repository's Dockerfile is the complete record of what it adds to that image (the scheduler binary and a Go toolchain) and what it removes from it (the unused docker CLI and TypeScript compiler binaries).

Tag summary

Content type

Image

Digest

sha256:d97b4bc94

Size

501.9 MB

Last updated

about 1 hour ago

docker pull cplieger/docker-renovate-scheduler