From 0ea8efffcdd1ee2d45f0ed6605034fd519c4bedb Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 6 Jun 2022 04:37:03 +0200 Subject: [PATCH] feat(docker-compose): Allow directory name different from service or component names --- README.md | 5 +- docker-compose/README.md | 87 +++++++++++++++++-- docker-compose/cookiecutter.json | 2 +- .../hashicorpvault/build-context/Dockerfile | 4 +- .../docker-compose.override.yml | 8 +- .../hashicorpvault/docker-compose.yml | 22 ++--- .../env/fully.qualified.domain.name.example | 2 +- 7 files changed, 104 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6f407d8..137fa40 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,10 @@ Cookiecutter prompts you for whatever info the template needs then generates fil This is Cookiecutter prompting for info: ``` -service []: grafana +project_slug [dir-name]: grafana +service [grafana]: component_list [grafana]: grafana,nginx -context []: cncf +context [ctx]: cncf ``` The end result is a directory structure that has everything you need to hit the ground running. diff --git a/docker-compose/README.md b/docker-compose/README.md index 913281c..2e1ba90 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -9,20 +9,73 @@ cookiecutter https://quico.space/Quico/py-cookiecutter-templates.git --directory Cookiecutter interactively prompts you for the following info, here with example answers: ``` -service []: grafana +project_slug [dir-name]: grafana +service [grafana]: component_list [grafana]: grafana,nginx -context []: cncf +context [ctx]: cncf ``` Done, directory structure and files for your next `docker-compose` project are ready for you to hit the ground running. ## Explanation and terminology -Each `docker-compose` project forms a *__service__* that may consist of either a single or multiple *__components__*. +Your four answers translate as follows into rendered files. -The `service` variable by default is empty. In this example we've chosen to name the service `grafana`. We want `grafana` to consist of two components, namely Grafana itself and Nginx. Syntax for a multi-component `component_list` is a comma-separated list without spaces. The string `grafana,nginx` will be treated as a list of two components. Capitalization doesn't matter, we're lowercasing all strings automatically. The template prefills `component_list` with whatever you previously entered as the `service` name. To create directory structure for a _single-component service_ confirm the default. If `component_list` and `service` are identical directory structure will be that for a _single-component service_. +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}/... <--- + ... + ``` -The last prompt for a *__context__* is a generic string to help you distinguish deployments. It can be whatever you want such as for example a team name, here `cncf`. +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. The last prompt for a `context` is a generic string to help you distinguish deployments. It can be whatever you want such as for example a team name, here `cncf` which shows up as a preset in an example env file. It defaults to `ctx` just it can't be empty. + ``` + . + └── grafana + ... + └── env + └── fully.qualified.domain.name.example <--- + ``` + + Which then looks like: + ``` + CONTEXT=cncf + ... + ``` + +Also check out [the Caveats section](#caveats) at the end to learn what this template does not do well. ## Result @@ -72,3 +125,27 @@ With an alternative single-component `hashicorpvault` service the result may loo └── fully.qualified.domain.name.example ``` 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 perfect. + +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 simply and go with option 2. diff --git a/docker-compose/cookiecutter.json b/docker-compose/cookiecutter.json index e5126f9..07bc351 100644 --- a/docker-compose/cookiecutter.json +++ b/docker-compose/cookiecutter.json @@ -5,6 +5,6 @@ "__service_slug": "{{ cookiecutter.service.lower().replace(' ', '_').replace('-', '_') }}", "component_list": "{{ cookiecutter.__service_slug }}", "__component_list_slug": "{{ cookiecutter.component_list.lower().replace(' ', '_').replace('-', '_') }}", - "context": "", + "context": "ctx", "__context_slug": "{{ cookiecutter.context.lower().replace(' ', '_').replace('-', '_') }}" } diff --git a/docker-compose/examples/hashicorpvault/build-context/Dockerfile b/docker-compose/examples/hashicorpvault/build-context/Dockerfile index 0be04fa..e769fff 100644 --- a/docker-compose/examples/hashicorpvault/build-context/Dockerfile +++ b/docker-compose/examples/hashicorpvault/build-context/Dockerfile @@ -4,10 +4,10 @@ # ARG EXAMPLE_ARG_FOR_DOCKERFILE # Another env var, this one's needed in the example build step below: -# ARG HASHICORPVAULT_VERSION +# ARG VAULT_VERSION # Example -# FROM "hashicorpvault:${HASHICORPVAULT_VERSION}" +# FROM "vault:${VAULT_VERSION}" # RUN apt-get update && \ # apt-get -y install \ # somepackage-6.q16-6-extra && \ diff --git a/docker-compose/examples/hashicorpvault/docker-compose.override.yml b/docker-compose/examples/hashicorpvault/docker-compose.override.yml index 2917348..0f7e0dd 100644 --- a/docker-compose/examples/hashicorpvault/docker-compose.override.yml +++ b/docker-compose/examples/hashicorpvault/docker-compose.override.yml @@ -1,10 +1,10 @@ services: - hashicorpvault-build: - image: "hashicorpvault:${HASHICORPVAULT_VERSION}" + vault-build: + image: "vault:${VAULT_VERSION}" profiles: ["build"] build: - context: "build-context/hashicorpvault" + context: "build-context/vault" dockerfile: Dockerfile args: EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}" - HASHICORPVAULT_VERSION: "${HASHICORPVAULT_VERSION}" + VAULT_VERSION: "${VAULT_VERSION}" diff --git a/docker-compose/examples/hashicorpvault/docker-compose.yml b/docker-compose/examples/hashicorpvault/docker-compose.yml index 04d3f35..6e0ecf9 100644 --- a/docker-compose/examples/hashicorpvault/docker-compose.yml +++ b/docker-compose/examples/hashicorpvault/docker-compose.yml @@ -1,24 +1,24 @@ services: - hashicorpvault: - image: "hashicorpvault:${HASHICORPVAULT_VERSION}" - container_name: "hashicorpvault-${CONTEXT}" + vault: + image: "vault:${VAULT_VERSION}" + container_name: "vault-${CONTEXT}" networks: - hashicorpvault-default: + vault-default: extends: file: common-settings.yml service: common-settings ports: # - "8080:80" volumes: - # - /opt/docker-data/hashicorpvault-${CONTEXT}/data/db:/usr/lib/hashicorpvault - # - /opt/docker-data/hashicorpvault-${CONTEXT}/data/logs:/var/log/hashicorpvault - # - /opt/docker-data/hashicorpvault-${CONTEXT}/config:/etc/hashicorpvault + # - /opt/docker-data/vault-${CONTEXT}/data/db:/usr/lib/vault + # - /opt/docker-data/vault-${CONTEXT}/data/logs:/var/log/vault + # - /opt/docker-data/vault-${CONTEXT}/config:/etc/vault environment: - # HASHICORPVAULT_USER: ${HASHICORPVAULT_USER} - # HASHICORPVAULT_PASSWORD: ${HASHICORPVAULT_PASSWORD} + # VAULT_USER: ${VAULT_USER} + # VAULT_PASSWORD: ${VAULT_PASSWORD} networks: - hashicorpvault-default: - name: hashicorpvault-${CONTEXT} + vault-default: + name: vault-${CONTEXT} driver: bridge driver_opts: com.docker.network.enable_ipv6: "false" diff --git a/docker-compose/examples/hashicorpvault/env/fully.qualified.domain.name.example b/docker-compose/examples/hashicorpvault/env/fully.qualified.domain.name.example index bf58662..dd4646f 100644 --- a/docker-compose/examples/hashicorpvault/env/fully.qualified.domain.name.example +++ b/docker-compose/examples/hashicorpvault/env/fully.qualified.domain.name.example @@ -4,7 +4,7 @@ CONTEXT=fsf # Set something sensible here and uncomment # --- -# HASHICORPVAULT_VERSION=x.y.z +# VAULT_VERSION=x.y.z