My approach
A large environment leads to large compose and environment files which leads to all sorts of problems in terms of complexity, maintainability, readability, performance, scalability, security, privacy, and dependency management. My approach modularizes each environment, stack, and container into smaller chunks and manage them through a single, easy to use tool.
Key Features
- Modularized - Containers (and their files) are grouped into "environments" & "stacks"
- Organized - Stacks display and are controllable in Docker Desktop, Portainer, and other docker GUI management tools
- Easy to configure - When composing an environment, simply add/remove your "stack" name from stacks.txt to include/exclude a stack from being managed
- Easy to manage - Simply call a single script to build, teardown, start, stop, pause, etc individual or all environments and or stacks
- Security - Separates secrets from compose and environment files
- Privacy - Only allow git to see files you specify (useful only if you git push to a repo)
- Documented - Automatically documented - check out the documentation site
How To Use
Use /tools/compose.sh to perform any docker compose action (ex. up, down, start, restart, etc) on an environment, its stacks, and or its stack items
Some example commands
| Purpose | Example Command |
|---|---|
compose up all stacks in production environment |
compose.sh production up |
compose up the writing stack in production environment |
compose.sh production.writing up |
compose up ghost in the writing stack in production environment |
compose.sh production.writing.ghost up |
The examples above used the action up but you can use any docker compose action (ex. up, down, start, restart, etc).
For example, to restart all containers in the production environment writing stack:
You can also use the custom action rebuild to compose down and up.
For example, to compose down and up all containers in the production environment writing stack:
Prerequisites
- docker
- docker compose
- make
.shfiles in/toolsexecutable - ex.
chmod +x tools/*.sh
Configuration
- create your desired environment and optional environment .env
ex.
/environments/production
/environments/production/.env
- create any stacks and optional stack .env
ex.
/environments/production/writing
/environments/production/writing/.env
- optionally create and fill a stacks.txt (with ordered stack names, only used by
tools/compose.shwhen composing an entire environment)
ex.
/environments/production/stacks.txt
- create a compose file, optional environment file, and optional secrets file per container
ex.
/environments/production/writing/ghost.yml
/environments/production/writing/ghost.env
/environments/production/writing/ghost.secrets
- optionally, include any files you want git to see in
/.gitignore
compose files
To make my compose files more readable (and smaller in size / line count), I place commonly repeated lines in /environments/common-services.yml and reference with an extends keyword.
.env and .secrets
.env and .secrets are both environment files where .envstores non-sensitive data (ex. timezone) and .secrets stores sensitive data (ex. password).
You can have overlapping key names which are resolved in the following order (from most to least precendence):
- item .secrets (ex.
/environments/production/writing/ghost.secrets) - item .env (ex.
/environments/production/writing/ghost.env) - stack .env (ex.
/environments/production/writing/.env) - environment .env (ex.
/environments/production/.env) - environments .env (ex.
/environments/.env)
Variable Substitution
/tools/compose.sh will dynamically replace referenced variables in .env and .secrets. For example, let's say this is your environment .env file:
And media/something.env contains:
The final environment variables used to compose would be:
Example Secrets
/tools/compose.sh will automatically create a copy of every .secrets file, clear out the values (leaving key names), and add a .example extension. If you include these files in your /.gitignore, they can help others understand what secret variables are required without seeing your secret values.
stacks.txt
stacks.txt is a filter for /tools/compose.sh when composing an environment. Normally, all stacks will be processed in alphabetical order when composing an environment (ex. compose.sh production up, compose.sh production down, compose.sh production restart, etc).
But if you have a non-empty stacks.txt with valid stack names (1 per line), each stack will be composed in the ordered specified.
Troubleshooting
Traefik not serving SSL certs
Probably need to chmod 600 acme.json
s6-overlay-suexec: fatal: can only run as pid 1
if you see the error below and use /environments/common-services.yml, set the extends service to base or with_networks