I have multiple services that needs to use the same locally built image.
So I created a helper service which would build the image and all other services would depend on the builder service to ensure that image is built first.
Here’s docker-compose.yml with only 2 services but in actual, I have around 20 services.
version: "3.5"
services:
api:
image: test-image # using the image built below
networks:
- mylab
depends_on:
- tests-container-builder
volumes:
- ./tests:/tests
command: pytest -v -p no:cacheprovider /tests/api.py
license-chrome:
image: test-image
networks:
- mylab
depends_on:
- tests-container-builder
volumes:
- ./tests:/tests
command: sh -c "/tests/health-check-script.sh && pytest -v -p no:cacheprovider -n=1 /tests/license.py"
tests-container-builder:
build:
context: .
dockerfile: ./tests/Dockerfile
target: test-env
image: test-image # this service builds the image
But when I build and run the container using
docker-compose up --build api;
docker-compose up --scale license-chrome
I’m getting error like
ERROR: for mylab_visual_ner-chrome_1 no such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa: No such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa
ERROR: for visual_ner-chrome no such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa: No such image: sha256:ceff9945d8722c89331696aa33d88f84703e322fbb64c1ebaa8f83c6e19a4cfa
ERROR: The image for the service you're trying to recreate has been removed. If you continue, volume data could be lost. Consider backing up your data before continuing.
Continue with the new image? [yN]
It works fine if I remove the test-container-builder
service and use build
command inside all services.
Is it considered an anti-pattern to use a different service to build image?
What is the proper way to do this ?
2
Answers
I’d consider an absolutely-best-practice Compose setup to only contain long-running containers, and not containers you don’t expect to actually run. In your case the "builder" container doesn’t actually do anything and I wouldn’t include it in the Compose setup. Conversely,
build:
ing a literally identical image from the same source code is all but free; Docker needs to scan the build context to determine that the two images are identical, but in the end you will just get two different names for the same physical image.Taking @TheFool’s suggestion to use YAML anchors to avoid repeating the build setup, I might write:
I’ve omitted unnecessary
networks:
, since Compose creates a perfectly usable network nameddefault
for you, andvolumes:
, since your code should generally be built into the image.If you want to explicitly build the image and include it in the Compose setup (maybe you want to push it to a registry) then you need to manually
docker-compose build
the builder image, not any of the containers you’re going to run. The Compose setup can look likeCompared to my previous Compose setup and your question, I make it explicit that the container should just exit immediately and not restart, and I use a registry-qualified name.
depends_on:
only affects the order in which containers start starting and doesn’t include any dependencies on image builds.If you’re using this setup, you need to
docker-compose build
the builder "container" before you run the rest:This is maybe not a real answer, but I have recreated your scenario, and it surprisingly works. I did expect it to fail if you only want to build the container that hasn’t a build key in the config.
Compose file:
Dockerfile
The output I am getting is the following. It may make sense because when reading the definition of the –build flag,
Build images before starting containers.
, it sounds a bit like it doesn’t care about what service you want to start. It just builds all images.