Side reading
Pinning images, and reading a release note
Tags against digests, and how to tell an upgrade that migrates your database irreversibly from one that does not.
Tags move, digests do not #
A tag is a label the publisher can point anywhere. :v3 today and :v3 next month may be different software. :latest certainly is.
A digest is a hash of the image content. @sha256:bcf633... is one specific image for ever.
$ sudo docker image inspect ghcr.io/immich-app/immich-server:v3 --format '{{index .RepoDigests 0}}'
Pin both, so the file stays readable and the behaviour stays fixed:
image: ghcr.io/immich-app/immich-server:v3@sha256:<the digest you looked up>
The tag is documentation for humans. The digest is what Docker uses.
Why bother #
Reproducibility. The same file produces the same system next month, and on a rebuilt machine.
Deliberate upgrades. Changing software becomes a commit you wrote, with a date and a message, rather than something that happened because you ran pull.
Supply chain. A publisher whose account is compromised can move a tag. They cannot change what a digest refers to.
Pinning without reviewing is worse than not pinning
A pinned digest never gets security fixes. If you pin and then never look again, you are running old software on purpose.
Pinning only makes sense with a habit attached: a calendar entry, monthly, to review and bump. If you know you will not do that, tracking a minor version tag is the more honest choice.
Reading a release note #
Before bumping anything, read from your current version to the target. The questions worth asking, in order:
Does it migrate the database? The most important one. Look for "migration", "schema", "will be upgraded automatically". Then the follow-up: is it reversible? Usually not. Once the schema is upgraded, the old version cannot read it, and rolling back means restoring from backup.
Is it a major version? Semantic versioning is a convention, not a promise, but a major bump is a signal to read more carefully.
Are there breaking configuration changes? Renamed environment variables, removed options, a changed default. These usually appear as a container that starts and then exits.
Does it need a specific upgrade path? Some projects require passing through an intermediate version. Skipping it produces a broken database.
What is the security content? A fix for something you are exposed to moves the upgrade up your list.
The upgrade procedure #
# 1. back up first, and know you can restore
$ sudo /usr/local/sbin/homeserver-backup
$ sudo /usr/local/sbin/homeserver-restic snapshots
# 2. write down what you are on
$ sudo docker compose images
# 3. change the digest in the file, commit the change
# 4. pull and recreate
$ sudo docker compose pull
$ sudo docker compose up -d
# 5. watch it come up
$ sudo docker compose logs -f
Step 1 is not optional for anything that touches a database. Step 3 being a commit is what gives you the record of when a change happened, which is the first question you will ask when something is odd a week later.
Do one application at a time. Two at once means two suspects.
Rolling back #
Change the digest back and up -d, if nothing migrated. That is the whole reason for asking the first question.
If the schema moved, rolling back means restoring the database from the backup you took in step 1, and losing anything written since. This is why the backup comes first, and why trying an upgrade to see what happens is expensive for a database.
Automating the boring part #
Tools like Renovate or Diun watch for new versions. Configure them to propose a change: a pull request, or a notification.
This book uses those tools to propose changes, not deploy them. The review, tested backup and deliberate Compose run remain separate steps.