Skip to content
All posts
how-it-worksscheduling

How freshdock decides when to update a container

A walk through freshdock's update logic: opt-in labels, per-container modes, digest checks, and the health gate that decides if an update sticks or rolls back.

freshdock's job sounds simple ("update my containers"), but the interesting part is everything it does not do automatically. Here's the full decision path, from "should I even look at this container?" to "keep the update or roll it back?"

Step 1: is this container opted in?

freshdock is opt-in. A container with no freshdock.enable=true label is invisible to it: no checks, no notifications, nothing. This is the opposite of Watchtower's update-everything default, and it's deliberate: you decide what freshdock manages, one label at a time.

labels:
  - "freshdock.enable=true"   # now freshdock can see it

Step 2: what mode is it in?

An enabled container picks a mode with freshdock.mode. The mode decides whether freshdock acts and when:

  • watch: detect updates and notify only. Never pulls, never restarts. This is the default for an enabled container with no explicit mode.
  • live: pull and recreate on every new digest, checked every --interval (default 300s).
  • nightly / weekly / monthly: recreate if newer, on a cron schedule (default 04:00).
  • off: ignored entirely.

A single daemon mixes these freely. Your reverse proxy can be on live, your database on watch, your media server on weekly. Calendar modes take an optional freshdock.schedule cron override.

Step 3: is there actually a newer image?

When a container is due, freshdock resolves the latest digest for its image tag against the registry, using a rate-friendly HEAD request, not a full pull, and deduplicated so ten containers on the same image cost one lookup. It compares that digest to what the container is currently running.

If the digest is unchanged, freshdock stops here. If the image is pinned to a digest (repo@sha256:…), there's no moving tag to follow, so it's reported as pinned (no check) and never updated. You can see all of this without changing anything by running:

freshdock check

Step 4: the health gate

This is the part that makes unattended updates safe. For an updating mode with a newer digest, freshdock runs the recreate cycle: inspect the running container, pull the new image, stop the old one, rename it to an archive, create the new container from the exact same config, and start it.

Then it waits. The container reaches one of three verdicts:

  • Healthy: a declared healthcheck reported healthy, or (no healthcheck) the container stayed up for the grace period. The archive is removed; the update stands.
  • Timeout: a healthcheck was declared but never went healthy in time. Roll back.
  • Crashed: the container exited before becoming healthy. Roll back.

On a rollback, freshdock removes the failed container, renames the archive back to the original name, and restarts it. You're left running exactly what you had, plus a failed notification explaining why.

The health timeout (120s), the grace period for containers without a healthcheck (10s), and the poll interval (1s) are currently hardcoded. Declaring a HEALTHCHECK on your image gives the gate a much stronger signal than "did it stay up?".

Why this matters

The whole point is that freshdock will never knowingly leave you with a broken service. An update either passes its own health check and stays, or it's reverted automatically. That's the difference between "set and forget" being a feature and being a liability.

The exact verdict logic and timings are documented in health & rollback; the scheduling model is in scheduling. When you're ready to try it, the install guide gets you to a read-only freshdock check in a minute, and the Watchtower comparison shows how this differs from the tool you're probably replacing.