# 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 `docker-compose.yml` 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 `<Enter>` 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.yml
    ├── docker-compose.override.yml
    ├── docker-compose.yml
    ├── 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.yml
    ├── docker-compose.override.yml
    ├── docker-compose.yml
    ├── 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 `docker-compose.yml` 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.