docker-compose: using multiple Dockerfiles for multiple services
Asked Answered
D

4

49

I'm using docker-compose and I'd like to use different Dockerfiles for different services' build steps. The docs seem to suggest to place different Dockerfiles in different directories, but I'd like them all to be in the same one (and perhaps distinguishable using the following convention: Dockerfile.postgres, Dockerfile.main...). Is this possible?

Edit: The scenario I have contains this docker-compose file:

main:
  build: .
  volumes:
    - .:/code
  environment:
    - DEBUG=true

postgresdb:
  extends:
    file: docker-compose.yml
    service: main
  build: utils/sql/
  ports:
    - "5432"
  environment:
    - DEBUG=true

where postgresdb's Dockerfile is:

FROM postgres

# http://www.slideshare.net/tarkasteve/developerweek-2015-docker-tutorial
ADD make-db.sh /docker-entrypoint-initdb.d/

and the main is:

FROM python:2.7

RUN mkdir /code
WORKDIR /code
ADD requirements.txt /code/

RUN pip install --upgrade pip
RUN pip install -r requirements.txt
ADD . /code/

This works right now, but I'd like to extend postgresdb's Dockerfile by calling a Python script that creates tables in the database according to models built upon SQL Alchemy (the Python script would be called as python manage.py create_tables). I wanted to add it to the db's Dockerfile, but due to the isolation of the containers I can't use SQL Alchemy there because that image is based on the postgres image instead of Python's, and it doesn't contain the sqlalchemy package...

What can I do? I tried to use the main service in postgresdb, but unfortunately it doesn't carry python and its packages over, so I still can't write a single Dockerfile that creates the Postgres database (through the shell script) as well as its tables (through a Python script).

Damiandamiani answered 23/4, 2015 at 23:7 Comment(0)
H
25

This is not possible due to the way Docker handles build contexts.

You will have to use and place a Dockerfile in each directory that becomes part of the Docker build context for that service.

See: Dockerfile

You will in fact require a docker-compose.yml that looks like:

service1:
    build: service1

service2:
    build: service2

See: docker-compose

Update:

To address your particular use-case -- Whilst I understand what you're trying to do and why I personally wouldn't do this myself. The isolation is a good thing and helps to manage expectations and complexity. I would perform the "database creation" as either another container based off your app's source code or within the app container itself.

Alternatively you could look at more scripted and template driven solutions such as shutit (I have no experience in but heard god thigns about).

FWIW: Separation of concerns ftw :)

Headwaiter answered 23/4, 2015 at 23:43 Comment(1)
Hey James --thank you! I edited the question and added the reason I wanted to do this; would you know how to extend the services to solve this problem? Thanks again!Damiandamiani
C
59

You have to add it in build section. So, you can specify different alternative dockerfiles for each service.

services:
  service1:
    build:
        context: .
        args:
            - NODE_ENV=local
        dockerfile: Dockerfile_X
    ports:
        - "8765:8765"
Cloudy answered 13/4, 2018 at 7:51 Comment(1)
It was important for me to specify the path to my Dockerfile file where you have "Dockerfile_X" since it was in a subdirectory. For example: dockerfile: api/DockerfileLander
H
25

This is not possible due to the way Docker handles build contexts.

You will have to use and place a Dockerfile in each directory that becomes part of the Docker build context for that service.

See: Dockerfile

You will in fact require a docker-compose.yml that looks like:

service1:
    build: service1

service2:
    build: service2

See: docker-compose

Update:

To address your particular use-case -- Whilst I understand what you're trying to do and why I personally wouldn't do this myself. The isolation is a good thing and helps to manage expectations and complexity. I would perform the "database creation" as either another container based off your app's source code or within the app container itself.

Alternatively you could look at more scripted and template driven solutions such as shutit (I have no experience in but heard god thigns about).

FWIW: Separation of concerns ftw :)

Headwaiter answered 23/4, 2015 at 23:43 Comment(1)
Hey James --thank you! I edited the question and added the reason I wanted to do this; would you know how to extend the services to solve this problem? Thanks again!Damiandamiani
M
15

You can use dockerfile argument in your docker-compose.yml to specify an alternate one for a specific service.

I don't know when it was added, since the discussion is old, but you can see it's in the reference https://docs.docker.com/compose/compose-file/#dockerfile

I've tried it yesterday and it works with me. It the base dir for my project I have Dockerfile and Dockerfile-service3 and in the docker-compose.yml:

version: '2'

services:
    service1:
        build:
            context: .
            args:
                - NODE_ENV=local
        ports:
            - "8765:8765"
        # other args skipped for clarity
    service2:
        build:
            context: .
            args:
                - NODE_ENV=local
        ports:
            - "8766:8766"
        # other args skipped for clarity
    service3:
        build:
            context: .
            dockerfile: Dockerfile-service3
            args:
                - NODE_ENV=local
        ports:
            - "8767:8767"
        # other args skipped for clarity
    service4:
        build:
            context: .
            args:
                - NODE_ENV=local
        ports:
            - "8768:8768"
        # other args skipped for clarity

In this way all services, except service3 will be built using the standard Dockerfile and service3 will be built using the Dockerfile-service3.

Maltreat answered 13/4, 2018 at 6:36 Comment(0)
G
3

Creator of ShutIt here. Gratified to hear that people are hearing good things about it.

To be honest, in your position I'd write your own Dockerfile and use standard package management such as apt or yum. A quick check with an ubuntu image and python-pip and python-sqlalchemy are freely available.

There are more convoluted solutions that may work for you using ShutIt, happy to discuss this offline, as I think it's a bit off-topic. ShutIt was written for this kind of use case, as I could see that this would be a common problem given Dockerfiles' limited utility outside the microservices space.

Gmt answered 11/5, 2015 at 10:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.