While developing application and using docker-compose one question quickly arise:

How to properly rebuild application?

Once an image is built new one will not be built with the same tag as long it exists in a local cache. The compose builds an image it names it with the pattern <context>_<service_name>:latest.

Where:

  • Context is directory name where compose YAML is
  • Service is service name in compose YAML file

This means that you can stop or takedown the compose application, next time you run it your images will not be rebuilt if they already exist. Anyway, we aim to rebuild/restart only parts of the system that are changed. Once the compose application is running, we only rebuild the service we are working on.

Let’s look at compose application we used previously in previous post about docker-compose

version: "3.9"

services:
  app:
    container_name: echo
    build: .
    ports:
      - 9999:9999
    volumes:
      - ./configs:/app/configs
    depends_on:
      - liquibase_pg
    restart: always

  liquibase_pg:
    container_name: pg_updater
    image: liquibase/liquibase:4.7.0
    volumes:
      - ./liquibase:/liquibase/changelog
    command: liquibase --url="jdbc:postgresql://pg:5432/docker" --changeLogFile=./changelog/changelog.xml --username=root --password=password update
    depends_on:
      - pg

  pg:
    container_name: pg
    image: postgres:13.1
    healthcheck:
      test: pg_isready -q -d $$POSTGRES_DB -U $$POSTGRES_USER
      timeout: 45s
      interval: 10s
      retries: 10
    restart: always
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: password
      POSTGRES_DB: docker
    volumes:
      - ./db:/docker-entrypoint-initdb.d/
    ports:
      - 5432:5432

In the above example the compose builds three images:

  • dc-playgroud_app
  • liquibase/liquibase
  • postgres

Only the first time the compose application is started those images will be built. The service app is one I’m working on and if I change code I would like the image to be rebuilt and service restarted. As well it would be nice not to restart its dependencies.

In short, I expect only the service app to be rebuilt and restarted when I change the code. This is a two-step process:

  1. rebuild image: docker-compose build --no-cache app
  2. rebuild container: docker-compose up --build --force-recreate --no-deps -d app

When rebuilding an image: do not cache(–no-cache) layers. Then start it up, but first build(–build) container and then recreate it(–force-recreate) if it exists. As well do not restart dependencies(–no-deps).

Instead of running two commands add a Makefile like this:

.PHONY: restart

restart:
    docker-compose build --no-cache $(APP) $(APP)
    docker-compose up --build --force-recreate --no-deps -d $(APP)

Then from CLI you can run: make restart APP=app