`docker-compose images`

I am using docker-compose in stages. The first stage runs on one machine to docker-compose build the images and then docker-compose push them to an image repository. Another machine runs the second stage: docker-compose down to cleanly bring down the old version of the software, then docker-compose rm to destroy the old containers since they’re not needed any more, followed by docker-compose pull the updated images from the repository and docker-compose up -d to deploy.

The build server is also used by other teams.

The build server recently ran out of disk storage because I had neglected to prune the images afterward. Since the build server is also used by other teams, I needed to ensure that I only removed the images I built, not the images built by other teams.

I couldn’t find an easy way to do that.

So I added some code to do that which would docker-compose images -q to find the specific image hashes then grep for relevant tags from docker images and then remove those tags:

#!/usr/bin/env bash
docker-compose build
docker-compose push
mapfile -t tags_to_remove < <(
	#
	# List all images
	#   then filter to include just the IDs we want
	#   then cut to get the tags
	docker images \
		--no-trunc \
		--format '{{.Repository}}:{{.Tag}}\t{{.ID}}' |
		grep -f <(docker-compose images -q) | cut -f 1
)
docker image rm "${tags_to_remove[@]}"

It works on my machine! Except… it doesn’t work on the build server.

It turns out that tags_to_remove ends up being non-empty on my machine: docker-compose images -q printed a list of image hashes. But on the build machine it’s empty: docker-compose images -q printed nothing. It seems that the only way to get it to print anything is to docker-compose create or docker-compose up --no-start.

That’s not good. Those commands don’t “just” make docker-compose images -q to work. Those commands also go and create containers… which also means trying to create networks and filesystems. All of that is going to further pollute the build system with even more problems to resolve: how do I then enumerate the volumes that need to be deleted? How do I then enumerate the networks to be deleted?

Not only that but one of the volumes is an NFS filesystem and if the volume configuration (eg, remote host) changes then docker-compose will completely stop functioning and instead will complain about a volume that it created and refuses to destroy. Right now the workaround for that on the deploy server is to use Portainer to manage the containers and volumes. But I don’t have such access on the build server.

All of that means that creating the containers and then deleting them is completely backwards to how docker-compose should function. It should absolutely have some functionality to tell me what it has created. I don’t understand why docker-compose images requires services to have been created. docker-compose literally downloads or builds the images when it can. Why can’t that functionality provide a list of images?

There does appear to be docker-compose config which shows a somewhat-resolved configuration. There’s also the --resolve-image-digests flag which would give me what I want, but that also appears to be a shoehorn and includes a lot of irrelevant junk ("ERROR: some images are missing digests" and “use docker-compose push ... to push them” for a script that only wants the image hashes and/or tags. I’m worried using that shoehorn will only cause more problems at a later date.

So I figured I must be doing something radically wrong to have so many issues trying to have a separate build and deploy server. Can someone provide some insight or advice or recommend further reading on the subject? As-is it works but eventually fills up the build server storage.

To be clear, my question is: how do I get a list of images built or tagged by docker-compose without needing to use docker-compose create or docker-compose up?