dockerdocker-composedocker-containermulti-tier

Where do you keep your docker compose.yml's?


Introduction

I've got two multi-tiered web applications running in docker containers that I'm trying to start using docker compose rather than docker run. I hope the diagram below conveys the setup but I wonder if it's done properly.

Docker Containers

Let's take just one as example, the simpler galleries application on the right. I can probably figure out the recipes application if I get the galleries right. It has two images:

  1. ng.galleries - an angular web front-end, internet-facing, listening with nginx on port 8001, and communicating with the rest service over port 8000. Developed in vscode.
  2. rest.galleries - a spring boot rest service with tomcat listening on port 8000, logging to a volume and storing its data (folders and pictures) in another volume. Developed in Spring Tool Suite 4.

Angular Front-end

It has a Dockerfile and ng build creates the image. I was about to create a compose.yml when I realized I probably shouldn't have one for each image but rather somehow use compose to orchestrate startup of multiple images, dependencies and volumes.

Dockerfile

FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf
COPY /dist/ca.footeware.ng.web /usr/share/nginx/html

Rest Service

This is where I started to use compose. It's a maven build with a Dockerfile and a compose.yml. mvn clean package creates the docker image and docker compose up starts it as a container. I can test it locally using curl and deploy on server when fit.

Dockerfile

FROM amd64/eclipse-temurin:22-jre
ARG JAR_FILE
ADD ${JAR_FILE} /opt/rest.galleries/app.jar
EXPOSE 8000
ENTRYPOINT ["java","-jar","/opt/rest.galleries/app.jar"]

compose.yml:

services:
  rest_galleries:
    image: rest.galleries:3.5.0
    container_name: rest.galleries
    restart: unless-stopped
    ports:
      - 8000:8000
    volumes:
      - /opt/rest.galleries/galleries:/opt/rest.galleries/galleries
      - /opt/rest.galleries/logs:/opt/rest.galleries/logs

The Question

So after all that I'm trying to decide the next move. Do I create a compose.yml in the ng.galleries project in vscode? If I do, I'd have to describe that it depends_on the rest.galleries service. Then when all looks right, I can log onto the server and start using another compose.yml? One tailored to starting the two galleries containers? I can see if both angular and rest service were developed in the one IDE, it might be easier but that's not the case and it's clear as mud to me.

Where do you keep your compose.yml's and what would they look like given the above diagram?


Solution

  • I would create one Compose file per application. In the initial diagram you show two logical applications ("recipes" and "galleries") and at the bottom of that diagram one compose.yml file for each, and that model makes sense to me.

    (It seems like you're asking if you should create one Compose file per service. This is harder to manage, and there are complexities in trying to make different Compose files on the one hand talk to each other, and on the other hand not conflict from accidentally using the same names.)

    The natural place to put the Compose file is the parent directory of the projects it includes, like

    src/
    +-- galleries/
        +-- docker-compose.yml
        +-- ng.galleries/
        |   +-- Dockerfile
        |   +-- package.json
        |       ...
        +-- rest.galleries/
            +-- Dockerfile
            +-- pom.xml
                ...
    

    Then the Compose file lists the individual services.

    version: '3.8'
    services:
      ng:
        build: ./ng.galleries/
        restart: unless-stopped
        ports: ['3000:3000']
      rest:
        build: ./ng.rest/
        restart: unless-stopped
        ports: ['8000:8000']
        volumes:
          - galleries:/opt/rest.galleries/galleries
    volumes:
      galleries:
    

    (I've removed the "logs" volume from the setup; configure your application to write to stdout instead of a log file, and docker-compose logs rest will show the logs. I've converted the local storage to a Docker named volume as well, which can avoid some permission-related problems but can also add some complexity around backing up content.)

    You can individually start one service or the other if you need to

    # start only the frontend
    docker-compose up -d ng
    

    You can have a similar setup for the other project. Assuming the other project is in a differently-named top directory, Compose uses that directory name to generate a project name. The various objects Compose creates are internally labelled with that project name, and objects in different projects won't conflict. It's not a problem if both applications contain Compose services named rest, for example, since Compose will keep the two projects' Docker objects separate.