compose: docker-compose ups a bad build target with multiple compose files

Description of the issue

A bad build target in used on containers up when working with multiple compose files.

Seems like the image check doesn’t consider the build.target value.

Context information (for bug reports)

Output of docker-compose version

docker-compose version 1.25.4, build 8d51620a
docker-py version: 4.1.0
CPython version: 3.7.5
OpenSSL version: OpenSSL 1.1.1d  10 Sep 2019

Output of docker version

Client: Docker Engine - Community
 Version:           19.03.5
 API version:       1.40
 Go version:        go1.12.12
 Git commit:        633a0ea
 Built:             Wed Nov 13 07:22:34 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.5
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.12
  Git commit:       633a0ea
  Built:            Wed Nov 13 07:29:19 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Steps to reproduce the issue

  1. Use Dockerfile:
FROM node:13 AS builder

FROM builder AS development

CMD ["echo", "DEVELOPMENT"]

FROM builder AS ci

CMD ["echo", "CI"]
  1. Create 3 different docker compose files:

docker-compose.yml:

version: '3.4'
services:
  api:
    build:
      context: .
      target: development

docker-compose-ci.yml:

version: '3.4'
services:
  api:
    build:
      context: .
      target: ci

docker-compose-local.yml:

version: '3.4'
services:
  api:
    build:
      context: .
      target: development
  1. Run docker-compose -f docker-compose.yml -f docker-compose-ci.yml up.

  2. Then run docker-compose -f docker-compose.yml -f docker-compose-local.yml up.

Observed result

On the 1st run, it will use ci build target and will execute echo CI, which is expected.

On the 2nd run, it should use development build target, but it still uses the previous ci target build and executes the same ci command, which is NOT expected.

The same bug happens if you will run commands in reverse order.

Expected result

Should run the expected build target based on extended docker file.

Stacktrace / full error message

grigorii-duca:testapp greg$ docker-compose -f docker-compose.yml -f docker-compose-ci.yml up
Creating network "testapp_default" with the default driver
Building api
Step 1/5 : FROM node:13 AS builder
 ---> f7756628c1ee

Step 2/5 : FROM builder AS development
 ---> f7756628c1ee
Step 3/5 : CMD ["echo", "DEVELOPMENT"]
 ---> Running in 960536e7bd45
Removing intermediate container 960536e7bd45
 ---> 2a69c4326cad

Step 4/5 : FROM builder AS ci
 ---> f7756628c1ee
Step 5/5 : CMD ["echo", "CI"]
 ---> Running in c68aa47d3686
Removing intermediate container c68aa47d3686
 ---> 28cd629f5770

Successfully built 28cd629f5770
Successfully tagged testapp_api:latest
WARNING: Image for service api was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating testapp_api_1 ... done
Attaching to testapp_api_1
api_1  | CI
testapp_api_1 exited with code 0
grigorii-duca:testapp greg$ docker-compose -f docker-compose.yml -f docker-compose-local.yml up
Recreating testapp_api_1 ... done
Attaching to testapp_api_1
api_1  | CI
testapp_api_1 exited with code 0
grigorii-duca:testapp greg$ 

Additional information

MacOS

docker-compose -f docker-compose.yml -f docker-compose-ci.yml config

services:
  api:
    build:
      context: /htdocs/combats/testapp
      target: ci
version: '3.4'

docker-compose -f docker-compose.yml -f docker-compose-local.yml config

services:
  api:
    build:
      context: /htdocs/combats/testapp
      target: development
version: '3.4'

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 27
  • Comments: 23 (1 by maintainers)

Commits related to this issue

Most upvoted comments

This issue has been automatically marked as not stale anymore due to the recent activity.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

I had problems with this in github actions, but no in my local. I added DOCKER_BUILDKIT: 1 thinking that docker-compose it’s just a wrapper of docker, and it worked.

@DracotMolver you might be missing DOCKER_BUILDKIT=1

As of Docker 18.09 you can use BuildKit. One of the benefits is skipping unused stages, so all you should need to do is build with DOCKER_BUILDKIT=1 docker build -t my-app --target prod

https://stackoverflow.com/a/55320725/368144

@eweidner For me, rebuilding does not fix it, and I’m not running multiple compose files at once. Do you think it’s a different issue?

It seems to keep the build.target from whichever file you ran docker-compose build on.

For example, say my docker-compose.yml specifies target: dev and my docker-compose.prod.yml specifies target: bin. If I now run docker-compose -f docker-compose.prod.yml build and then docker-compose up, it starts the bin stage.

In my case @bog-h i only work with one docker compose file. I’m using version 3.7

This is happening to me but with a different configuration. It’s creating dangling images because when I target to prod it creates the dev stage as well, and this stage was previously created.

My docker file (I removed some info):


FROM node:12 as base

WORKDIR /server

COPY package.json ./

RUN npm install

COPY ./ ./

# ------------------------

FROM base as dev

ENV NODE_ENV=development
ENV APP_HOST="0.0.0.0"

EXPOSE 3000

CMD ["npm", "run", "dev"]

# ------------------------

FROM base as prod

ENV NODE_ENV=production
ENV PORT=5000

EXPOSE 5000

CMD ["npm", "start"]

My docker-compose (I removed some info too):

version: "3.7"
services:
  server:
    build:
      context: ./server
      dockerfile: Dockerfile
      target: dev
    volumes:
      - ./server:/server
      - /server/node_modules
    container_name: newlit_server
    depends_on:
      - db
    ports:
      - 3000:3000
      - 5000:5000

  db:
    image: mongo
    container_name: newlist_db
    ports:
      - 27017:27017
    volumes:
      - mongodb_data_container:/data/db

volumes:
  mongodb_data_container:

If I run docker-compose up for the very first time. It will pull the node image and then will use it as a base for the dev stage. The container is up and running fine.

base stage Screen Shot 2020-04-09 at 18 12 16 … I skipped all the instalation of npm dev stage Screen Shot 2020-04-09 at 18 14 19

But then I face 2 situations when I change the target:

  • If I change the target value to prod, the docker-compose up doesn’t rebuild the image based on that stage on the Dockerfile. Instead, it’s setting up my container like it was in development mode (devstage). Doesn’t docker-compose up build (rebuild) the image if it doesn’t exist (prod stage doesn’t exist yet) and then run the container?.

rebuild dev stage image

  • When I run docker-compose build to avoid the step above. It rebuild the base image from cache, perfect!. The dev stage now is dangle because the prod stage has the same label (Am I right why the dangle exist?). But when I see the terminal, it is building the dev stage and then the prod. It make sense If I think docker-compose build runs through all the Dockerfile. If that the case, it is inevitable don’t go through the dev stage.

images after all of that image

Now. If I change again to dev and rebuild the image with docker-compose up server --build. It dangled the prev image (prod stage) and create again the dev from scratch, not form the cache. so know i have more dangle images, and this cycle will never ends.

image

What I finally ended up doing was:

  • Remove target from docker-compose.yml
  • Create two images running docker build ./server -t server-dev --target=dev and docker build ./server -t server-prod --target=prod
  • Using these images on docker-compose.yml when I need them.
...
services:
  server:
    # for productions change it to server-prod
    image: sever-dev
...

There’s a few different things going on in this issue:

  1. If target isn’t doing anything at all, it’s likely that you’re not building with BuildKit. Refer to @rafawhs’s comment.
  2. There is an issue where, when the target is changed in a compose file, such as:
services:
    foo:
        build:
            context: .
            target: devel

then running compose up then changing the Compose file to:

services:
    foo:
        build:
            context: .
            target: ci

and running compose up again, the image won’t be rebuilt according to the new target. A quick fix to this is running compose up --build, to force image rebuilding. This same issue is what was seen in the original issue, but with overwriting the target attribute of the build section. This doesn’t actually have anything to do with multiple Compose files, but with how/when images are built. After Compose has built the image for the service (with whatever target was defined at the time), the image won’t be rebuilt in consequent ups, unless specified.

Please comment (feel free to @ me) if there are other issues other than these.

Same issue here running docker-compose.yml with a docker-compose.override.yml file.

It worked with BuildKit enabled, as sugested by @infinito84

More about BuildKit: What is BuildKit? - Introducing BuildKit

Hello Guys! I’m glad that it is a common problem because I started to lose my mind 😄

Looks like docker-compose override is ignoring build: target argument. I thought the problem is in the cache, but not!

If you will specify a target (ex debug or base) in the main docker-compose.yaml file then everything will work as expected in depends on your target build: target: debug|base

But if you will specify the target in an override file (ex: docker-compose.debug.yaml) then this parameter is ignored!