How to prevent docker-compose building the same image multiple times?

My docker-compose.yml specifies multiple images. Two of these images are built using the same local Dockerfile. They share the same image name but each has a different command.

During development, I frequently use docker-compose up --build to rebuild the images. The trouble is that docker builds the same myimage twice - taking longer than necessary.

Is there a way to express that the image only needs to be built once?

version: '2'
services:

  abc:
    image: myimage
    command: abc
    build:
      context: .
      dockerfile: Dockerfile

  xyz:
    image: myimage
    command: xyz
    build:
      context: .
      dockerfile: Dockerfile

Per the docker-compose file documentation for build, specify build: and image: for the first service, and then only image: for subsequent services.

Here's a modified version of your example that only builds the image once (for abc service) and reuses that image for xyz service.

version: '2'
services:

  abc:
    image: myimage
    command: abc
    build:
      context: .
      dockerfile: Dockerfile

  xyz:
    image: myimage
    command: xyz

You can fake a build only service to build the image, and then use dependencies to that for the actual workers. That has the advantage that you don't have one of those services automatically start if you wanna start the others.

you need to add an image name to specify build: and image: for the build service, as well as make sure it terminates and never restarts automatically. Then image: and depends_on: first_service for your services.

like so:

version: '2'
services:
  _myimage_build:
    image: myimage
    command: ['echo', 'build completed']  # any linux command which directly terminates.
    build:
      context: .
      dockerfile: Dockerfile

  first_service:
    image: myimage
    depends_on:
    - _myimage_build
    command: abc
    
  second_service:
    image: myimage
    depends_on:
    - _myimage_build
    command: xyz

thanks to @amath for their answer.


To make @amath good answer a bit clearer

you need to add an image name to specify build: and image: for the first service, and then image: and depends_on: first_service for subsequent services.

like so:

version: '2'
services:

  first_service:
    image: myimage
    command: abc
    build:
      context: .
      dockerfile: Dockerfile

  second_service:
    image: myimage
    command: xyz
    depends_on:
    - first_service

thanks to @DrSensor for the comment