Home > other >  How to organize multiple Dockerfiles, docker-compose.yaml and .dockerignore
How to organize multiple Dockerfiles, docker-compose.yaml and .dockerignore

Time:10-15

After reviewing the answers on How to name Dockerfiles I'm still left with a lot of questions.

In my case, I am needing at least two Dockerfiles, a docker-compose.yaml and a .dockerignore. It sounds like using an extension such as <purpose>.Dockerfile or Dockerfile.<purpose> has the drawback of losing the functionality of using autobuilder at hub.docker.com.

So others are suggesting you keep each Dockerfile in a directory and build from there.

So maybe something like:

dockerfiles/
--python_consumer/
-----Dockerfile
--python_producer/
-----Dockerfile
--docker-compose.yaml
--.dockerignore

Would the .dockerignore in this case work globally for all of the dockerfiles? Any big drawbacks to structuring this way?

Example of my docker-compose.yaml without separate directories and one combined consumer/production image for context.

version: '3.8'
services:
  standalone:
    hostname: standalone
    container_name: standalone
    image: apachepulsar/pulsar:2.8.1
    ports:
      - 8080:8080 # exposed would be a better practice
      - 6650:6650 # exposed would be a better practice
    command: bin/pulsar standalone
    healthcheck:
      test: ["CMD", "nc", "-vz", "localhost", "6650"]
      interval: 20s
      timeout: 5s
      retries: 5
    networks:
      - conprod
  conprod:
    hostname: conprod
    container_name: conprod
    build:
      context: .
      dockerfile: ./Dockerfile
    restart: on-failure # best practice is probably "unless-stopped"
    depends_on:
      - standalone
    networks:
      - conprod
networks:
  conprod:

CodePudding user response:

When you build an image, you send the Docker daemon a build context; in your Compose setup this is the directory named in the build: { context: } setting. The .dockerignore file must be in that exact directory and nowhere else. Its actual effect is to cause files to be excluded from the build context, which can result in a faster build sequence.

The build context's other important effect is that all Dockerfile COPY directives are considered relative to that directory; you cannot COPY from parent or sibling directories. So if files are shared between projects, you must set the context directory to some ancestor directory of all of the files that will be included, and COPY directives will be relative to that directory (even if the Dockerfiles are in per-project directories). See also How to include files outside of Docker's build context?

If your projects are completely separate: maybe there's a front-end and a back-end project, or in your case a producer and a consumer that share a message format but not any actual code. Then in this case:

  • Put a Dockerfile, named exactly Dockerfile, in each project subdirectory
  • Put a .dockerignore file in each project subdirectory (it cannot be in the parent directory)
  • COPY directives are relative to the project subdirectory
    COPY requirements.txt ./
    
  • In the Compose file, you can use the shorthand build: directory syntax, since you have the standard (default) dockerfile: name
    version: '3.8'
    services:
       producer:
         build: ./python_producer
         environment:
           - RABBITMQ_HOST=rabbitmq
       consumer:
         build: ./python_consumer
         environment:
           - RABBITMQ_HOST=rabbitmq
       rabbitmq:
         image: rabbitmq:3
         hostname: rabbitmq # RabbitMQ is very unusual in needing to set this
    

If your projects share code or other files: in your example maybe you define Python data structures for the message format in shared code. This in this case:

  • Put a Dockerfile, named exactly Dockerfile, in each project subdirectory
  • Put a single .dockerignore file in the project root
  • COPY directives are relative to the project root directory
    COPY python_producer/requirements.txt ./
    
  • In the Compose file you need to specify context: . and dockerfile: pointing at a per-component Dockerfile
    version: '3.8'
    services:
       producer:
         build:
           context: .
           dockerfile: python_producer/Dockerfile
         environment:
           - RABBITMQ_HOST=rabbitmq
       consumer:
         build:
           context: .
           dockerfile: python_consumer/Dockerfile
         environment:
           - RABBITMQ_HOST=rabbitmq
       rabbitmq:
         image: rabbitmq:3
         hostname: rabbitmq # RabbitMQ is very unusual in needing to set this
    
  • Related