From 63cbe035ad6f4cd8f83533749e96ddf99b98acf9 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:17:32 +0200 Subject: [PATCH 01/12] feat(docker-compose): Align env example file name with other docs --- .../env/{fully.qualified.domain.name.example => fqdn_context.env} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docker-compose/{{ cookiecutter.__project_slug }}/env/{fully.qualified.domain.name.example => fqdn_context.env} (100%) diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/env/fully.qualified.domain.name.example b/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env similarity index 100% rename from docker-compose/{{ cookiecutter.__project_slug }}/env/fully.qualified.domain.name.example rename to docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env -- 2.47.2 From 0c167ec6aba2cb29d47c1c43078d888905036209 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:41:24 +0200 Subject: [PATCH 02/12] feat(docker-compose): Align env example file name with other docs --- .../env/{fqdn_context.env => fqdn_context.env.example} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docker-compose/{{ cookiecutter.__project_slug }}/env/{fqdn_context.env => fqdn_context.env.example} (100%) diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env b/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example similarity index 100% rename from docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env rename to docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example -- 2.47.2 From a7a8290f66cb820aaa52b748acf4f474a9c9d34f Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:42:17 +0200 Subject: [PATCH 03/12] feat(docker-compose): Align env example file name with other docs --- ...lly.qualified.domain.name.example => fqdn_context.env.example} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docker-compose/examples/hashicorpvault/env/{fully.qualified.domain.name.example => fqdn_context.env.example} (100%) diff --git a/docker-compose/examples/hashicorpvault/env/fully.qualified.domain.name.example b/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example similarity index 100% rename from docker-compose/examples/hashicorpvault/env/fully.qualified.domain.name.example rename to docker-compose/examples/hashicorpvault/env/fqdn_context.env.example -- 2.47.2 From 3de179d613ced10c3c25a1acc231f763b3d7fb21 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:49:04 +0200 Subject: [PATCH 04/12] feat(docker-compose): Allow env inside Docker Compose Cookiecutter template --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ed24fba..374ca1c 100644 --- a/.gitignore +++ b/.gitignore @@ -206,6 +206,8 @@ venv/ ENV/ env.bak/ venv.bak/ +!docker-compose/examples/*/env +!docker-compose/{{ cookiecutter.__project_slug }}/env # Spyder project settings .spyderproject -- 2.47.2 From b0339464443b940a73e4a6a6ccfbf12c04bf5226 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:49:45 +0200 Subject: [PATCH 05/12] feat(docker-compose): Add example for health check between two services --- .../examples/grafana/docker-compose.yml | 9 ++++++++ ....name.example => fqdn_context.env.example} | 1 + .../env/fqdn_context.env.example | 1 + .../docker-compose.yml | 21 +++++++++++++++++++ .../env/fqdn_context.env.example | 5 +++++ 5 files changed, 37 insertions(+) rename docker-compose/examples/grafana/env/{fully.qualified.domain.name.example => fqdn_context.env.example} (96%) diff --git a/docker-compose/examples/grafana/docker-compose.yml b/docker-compose/examples/grafana/docker-compose.yml index 8be8499..c2fb650 100644 --- a/docker-compose/examples/grafana/docker-compose.yml +++ b/docker-compose/examples/grafana/docker-compose.yml @@ -5,6 +5,9 @@ services: networks: grafana-default: profiles: ["full", "grafana"] + depends_on: + nginx: + condition: service_healthy extends: file: common-settings.yml service: common-settings @@ -23,6 +26,12 @@ services: networks: grafana-default: profiles: ["full", "nginx"] + healthcheck: + test: ["CMD", "fping", "--count=1", "${GRAFANA_VIP}", "--period=500", "--quiet"] + interval: 3s + timeout: 1s + retries: 60 + start_period: 2s extends: file: common-settings.yml service: common-settings diff --git a/docker-compose/examples/grafana/env/fully.qualified.domain.name.example b/docker-compose/examples/grafana/env/fqdn_context.env.example similarity index 96% rename from docker-compose/examples/grafana/env/fully.qualified.domain.name.example rename to docker-compose/examples/grafana/env/fqdn_context.env.example index b482555..e7d7042 100644 --- a/docker-compose/examples/grafana/env/fully.qualified.domain.name.example +++ b/docker-compose/examples/grafana/env/fqdn_context.env.example @@ -6,6 +6,7 @@ CONTEXT=cncf # --- # GRAFANA_VERSION=x.y.z # NGINX_VERSION=x.y.z +# GRAFANA_VIP=10.1.1.2 diff --git a/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example b/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example index dd4646f..7604081 100644 --- a/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example +++ b/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example @@ -5,6 +5,7 @@ CONTEXT=fsf # Set something sensible here and uncomment # --- # VAULT_VERSION=x.y.z +# VAULT_VIP=10.1.1.2 diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml index 3be4ce4..f254c24 100644 --- a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml +++ b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml @@ -1,6 +1,15 @@ services: {%- if ',' in cookiecutter.__component_list_slug -%} {%- set components = cookiecutter.__component_list_slug.split(',') -%} +{%- set ns = namespace(found=false) -%} +{%- for component in components %} + {%- if loop.first -%} + {%- set ns.first_component = component -%} + {%- elif N is undefined -%} + {%- set ns.second_component = component -%} + {%- set N = 0 -%} + {%- endif -%} +{%- endfor -%} {%- for component in components %} {{ component }}: image: "{{ component }}:${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}" @@ -8,6 +17,18 @@ services: networks: {{ cookiecutter.__service_slug }}-default: profiles: ["full", "{{ component }}"] + {% if loop.first -%} + depends_on: + {{ ns.second_component }}: + condition: service_healthy + {%- else -%} + healthcheck: + test: ["CMD", "fping", "--count=1", "${% raw %}{{% endraw %}{{ ns.first_component.upper() }}_VIP{% raw %}}{% endraw %}", "--period=500", "--quiet"] + interval: 3s + timeout: 1s + retries: 60 + start_period: 2s + {%- endif %} extends: file: common-settings.yml service: common-settings diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example b/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example index fc0b853..969b44a 100644 --- a/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example +++ b/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example @@ -8,6 +8,11 @@ CONTEXT={{ cookiecutter.__context_slug }} {% for component in components %} # {{ component.upper() }}_VERSION=x.y.z {%- endfor %} +{%- for component in components %} +{%- if loop.first %} +# {{ component.upper() }}_VIP=10.1.1.2 +{%- endif %} +{%- endfor %} -- 2.47.2 From 7e2cce9c72ebedd77842165926213fad64c4c66b Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:50:42 +0200 Subject: [PATCH 06/12] refactor(docker-compose): Let's not commit a pyenv .python-version file --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 374ca1c..4c36e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,9 @@ # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 +# pyenv +.python-version + # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml -- 2.47.2 From 1e9e1136f0285b2e6babf4e6c9c8775d863e945c Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 22:51:51 +0200 Subject: [PATCH 07/12] docs(meta): H1 headlines all the way --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 137fa40..9a54f06 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,17 @@ Project directory structure templates for the Python Cookiecutter package. -## What's Cookiecutter? +# What's Cookiecutter? The Python package [Cookiecutter](https://github.com/cookiecutter/cookiecutter) assists in creating directory structure for whatever purpose you need such as for example a new Python project, an Ansible role or a `docker-compose` project - anything really that benefits from a unifirm reproducible directory structure. If you've ever wanted to put project structure best practices into version control then Cookiecutter's here to help. Cookiecutter is governed by so-called Cookiecutter templates, most of its magic inside Cookiecutter templates happens via the [Jinja2 template engine](https://palletsprojects.com/p/jinja/). You'll feel right at home if you're familiar with Ansible. -## Repo layout +# Repo layout Each subdirectory in this repo is a Cookiecutter template, you'll recognize them from their telltale `cookiecutter.json` files. Directories usually also have a readme file explaining more about each individual template. -## Get started +# Get started Get Cookiecutter like so: ``` -- 2.47.2 From c8e6465ee97aa5ae739af213c83cd5acf242e1b3 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 23:03:19 +0200 Subject: [PATCH 08/12] docs(meta): Add dev instructions --- README.md | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) diff --git a/README.md b/README.md index 9a54f06..6a60b02 100644 --- a/README.md +++ b/README.md @@ -57,3 +57,176 @@ The end result is a directory structure that has everything you need to hit the └── env └── fully.qualified.domain.name.example ``` + +# Developing + +To change Cookiecutter templates get yourself an environment then make, test and commit your changes. First things first, the environment. + +## Environment + +Get yourself a Python virtual environment. In this example we're assuming you're running a Linux operating system and you'll be using [pyenv](https://github.com/pyenv/pyenv) to manage virtual environments. + +### pyenv + +- Install pyenv with what they are calling their automatic installer. Feel free to also read up on pyenv on their [GitHub project page](https://github.com/pyenv/pyenv). + ``` + curl https://pyenv.run | bash + ``` + +- Following the installer's instruction add at least the following commands to your `~/.bashrc` file + ``` + export PYENV_ROOT="$HOME/.pyenv" + command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH" + eval "$(pyenv init -)" + ``` + +- You will also likely want to add this line which will make sure pyenv auto-activates venvs when you navigate into certain directories. More on that down at [venv](#venv). + ``` + eval "$(pyenv virtualenv-init -)" + ``` + +- Also make sure `~/.bashrc` gets loaded for example by including this in a `~/.bash_profile` file + ``` + [[ -f ~/.bashrc ]] && . ~/.bashrc + ``` + +- Reload `~/.bashrc` + ``` + source ~/.bashrc + ``` + +### Python + +- Update pyenv's package list + ``` + pyenv update + ``` +- Pick a Python version you like, for example copy-paste `3.11.4`: + ``` + pyenv install --list | less + + ... + 3.10.12 + 3.11.0 + 3.11-dev + 3.11.1 + 3.11.2 + 3.11.3 + 3.11.4 + 3.12.0b2 + 3.12-dev + 3.13-dev + ... + ``` +- Install Python, wait for compilation to finish on your machine + ``` + pyenv install 3.11.4 + ``` + +### Repo + +- Clone this repo + ``` + git clone https://quico.space/Quico/py-cookiecutter-templates.git ~/py-cookiecutter-templates + ``` + +### venv + +- Create a virtual environment where `3.11.4` is the Python version you want to use in this venv and `cookiecutter-3.11.4` is the name of your venv. Adding or dropping the Python version from your venv name comes down to personal preference. + ``` + pyenv virtualenv 3.11.4 cookiecutter-3.11.4 + ``` + +- In your repo path `~/py-cookiecutter-templates` create a `.python-version` file to tell pyenv to always activate your desired venv when inside this dir. + ``` + cd ~/py-cookiecutter-templates + pyenv local cookiecutter-3.11.4 + ``` + pyenv will immediately prefix your shell's `${PS1}` prompt with the venv name. + ``` + (cookiecutter-3.11.4) [✔ 23:19 user@machine py-cookiecutter-templates]$ + ``` + It will deactivate the venv and drop its prefix as soon as you navigate out of this dir. + ``` + (cookiecutter-3.11.4) [✔ 23:19 user@machine py-cookiecutter-templates]$ cd + [✔ 23:19 user@machine ~]$ + ``` + For now though stay in `~/py-cookiecutter-templates`, you're going to want to pip-install [cookiecutter](https://pypi.org/project/cookiecutter). + +- Upgrade `pip` + ``` + pip install --upgrade pip + ``` + +- Install [cookiecutter](https://pypi.org/project/cookiecutter) + ``` + pip install cookiecutter + ``` + +All done, your environment is set up. + +## Change + +Make some code changes, for example to the Docker Compose Cookiecutter template. When you're happy run your local Cookiecutter template to see how your changes are rendering. + +- Create `/tmp/cookiecutter-docker-compose` + ``` + mkdir '/tmp/cookiecutter-docker-compose' + ``` + +- Render a Docker Compose directory into your output directory, answer Cookiecutter's prompts: + ``` + # cookiecutter ~/py-cookiecutter-templates \ + --directory docker-compose \ + --output-dir /tmp/cookiecutter-docker-compose + + project_slug [dir-name]: mydir + service [mydir]: myservice + component_list [myservice]: mycomponent_one,mycomponent_two + context [ctx]: ux_novosibirsk + ``` + +- Observe that in `/tmp/cookiecutter-docker-compose` you now have your rendered Docker Compose dir: + ``` + # tree /tmp/cookiecutter-docker-compose + + /tmp/cookiecutter-docker-compose + └── mydir + ├── build-context + │   ├── mycomponent_one + │   │   ├── docker-data + │   │   ├── Dockerfile + │   │   └── extras + │   └── mycomponent_two + │   ├── docker-data + │   ├── Dockerfile + │   └── extras + ├── common-settings.yml + ├── docker-compose.override.yml + ├── docker-compose.yml + └── env + └── fqdn_context.env.example + ``` + +- For rapid testing you will most likely want to not type prompt answers repeatedly. Give them as command line arguments instead, also specify `--no-input` to suppress prompts: + ``` + cookiecutter ~/py-cookiecutter-templates \ + --no-input \ + --directory docker-compose \ + --output-dir /tmp/cookiecutter-docker-compose \ + project_slug=mydir \ + service=myservice \ + component_list=mycomponent_one,mycomponent_two \ + context=ux_novosibirsk + ``` + +## Commit prep + +When you're about ready to commit changes into this repo check the following bullet points. + +- Did you update the [Cookiecutter template README.md file](docker-compose/README.md), here for example for Docker Compose? + - Change in behavior? + - An updated example directory layout? + - Updated example file content? +- Did you commit a new completely rendered example directory structure into [docker-compose/examples](docker-compose/examples) dir? +- Did you change something that affects existing example directories? If so rerender them. -- 2.47.2 From 7fb2be86ee1d907cecfbd83c93deba7b8118836d Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 23:05:23 +0200 Subject: [PATCH 09/12] docs(meta): Better distiguish component_list entry examples --- docker-compose/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose/README.md b/docker-compose/README.md index 2869ead..1b2bd2c 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -66,7 +66,7 @@ Your four answers translate as follows into rendered files. └── grafana ... └── env - └── fully.qualified.domain.name.example <--- + └── fqdn_context.env.example <--- ``` Which then looks like: @@ -132,7 +132,7 @@ Consider Cookiecutter's project directory and rendered files a starting point. I 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): +_**This**_ will cause obvious issues (but the `image:` key is kinda correct): ``` services: infinispan/server: @@ -140,7 +140,7 @@ services: 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`): +_**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: -- 2.47.2 From 0daecee302cea9a33d098468629663bb94622e46 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 23:19:19 +0200 Subject: [PATCH 10/12] refactor(docker-compose): Slim down Docker bind mount directory structure --- docker-compose/examples/grafana/docker-compose.yml | 12 ++++++------ .../docker-compose.yml | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docker-compose/examples/grafana/docker-compose.yml b/docker-compose/examples/grafana/docker-compose.yml index c2fb650..21f7718 100644 --- a/docker-compose/examples/grafana/docker-compose.yml +++ b/docker-compose/examples/grafana/docker-compose.yml @@ -14,9 +14,9 @@ services: ports: # - "8080:80" volumes: - # - /opt/docker-data/grafana-grafana-${CONTEXT}/grafana/data/db:/usr/lib/grafana - # - /opt/docker-data/grafana-grafana-${CONTEXT}/grafana/data/logs:/var/log/grafana - # - /opt/docker-data/grafana-grafana-${CONTEXT}/grafana/config:/etc/grafana + # - /opt/docker-data/grafana-${CONTEXT}/grafana/data/db:/usr/lib/grafana + # - /opt/docker-data/grafana-${CONTEXT}/grafana/data/logs:/var/log/grafana + # - /opt/docker-data/grafana-${CONTEXT}/grafana/config:/etc/grafana environment: # GRAFANA_USER: ${GRAFANA_USER} # GRAFANA_PASSWORD: ${GRAFANA_PASSWORD} @@ -38,9 +38,9 @@ services: ports: # - "8080:80" volumes: - # - /opt/docker-data/grafana-nginx-${CONTEXT}/nginx/data/db:/usr/lib/nginx - # - /opt/docker-data/grafana-nginx-${CONTEXT}/nginx/data/logs:/var/log/nginx - # - /opt/docker-data/grafana-nginx-${CONTEXT}/nginx/config:/etc/nginx + # - /opt/docker-data/grafana-${CONTEXT}/nginx/data/db:/usr/lib/nginx + # - /opt/docker-data/grafana-${CONTEXT}/nginx/data/logs:/var/log/nginx + # - /opt/docker-data/grafana-${CONTEXT}/nginx/config:/etc/nginx environment: # NGINX_USER: ${NGINX_USER} # NGINX_PASSWORD: ${NGINX_PASSWORD} diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml index f254c24..e4ce915 100644 --- a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml +++ b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml @@ -35,9 +35,9 @@ services: ports: # - "8080:80" volumes: - # - /opt/docker-data/{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}/{{ component }}/data/db:/usr/lib/{{ component }} - # - /opt/docker-data/{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}/{{ component }}/data/logs:/var/log/{{ component }} - # - /opt/docker-data/{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}/{{ component }}/config:/etc/{{ component }} + # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ component }}/data/db:/usr/lib/{{ component }} + # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ component }}/data/logs:/var/log/{{ component }} + # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ component }}/config:/etc/{{ component }} environment: # {{ component.upper() }}_USER: ${% raw %}{{% endraw %}{{ component.upper() }}_USER{% raw %}}{% endraw %} # {{ component.upper() }}_PASSWORD: ${% raw %}{{% endraw %}{{ component.upper() }}_PASSWORD{% raw %}}{% endraw %} -- 2.47.2 From c871116f9f67b349e623aecb7397cdec8fb8bf49 Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Sun, 11 Jun 2023 23:19:49 +0200 Subject: [PATCH 11/12] refactor(docker-compose): Add a subnet to examples --- docker-compose/examples/grafana/docker-compose.yml | 2 +- .../examples/grafana/env/fqdn_context.env.example | 10 ++++++++++ .../examples/hashicorpvault/docker-compose.yml | 2 +- .../hashicorpvault/env/fqdn_context.env.example | 10 ++++++++++ .../docker-compose.yml | 2 +- .../env/fqdn_context.env.example | 10 ++++++++++ 6 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docker-compose/examples/grafana/docker-compose.yml b/docker-compose/examples/grafana/docker-compose.yml index 21f7718..73bfe39 100644 --- a/docker-compose/examples/grafana/docker-compose.yml +++ b/docker-compose/examples/grafana/docker-compose.yml @@ -53,4 +53,4 @@ networks: ipam: driver: default config: - # - subnet: 172.21.184.0/24 + - subnet: ${SUBNET} diff --git a/docker-compose/examples/grafana/env/fqdn_context.env.example b/docker-compose/examples/grafana/env/fqdn_context.env.example index e7d7042..cfec8dd 100644 --- a/docker-compose/examples/grafana/env/fqdn_context.env.example +++ b/docker-compose/examples/grafana/env/fqdn_context.env.example @@ -25,6 +25,16 @@ CONTEXT=cncf +# Subnet to use for this Docker Compose project. Docker defaults to +# container networks in prefix 172.16.0.0/12 which is 1 million addresses in +# the range from 172.16.0.0 to 172.31.255.255. Docker uses 172.17.0.0/16 for +# itself. Use any sensible prefix in 172.16.0.0/12 here except for Docker's +# own 172.17.0.0/16. +# --- +SUBNET=172.30.95.0/24 + + + # See 'docker-compose.override.yml' for how to make a variable available in # a Dockerfile # --- diff --git a/docker-compose/examples/hashicorpvault/docker-compose.yml b/docker-compose/examples/hashicorpvault/docker-compose.yml index 6e0ecf9..0d917e1 100644 --- a/docker-compose/examples/hashicorpvault/docker-compose.yml +++ b/docker-compose/examples/hashicorpvault/docker-compose.yml @@ -25,4 +25,4 @@ networks: ipam: driver: default config: - # - subnet: 172.21.184.0/24 + - subnet: ${SUBNET} diff --git a/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example b/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example index 7604081..b43af71 100644 --- a/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example +++ b/docker-compose/examples/hashicorpvault/env/fqdn_context.env.example @@ -24,6 +24,16 @@ CONTEXT=fsf +# Subnet to use for this Docker Compose project. Docker defaults to +# container networks in prefix 172.16.0.0/12 which is 1 million addresses in +# the range from 172.16.0.0 to 172.31.255.255. Docker uses 172.17.0.0/16 for +# itself. Use any sensible prefix in 172.16.0.0/12 here except for Docker's +# own 172.17.0.0/16. +# --- +SUBNET=172.30.95.0/24 + + + # See 'docker-compose.override.yml' for how to make a variable available in # a Dockerfile # --- diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml index e4ce915..9f203e8 100644 --- a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml +++ b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml @@ -70,4 +70,4 @@ networks: ipam: driver: default config: - # - subnet: 172.21.184.0/24 + - subnet: ${SUBNET} diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example b/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example index 969b44a..78f62a3 100644 --- a/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example +++ b/docker-compose/{{ cookiecutter.__project_slug }}/env/fqdn_context.env.example @@ -31,6 +31,16 @@ CONTEXT={{ cookiecutter.__context_slug }} +# Subnet to use for this Docker Compose project. Docker defaults to +# container networks in prefix 172.16.0.0/12 which is 1 million addresses in +# the range from 172.16.0.0 to 172.31.255.255. Docker uses 172.17.0.0/16 for +# itself. Use any sensible prefix in 172.16.0.0/12 here except for Docker's +# own 172.17.0.0/16. +# --- +SUBNET=172.30.95.0/24 + + + # See 'docker-compose.override.yml' for how to make a variable available in # a Dockerfile # --- -- 2.47.2 From 8b09465349e22e9b8ff08506905047be3f649ded Mon Sep 17 00:00:00 2001 From: hygienic-books Date: Mon, 12 Jun 2023 01:25:26 +0200 Subject: [PATCH 12/12] docs(docker-compose): Add example README Markdown file --- docker-compose/README.md | 12 ++- docker-compose/cookiecutter.json | 3 +- .../README.md | 80 +++++++++++++++++++ .../docker-compose.yml | 10 ++- 4 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 docker-compose/{{ cookiecutter.__project_slug }}/README.md diff --git a/docker-compose/README.md b/docker-compose/README.md index 1b2bd2c..18d5675 100644 --- a/docker-compose/README.md +++ b/docker-compose/README.md @@ -13,6 +13,10 @@ project_slug [dir-name]: grafana service [grafana]: component_list [grafana]: grafana,nginx context [ctx]: cncf +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. @@ -60,7 +64,7 @@ Your four answers translate as follows into rendered files. ... ``` -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 so it can't be empty. +4. The `context` prompt 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 so it can't be empty. ``` . └── grafana @@ -75,6 +79,12 @@ Your four answers translate as follows into rendered files. ... ``` +5. 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 diff --git a/docker-compose/cookiecutter.json b/docker-compose/cookiecutter.json index 07bc351..d4f1e8c 100644 --- a/docker-compose/cookiecutter.json +++ b/docker-compose/cookiecutter.json @@ -6,5 +6,6 @@ "component_list": "{{ cookiecutter.__service_slug }}", "__component_list_slug": "{{ cookiecutter.component_list.lower().replace(' ', '_').replace('-', '_') }}", "context": "ctx", - "__context_slug": "{{ cookiecutter.context.lower().replace(' ', '_').replace('-', '_') }}" + "__context_slug": "{{ cookiecutter.context.lower().replace(' ', '_').replace('-', '_') }}", + "build": ["no", "yes"] } diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/README.md b/docker-compose/{{ cookiecutter.__project_slug }}/README.md new file mode 100644 index 0000000..c395ae2 --- /dev/null +++ b/docker-compose/{{ cookiecutter.__project_slug }}/README.md @@ -0,0 +1,80 @@ +# {{ cookiecutter.__service_slug.capitalize() }} Docker Compose files + +Docker Compose files to spin up an instance of {{ cookiecutter.__service_slug.capitalize() }}. + +# How to run + +Add a `COMPOSE_ENV` file and save its location as a shell variable along with the location where this repo lives, here for example `/opt/containers/{{ cookiecutter.__project_slug }}` plus all other variables. At [env/fqdn_context.env.example](env/fqdn_context.env.example) you'll find an example environment file. + +When everything's ready start {{ cookiecutter.__service_slug.capitalize() }} with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first. + +## Environment +``` +export COMPOSE_DIR='/opt/containers/{{ cookiecutter.__project_slug }}' +export COMPOSE_CTX='{{ cookiecutter.__context_slug }}' +export COMPOSE_PROJECT='{{ cookiecutter.__service_slug }}-'"${COMPOSE_CTX}" +export COMPOSE_FILE="${COMPOSE_DIR}"'/docker-compose.yml'{% if cookiecutter.build == "yes" %} +export COMPOSE_OVERRIDE="${COMPOSE_DIR%/}"'/docker-compose.override.yml'{% endif %} +export COMPOSE_ENV= +``` + +{%- if cookiecutter.build == "yes" %} + +## Build + +``` +docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build' build +``` +{%- endif %} + +## Start + +``` +{%- if ',' in cookiecutter.__component_list_slug %} +docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' up --detach +{%- else %} +docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" up --detach +{%- endif %} +``` + +# Initial setup + +We're assuming you run Docker Compose workloads with ZFS-based bind mounts. ZFS management, creating a zpool and setting adequate properties for its datasets is out of scope of this document. + +## Datasets + +Create ZFS datasets and set permissions as needed. + +* Parent dateset + ``` + zfs create -o mountpoint=/opt/docker-data 'zpool/docker-data' + ``` + +* Container-specific datasets + ``` +{%- if ',' in cookiecutter.__component_list_slug -%} +{%- set components = cookiecutter.__component_list_slug.split(',') -%} +{%- for component in components %} + zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ component }}/data/db' + zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ component }}/data/logs' + zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ component }}/config' +{%- endfor -%} +{%- else %} + zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ cookiecutter.__service_slug }}/data/db' + zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ cookiecutter.__service_slug }}/data/logs' + zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ cookiecutter.__service_slug }}/config' +{%- endif %} + ``` + When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml). + +* Change ownership + ``` +{%- set components = cookiecutter.__component_list_slug.split(',') -%} +{% for component in components %} +{%- if loop.first %} + chown -R 1000:1000 '/opt/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ cookiecutter.__service_slug }}/data' +{%- endif %} +{%- endfor %} + ``` + +When done head back up to [How to run](#how-to-run). diff --git a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml index 9f203e8..0ed11c1 100644 --- a/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml +++ b/docker-compose/{{ cookiecutter.__project_slug }}/docker-compose.yml @@ -35,6 +35,8 @@ services: ports: # - "8080:80" volumes: + # When changing bind mount locations to real ones remember to + # also update "Initial setup" section in README.md. # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ component }}/data/db:/usr/lib/{{ component }} # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ component }}/data/logs:/var/log/{{ component }} # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ component }}/config:/etc/{{ component }} @@ -54,9 +56,11 @@ services: ports: # - "8080:80" volumes: - # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/data/db:/usr/lib/{{ cookiecutter.__service_slug }} - # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/data/logs:/var/log/{{ cookiecutter.__service_slug }} - # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/config:/etc/{{ cookiecutter.__service_slug }} + # When changing bind mount locations to real ones remember to + # also update "Initial setup" section in README.md. + # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ cookiecutter.__service_slug }}/data/db:/usr/lib/{{ cookiecutter.__service_slug }} + # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ cookiecutter.__service_slug }}/data/logs:/var/log/{{ cookiecutter.__service_slug }} + # - /opt/docker-data/{{ cookiecutter.__service_slug }}-${CONTEXT}/{{ cookiecutter.__service_slug }}/config:/etc/{{ cookiecutter.__service_slug }} environment: # {{ cookiecutter.__component_list_slug.upper() }}_USER: ${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_USER{% raw %}}{% endraw %} # {{ cookiecutter.__component_list_slug.upper() }}_PASSWORD: ${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_PASSWORD{% raw %}}{% endraw %} -- 2.47.2