380

How do you organize the Dockerfiles belonging to a project when you have one Dockerfile for the database, one for the application server, and so on? Do you create some sort of hierachy in the source? A big enterprise project can't consist of only one Dockerfile?

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
LuckyLuke
  • 47,771
  • 85
  • 270
  • 434
  • 28
    you may want to change the accepted answer – pomber Mar 09 '17 at 17:23
  • 4
    There should be an option to "outvote" and move automatically an obsolete `Accepted' attribute to a more appropriate answer. The eligibility criterion for such a move could be 1) a large difference in votes of say, 10:1 AND 2) the question author has not logged in for say, a year or longer (it seems @LuckyLuke has retired from SO 4 years ago...) – mirekphd Nov 22 '19 at 09:57
  • I want to update the question, but is already at 256, god help me – Juancki Mar 25 '21 at 11:57

6 Answers6

452

In newer versions(>=1.8.0) of docker, you can do this

docker build -f Dockerfile.db .
docker build -f Dockerfile.web .

A big save.

EDIT: update versions per raksja's comment

EDIT: comment from @vsevolod: it's possible to get syntax highlighting in VS code by giving files .Dockerfile extension(instead of name) e.g. Prod.Dockerfile, Test.Dockerfile etc.

Shuo
  • 8,447
  • 4
  • 30
  • 36
  • 4
    Just checked, https://github.com/docker/docker/wiki, so its > Docker 1.8.0 – raksja Apr 14 '17 at 01:53
  • 7
    sure this works, but my IDE won't do any syntax highlighting though, because it doesn't recognized the filename :( – Alexander Mills May 27 '17 at 00:59
  • 4
    @AlexanderMills my IDE WebStorm doesn't even allow `Dockerfile.web` as a run configuration. So I created an issue: https://youtrack.jetbrains.com/issue/WEB-28185 – steampowered Aug 05 '17 at 23:19
  • 9
    How do you specify which Dockerfile should be used for each 'service' defined within a `docker-compose.yml` file, for example? – JoeTidee Dec 24 '17 at 22:11
  • 1
    @AlexanderMills in IntelliJ IDEA you can associate filetype with a file name regex: Dockerfile.* – Dmitry Tokarev Jan 23 '18 at 06:32
  • 1
    @JoeTidee A bit late to the party, but as stated in the docs (https://docs.docker.com/compose/compose-file/#build) you can use `dockerfile: Dockerfile-alternate` inside of the `build` section for your container. – Yoone May 05 '18 at 23:08
  • 2
    @AlexanderMills you could also name the files db.Dockerfile, web.Dockerfile, etc, then the intellisense would recognize them as dockerfiles – Alan Zeng Sep 06 '18 at 15:31
  • Seconding @DmitryTokarev's suggestion. Matching the Dockerfile type to Dockerfile* works great, and preserves syntax highlighting. – Peter Cassetta Oct 22 '18 at 23:08
  • 1
    You can also just create directories like docker-prod or whatever you need and add a normally named Dockerfile to that directory, and then specify it with the path: `docker build -f ./docker-prod/Dockerfile` – Jordan Sep 13 '19 at 17:58
  • 3
    From 2019 (or earlier) it's possible to get syntax highlighting in VS code by giving files .Dockerfile extension(instead of name) e.g. Prod.Dockerfile, Test.Dockerfile etc. – Vsevolod Nov 13 '19 at 13:15
  • It doesn't work for `Docker version 19.03.13, build 4484c46d9d`. I get `docker build" requires exactly 1 argument.`, although `docker build --help` shows the `--file` option – Martin Thoma Sep 23 '20 at 06:13
  • 2
    I figured it it out: I still need to give the build context, which is a directory. So mind the dot at the end of `docker build -f tests/Dockerfile.pytest .` – Martin Thoma Sep 23 '20 at 07:11
256

Use docker-compose and multiple Dockerfile in separate directories

Don't rename your Dockerfile to Dockerfile.db or Dockerfile.web, it may not be supported by your IDE and you will lose syntax highlighting.

As Kingsley Uchnor said, you can have multiple Dockerfile, one per directory, which represent something you want to build.

I like to have a docker folder which holds each applications and their configuration. Here's an example project folder hierarchy for a web application that has a database.

docker-compose.yml
docker
├── web
│   └── Dockerfile
└── db
    └── Dockerfile

docker-compose.yml example:

version: '3'
services:
  web:
    # will build ./docker/web/Dockerfile
    build: ./docker/web
    ports:
     - "5000:5000"
    volumes:
     - .:/code
  db:
    # will build ./docker/db/Dockerfile
    build: ./docker/db
    ports:
      - "3306:3306"
  redis:
    # will use docker hub's redis prebuilt image from here:
    # https://hub.docker.com/_/redis/
    image: "redis:alpine"

docker-compose command line usage example:

# The following command will create and start all containers in the background
# using docker-compose.yml from current directory
docker-compose up -d

# get help
docker-compose --help

In case you need files from parent folder(s) as part of the build context of your Dockerfile

You can still use the above solution and place your Dockerfile in a directory such as docker/web/Dockerfile, all you need is to set the build context in your docker-compose.yml like this:

version: '3'
services:
  web:
    build:
      context: .
      dockerfile: ./docker/web/Dockerfile
    ports:
     - "5000:5000"
    volumes:
     - .:/code

The files hierarchy would loke like this:

config-on-root.ini
docker-compose.yml
docker
└── web
    ├── Dockerfile
    └── some-other-config.ini

The ./docker/web/Dockerfile will have access to desired files from the context like this:

FROM alpine:latest

COPY config-on-root.ini /
COPY docker/web/some-other-config.ini /

Also note that the build context will contain all the files of the specified directory. Make sure tou use a .dockerignore file to prevent loading undesired large files or directories to save time during build.

Here are some quick commands from tldr docker-compose. Make sure you refer to official documentation for more details.

GabLeRoux
  • 16,715
  • 16
  • 63
  • 81
  • 2
    What if you need to copy a package manager file in order to install deps on build time (f.i `COPY ../package.json /app/package.json`)? That file will be usually at root level and docker has forbidden access to the parent. What approach will you follow? – nass600 Feb 27 '18 at 20:21
  • 1
    I've hit that limitation too and for this exception, I build the `web` project from `.` (in `docker-compose.yml`: `build: .`). This way, `web` has access to root files when building. I've seen this related question: https://stackoverflow.com/questions/24537340/docker-adding-a-file-from-a-parent-directory and we can build from parent directory instead when using `docker` command line and this answer shows how to do so with docker-compose: https://stackoverflow.com/a/45353241/1092815 – GabLeRoux Feb 27 '18 at 20:51
  • Right, I end up adding `.` as `context` in the `build` option so I can access those files at root. Thanks @GabLeRoux – nass600 Feb 28 '18 at 13:26
  • 1
    This is an issue with your IDE, not with docker. @Shuo has the correct answer. – BentOnCoding Mar 01 '18 at 18:14
  • @BentOnCoding Please see https://stackoverflow.com/questions/26077543/how-to-name-dockerfiles – GabLeRoux Mar 01 '18 at 21:36
  • 1
    Second answer is 1 year old but it's not directly taken form Docker's documentation. `-f` option is fine, but I prefer to use `docker-compose` with subfolders. I think both answers are valid. Most people may just prefer to keep the default `Dockerfile` name to support most IDEs out of the box. I'm not invalidating first answer, I'm just providing an alternative. I just don't like my IDE to think my Dockerfile is a `php` file when I use `Dockerfile.php`, but yes, it works. I've seen a few examples in docker documentation; `Dockerfile.build`, `Dockerfile.debug`, etc. – GabLeRoux Mar 02 '18 at 01:45
  • 4
    Naming as `example.Dockerfile` keeps syntax highlighting and icons on VSCode. – vmassuchetto Jun 22 '18 at 10:52
  • 2
    This is a lot of complexity to add simply to get syntax highlighting in your IDE for what is a pretty trivial file format. – Graham Lea Oct 01 '19 at 04:47
  • 1
    This is a really good answer. – bit Aug 04 '22 at 17:49
  • "In case you need files from previous folders when building your Dockerfile" this part of the answer is not clear at all. It needs to be clarified. – bit Aug 04 '22 at 21:12
  • @bit I’ve updated the answer to make it easier to understand. Let me know how I can improve the answer if you feel it’s still unclear :) – GabLeRoux Aug 06 '22 at 16:23
34

Author's Note

This answer is out of date. Fig no longer exists and has been replaced by Docker compose. Accepted answers cannot be deleted.

Docker Compose supports the building of project hierachy. So it's now easy to support a Dockerfile in each sub directory.

├── docker-compose.yml
├── project1
│   └── Dockerfile
└── project2
    └── Dockerfile

Original answer

I just create a directory containing a Dockerfile for each component. Example:

When building the containers just give the directory name and Docker will select the correct Dockerfile.

Błażej Michalik
  • 4,474
  • 40
  • 55
Mark O'Connor
  • 76,015
  • 10
  • 139
  • 185
  • 3
    @DuncanJones Cause you cannot delete an accepted answer... Tried :-) – Mark O'Connor Apr 06 '18 at 16:10
  • 3
    The problem with this approach is if we need to add files from root directory to the project file while building the docker image it is a big problem. – Tara Prasad Gurung Jul 11 '20 at 14:16
  • I see your point, yes, changing a common file would mean all the images would to be rebuilt. Personally, I try to avoid multiple Dockerfile within a project. Where I encounter this scenario I build a single image that contains multiple binaries. At run-time the image can be invoked using different commands. – Mark O'Connor Jul 13 '20 at 08:03
  • +1 for modifying the answer with the newer acceptable solution, a lot of people just leave depricated ways of doing things. – Gherbi Hicham Oct 08 '21 at 15:36
15

In Intellij, I simply changed the name of the docker files to *.Dockerfile, and associated the file type *.Dockerfile to docker syntax.

GabLeRoux
  • 16,715
  • 16
  • 63
  • 81
KaziMurtaza
  • 147
  • 1
  • 3
3

Add an abstraction layer, for example, a YAML file like in this project https://github.com/larytet/dockerfile-generator which looks like

centos7:
    base: centos:centos7
    packager: rpm
    install:
      - $build_essential_centos 
      - rpm-build
    run:
      - $get_release
    env:
      - $environment_vars

A short Python script/make can generate all Dockerfiles from the configuration file.

zypA13510
  • 1,092
  • 1
  • 10
  • 28
Larytet
  • 648
  • 3
  • 13
1

When working on a project that requires the use of multiple dockerfiles, simply create each dockerfile in a separate directory. For instance,

app/ db/

Each of the above directories will contain their dockerfile. When an application is being built, docker will search all directories and build all dockerfiles.