The Stack Manager script helps you manage multiple stack environments by facilitating initialization, environment variable merging, Docker Compose file rendering, and managing stack deployment lifecycles. The Stack Manager provides commands for creating stack templates, merging environment variables, building and running stacks, and stopping them.
The Stack Manager script is implemented in shell rather than using other tools like Taskfile due to a specific bug in Taskfile's shell implementation. This bug affects the handling of associative arrays, making it necessary to use external shell scripting for reliability. Additionally, using shell provides greater flexibility for environment management tasks.
The gomplate templating tool is required for rendering configuration files. Please ensure it is installed before using the Stack Manager.
This setup allows for stack-specific customization, which often includes the need for templating environment variables and configuration files. The Stack Manager ensures that common and stack-specific settings can be easily managed and applied across different environments.
The init command initializes the environment setup by creating necessary directories, configuration files, and templates.
./stackman.sh init- Prompts:
- Application data directory (default:
app_data). - Stacks directory (default:
stacks).
- Application data directory (default:
- Creates:
app.conf: Configuration file containingAPP_DIRandSTACKS_DIRpaths..gitignore: Configured to ignore runtime directories (APP_DIRandSTACKS_DIR).global.env: Global environment variables template..stackignore: File to ignore certain stacks during operations.docker-compose.yml.tmpl: Default Docker Compose template for creating stack-specific configurations.
The create_template command generates a prototype directory in STACKS_DIR for a stack. The user can manually modify this directory before deployment.
./stackman.sh create_template -s <STACK>- Creates:
- Stack-specific design template directory in
STACKS_DIR. - Template files such as
.env.tmpl,docker-compose.yml.tmpl,.gitignore, andREADME.md.
- Stack-specific design template directory in
The merge command merges global.env variables into each stack's .env file.
./stackman.sh merge -s <STACK>- Global Variables: Reads all key-value pairs in
global.envinto an associative array,global_vars, excluding comments and empty lines. - Existing Stack Variables: Reads each line of the stack's
.envfile (OUTPUT_ENV) into an array,env_lines. - Backup: If
.envexists and--forceis set, a backup (.env.backup) is created. - Merge Process:
- Global Variables Addition: Appends all key-value pairs from
global.envto the top of the new.env, marking them as global. - Stack-Specific Variables: Iterates through
env_lines, preserving stack-specific entries. If a key in.envexists inglobal.env, it is commented out with#and noted as "Existed in global.env."
- Global Variables Addition: Appends all key-value pairs from
- No Nested Variable Expansion: Variables in
global.envthat reference others (e.g.,DOMAIN2=$DOMAIN) are not expanded. - Duplicate Keys: If
global.envand the stack.envfile share keys, the stack’s.envversion is retained and commented out. - No Live Updates: The merged
.envfile is static and reflects the state at merge time. Changes inglobal.envrequire re-runningmergefor updates.
The build command creates or updates the Docker Compose configuration (docker-compose.yml) and other stack-specific template files based on global.env and each stack's .env.
./stackman.sh build -s <STACK>- Environment Merge: Runs the
mergecommand to ensure the latest global and stack-specific environment variables are present in the stack’s.envfile. - Docker Compose Rendering:
- Checks if
docker-compose.yml.tmplexists in the stack directory. - If it exists and
docker-compose.ymldoes not, it usesgomplateto renderdocker-compose.ymlfromdocker-compose.yml.tmpl, substituting variables defined in.env. - The output file,
docker-compose.yml, contains resolved variables for Docker Compose to use directly.
- Checks if
- Data Template Rendering:
- If a
data.tmpldirectory exists, each.tmplfile within it is processed individually. gomplaterenders each.tmplfile, outputting the result into adatadirectory with the same filename but without the.tmplextension.- Variable substitution is based on values in
.env.
- If a
- Force Option:
- When
--forceis specified, it overwrites any existingdocker-compose.ymland rendered files indata/.
- When
- Static Rendering: Files are rendered at build time, so changes in
.envorglobal.envrequire re-runningbuildto updatedocker-compose.ymland data templates. - Missing Templates: If no
.envor template files are present,buildgenerates nothing but completes without errors, requiring correct setup beforehand. - Gomplate Not Tested: The use of
gomplatefor rendering has not been thoroughly tested in all use cases.
-
Run a Stack: Starts the Docker Compose services for a specific stack or all stacks that are not ignored.
./stackman.sh run -s <STACK>
-
Stop a Stack: Stops the running services for a specific stack or all stacks.
./stackman.sh stop -s <STACK>
The ignore command adds a stack to .stackignore, ensuring that it is ignored in future operations like merge, build, run, or stop.
./stackman.sh ignore -s <STACK>The list command lists all runtime stacks in APP_DIR, indicating whether each stack is ignored or not.
./stackman.sh listinit: Initializes directories, configuration files, and templates.create_template: Creates a prototype stack directory inSTACKS_DIR.merge: Merges global environment variables into each stack’s.envfile.build: Builds Docker Compose and other templates based on merged environment variables.run: Starts Docker Compose services for one or all stacks.stop: Stops running Docker Compose services.ignore: Adds a stack to.stackignoreto be ignored in operations.list: Lists all stacks inAPP_DIRand their ignore status.
# Initialize environment
./stackman.sh init
# Create a new stack template
./stackman.sh create_template -s my_stack
# Merge environment variables
./stackman.sh merge -s my_stack
# Build the stack
./stackman.sh build -s my_stack
# Run the stack
./stackman.sh run -s my_stack
# Stop the stack
./stackman.sh stop -s my_stack
# Ignore the stack
./stackman.sh ignore -s my_stack
# List all stacks
./stackman.sh list- Proxy Implementation:
- Implement a proxy setup with Authentik, Traefik, and Whoami to handle authentication and reverse proxy needs effectively.
- Per-Stack Customization:
- Implement per-stack customization using a Taskfile for managing stack-specific actions.
- Shell Script for Workaround: The customization logic uses a shell script instead of a Taskfile due to a bug with associative arrays in Taskfile's Go shell, making shell scripting a more reliable choice for this functionality.
- Static Environment Files:
- The
.envfiles can be modified manually and are dynamic in that sense. However, changes inglobal.envor the need for additional flexibility may require re-runningmergeor other commands to propagate updates.
- The
- Gomplate Not Tested:
- The use of
gomplatefor rendering templates has not been extensively tested and may need further validation in different environments.
- The use of
networks:
network1:
external: true
name: "${NETWORK_ID}"