# docker-compose template ## Run it Execute this template like so: ``` cookiecutter https://quico.space/Quico/py-cookiecutter-templates.git --directory 'docker-compose' ``` Cookiecutter interactively prompts you for the following info, here with example answers: ``` project_slug [dir-name]: grafana service [grafana]: component_list [grafana]: grafana,nginx Select build: 1 - no 2 - yes Choose from 1, 2 [1]: ``` Done, directory structure and files for your next `docker-compose` project are ready for you to hit the ground running. ## Explanation and terminology Your four answers translate as follows into rendered files. 1. The `project_slug` is used only as directory name. A container named `vault` may be fine but the project directory name `hashicorpvault` might be more descriptive. ``` . └── hashicorpvault <--- Here ├── build-context │   ├── docker-data │   │   └── .gitkeep │   ├── Dockerfile ... ``` 2. The `service` variable by default copies your `project_slug` answer. It's a style decision whether you leave it at that and just hit `Enter`. The service name will come up in rendered `compose.yaml` at purely cosmetic locations such as the `networks:` key, `container_name:` and `/opt/docker-data` volume mount presets, here with `ftp` as the service name: ``` services: mysql: image: "mysql:${MYSQL_VERSION}" container_name: "ftp-mysql-${CONTEXT}" <--- networks: ftp-default: <--- ... volumes: # - /opt/docker-data/ftp-mysql-${CONTEXT}/... <--- # - /opt/docker-data/ftp-mysql-${CONTEXT}/... <--- # - /opt/docker-data/ftp-mysql-${CONTEXT}/... <--- ... ``` 3. Treat `component_list` as the list of Docker images that make up your service. Each `docker-compose` project forms a *__service__* - see above - that consists of either a single or multiple *__components__*. They're your `services:`, your container, volume, variable names etc.: ``` services: grafana: <--- image: "grafana:${GRAFANA_VERSION}" <--- container_name: "grafana-grafana-${CONTEXT}" <--- ... environment: # GRAFANA_USER: ${GRAFANA_USER} <--- # GRAFANA_PASSWORD: ${GRAFANA_PASSWORD} <--- ... ``` 4. Prompt `build` is a yes-no question. Cookiecutter will create a `README.md` file with copy-pastable Docker Compose commands pre-filled. If you answer `yes` to this prompt `README.md` will contain an example paragraph that explains the build process along the lines of: ``` docker compose ... --profile 'build' build ``` Whereas by answering `no` (or just hitting `` to accept the default of `no`) no such paragraph will be added to the example Markdown file. Build instructions are only really needed if you need to locally build a derivative image. Also check out [the Caveats section](#caveats) at the end to learn what this template does not do well. ## Result ### Multi-component service Above example of a multi-component (two in this case) `grafana` service will give you this directory structure: ``` . └── grafana ├── build-context │   ├── grafana │   │   ├── docker-data │   │   │   └── .gitkeep │   │   ├── Dockerfile │   │   └── extras │   │   └── .gitkeep │   └── nginx │   ├── docker-data │   │   └── .gitkeep │   ├── Dockerfile │   └── extras │   └── .gitkeep ├── common-settings.yaml ├── compose.override.yaml ├── compose.yaml ├── env │   └── fqdn_context.env.example └── README.md ``` Check out file contents over in the [examples/grafana](examples/grafana) subdir. ### Single-component service With an alternative single-component `hashicorpvault` service the result may look like this: ``` . └── hashicorpvault ├── build-context │   ├── docker-data │   │   └── .gitkeep │   ├── Dockerfile │   └── extras │   └── .gitkeep ├── common-settings.yaml ├── compose.override.yaml ├── compose.yaml ├── env │   └── fqdn_context.env.example └── README.md ``` Check out file contents over in the [examples/hashicorpvault](examples/hashicorpvault) subdir. ## Caveats Consider Cookiecutter's project directory and rendered files a starting point. It won't do everything perfectly. Imagine if you will a service that consists of [Infinispan](https://infinispan.org/) among other things. In Docker Hub's content-addressable image store Infinispan's location is at `infinispan/server` so you obviously want that exact string with a forward slash to show up in your `compose.yaml` as the `image:` key's value, same with your `Dockerfile`. The `image:` key's value comes from what you enter in Cookiecutter's `component_list` prompt. Component strings are then used to also pre-fill the `volumes:` key. _**This**_ will cause obvious issues (but the `image:` key is kinda correct): ``` services: infinispan/server: image: "infinispan/server:${INFINISPAN/SERVER_VERSION}" container_name: "cacheman-infinispan/server-${CONTEXT}" ``` _**This**_ won't cause issues (but you'll have to then go in and manually change the `image:` key to use `infinispan/server`): ``` services: infinispan: image: "infinispan:${INFINISPAN_VERSION}" container_name: "cacheman-infinispan-${CONTEXT}" ``` You're going to want to keep it simple and go with option 2.