Conditional image usage in dockerfile and docker-compose

65 Views Asked by At

I saw this question, but it does not help my case.

I have several docker-compose.yml files and Dockerfiles which I use to build several images with dependencies between them. However, they mostly have passages like:

(on compose)

image: my_registry/image_name:${TAG:-latest}

Or:

(on dockerfile)

FROM my_registry/image_name:latest

This is inconvenient for testing purposes, as my_registry only has production images (tags don't help). People often get caught testing stuff in production because of this.

I'd like if possible, to have a flag, setting or whatever such that when I'm in development environment I could set:

(on compose)

image: image_name:local

Or:

(on dockerfile)

FROM image_name:local

And ensure I'm using locally built images with local code instead of production images with code in production branch. Basically, any workaround is valid as long as I'm not maintaining separate files.

1

There are 1 best solutions below

0
David Maze On

For the cases where Compose references an image: but you want to use a locally-built version, this is a case where using multiple Compose files can help. A typical setup here is that the docker-compose.yml file has the "production" setup

# docker-compose.yml
version: '3.8'
services:
  something:
    image: my_registry/image_name:${TAG:-latest}

But then in the same directory you put a docker-compose.override.yml. This is checked into source control, but not used as part of the production deploys. That defines options you'd only use locally; the options are merged with what's in the base Compose file.

# docker-compose.override.yml
version: '3.8'
services:
  something:
    build: .

This will build an image locally; since the combined container definition also has an image: line, it will name the built image my_registry/image_name:latest (or another value as specified by $TAG). It won't necessarily push the image to the remote repository, unless you explicitly docker-compose push it.

The related point is that you can name an image as though it existed in the remote repository, even if it doesn't actually exist there.

docker build -t my_registry/image_name:nonexistent-tag .
docker tag anything my_registry/nonexistent-image

When a Dockerfile has a FROM line (or any other time you run or use an image), if an image with the right name is used locally, it's used as-is; Docker doesn't contact a registry unless you explicitly ask it to.

The only real problem with this workflow is that Compose doesn't have a way to declare a "service" that only builds an image but doesn't run anything, or to have one build dependent on another build. You might have to manually build your base image (not necessarily pushing it) before you build your other local images.

docker build -t my_registry/base_image ./base-image
docker-compose build
docker-compose up -d

The other key assumption here is that the images themselves are the same across all environments. If you need details like host names, pass them using a mechanism like environment variables; don't build them into the images.