Problem
When a container's image was pulled by digest (e.g. via image@sha256:... in a compose file), Docker does not assign any RepoTags to the image. This means container.image.tags returns an empty list, and get_container_names() yields no names to match against BACKUP_PROVIDERS.
This affects Immich in particular, whose compose file pins the postgres image by digest:
ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
Result: RepoTags is [], so the immich-app/postgres pattern never matches, and the database is silently skipped.
Reproduction
- Run Immich (or any compose stack that pins images by digest)
- Run db-auto-backup
- Observe the Immich postgres container is not backed up despite
immich-app/postgres being in the patterns list
$ docker inspect immich_postgres --format '{{.Image}}' | xargs docker image inspect --format '{{json .RepoTags}}'
[]
Suggested fix
Fall back to parsing container.attrs['Config']['Image'] when container.image.tags is empty. This field contains the original image reference from the compose file (e.g. ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:...), which can be parsed the same way as a tag.
Something like:
def get_container_names(container: Container) -> Iterable[str]:
names = set()
tags = container.image.tags
# Fallback: if image was pulled by digest, there are no tags.
# Use the Config.Image field instead, which has the original reference.
if not tags:
config_image = container.attrs.get("Config", {}).get("Image", "")
if config_image:
# Strip digest
config_image = config_image.split("@")[0]
tags = [config_image]
for tag in tags:
registry, image = docker.auth.resolve_repository_name(tag)
if registry == docker.auth.INDEX_NAME:
image = image.removeprefix("library/")
image, _ = image.split(":", 1)
names.add(image)
return names
Problem
When a container's image was pulled by digest (e.g. via
image@sha256:...in a compose file), Docker does not assign anyRepoTagsto the image. This meanscontainer.image.tagsreturns an empty list, andget_container_names()yields no names to match againstBACKUP_PROVIDERS.This affects Immich in particular, whose compose file pins the postgres image by digest:
Result:
RepoTagsis[], so theimmich-app/postgrespattern never matches, and the database is silently skipped.Reproduction
immich-app/postgresbeing in the patterns listSuggested fix
Fall back to parsing
container.attrs['Config']['Image']whencontainer.image.tagsis empty. This field contains the original image reference from the compose file (e.g.ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:...), which can be parsed the same way as a tag.Something like: