Set the build context of docker-compose to a different directory than the docker-compse.yml file

Viewed 352

My Problem

I have an app with 3 containers - a DB, a tester, and a server. My code structure is as follows:

.
├── Makefile
├── docker-compose.yml
├── docker
│   ├── docker-compose.yml
│   ├── postgres
│   │   ├── Dockerfile
│   │   └── create_fixtures.sql
│   ├── server
│   │   └── Dockerfile
│   └── tests
│       └── Dockerfile
├── server
│   ├── __init__.py
│   └── server.py
└── tests
    ├── __init__.py
    └── test.py

I would like to keep all docker data inside the docker directory but have the build context set to the root directory so that it can copy the server and tests directories to their respective images.

What Have I Tried

Does not work

$ docker-compose -f docker/docker-compose.yml up

failed to solve with frontend dockerfile.v0: failed to read dockerfile: error from sender: resolve : lstat /Users/adamatan/repos/anda-app/docker/docker: no such file or directory

In other words, the build context seems to be the location of the docker-compose file. I want to decouple it.

Works

$ docker-compose up

Which takes the docker-compose.yml file from the root dir.

This has been reported in Docker's git repo, but I'm not sure if there's a good way to overcome it.

My Question

How can I set the build context of a docker-compose up action to a root directory, but use a docker-compose.yml file from one of its subdirectories?

2 Answers

I think the work-around is found in this bug comment here:

In case someone also gets to this ticket with the same issue. When specifying "." for context it will use the current directory that the compose file is located within. If you want to reference the compose file and related Dockerfile from the current directory you are running from you either need to specify full paths or use ${PWD} for context. I kinda wish it would use the current working directory by default.

I would like you to try with the following approach:
From:

.
├── Makefile
├── docker-compose.yml
├── docker
│   ├── docker-compose.yml
│   ├── postgres
│   │   ├── Dockerfile
│   │   └── create_fixtures.sql
│   ├── server
│   │   └── Dockerfile
│   └── tests
│       └── Dockerfile
├── server
│   ├── __init__.py
│   └── server.py
└── tests
    ├── __init__.py
    └── test.py

Change to:

.
├── Makefile
├── docker-compose.yml
|
|-- postgres
|    |--- Dockerfile
|    |--- create.sql
|
├── server
│   ├── __init__.py
│   └── server.py
|   |-- Dockerfile
|
└── tests
    ├── __init__.py
    └── test.py
    |-- Dockerfile

Now, within docker-compose.yml assuming you use version 3+

Set the service as follows:

networks:
 app_net:
volumes:
 postgres_data:

services:
database:
    image: example/database
    volumes:
      - postgres_data:/var/lib/postgresql/data
    env_file: postgres/.dbenv # If you want to send some env vars
    build:
      context: .
      dockerfile: postgres/Dockerfile
    environment:
      POSTGRES_PASSWORD: example
      POSTGRES_USER: example
    
    ports:
      - 9332:5432
    networks:
      - app_network

.dbenv will contain the following:

DBFILE=postgres/create.sql # This can also be achieved using args in docker-compose itself.

The Dockerfile should also ensure that the COPY happens correctly from the source to destination. An example for your reference:

FROM python:3.7
WORKDIR /usr/src/postgres
COPY ./postgres .
... Do something with it...

In the same way as database service you can also set up server and tests it will be build and started as expected. I also realized that you would like to keep docker stuff within docker.

I think if you may be play around with the build context as I have suggested around with your folder structure it will work as well. Furthermore, I think the solution to your problem will be to pass the context as context: ./docker/postgres and the dockerfile: Dockerfile

Related