11 KiB
Docker Compose App Role
A flexible Ansible role for deploying and managing Docker Compose applications with features including backup/restore and healthchecks.
Overview
This role provides a standardized way to deploy containerized applications using Docker Compose. It handles directory creation, template rendering, and container lifecycle management.
Features
- Template-based deployment with Jinja2 templating
- Dual backup system (controller + remote host)
- Health checks and deployment verification
- Multiple deployment modes (template, file, or inline content)
- Flexible directory management
- Configurable backup retention policies
Quick Start
1. Create a New Role
Use the provided script to create a new application skeleton role:
./create_app_role.sh my-app
This creates:
roles/my-app/
├── defaults/main.yml # Default variables
├── meta/main.yml # Role metadata and dependencies
└── templates/
└── compose.yml.j2 # Docker Compose template
2. Configure Your Application
Edit roles/my-app/defaults/main.yml:
---
app_role_name: my-app
my_app_container_name: "{{ app_name | default('my-app') }}"
my_app_container_version: latest
my_app_restart_policy: "{{ app_restart_policy }}"
my_app_http_port: 8080
my_app_data_path: "{{ app_dir }}/data"
my_app_config_path: "{{ app_dir }}/config"
# Optional: directories to create
app_subdirectories:
- "{{ my_app_data_path }}"
- "{{ my_app_config_path }}"
# Optional: backup configuration
app_backup_subdirectories:
- "{{ my_app_data_path }}"
- "{{ my_app_config_path }}"
3. Create Docker Compose Template
Edit roles/my-app/templates/compose.yml.j2:
---
services:
my-app:
image: "my-app:{{ my_app_container_version }}"
container_name: "{{ my_app_container_name }}"
restart: "{{ my_app_restart_policy }}"
ports:
- "{{ my_app_http_port }}:8080"
volumes:
- "{{ my_app_data_path }}:/data"
- "{{ my_app_config_path }}:/config"
environment:
- TZ={{ app_timezone | default('UTC') }}
4. Deploy Your Application
Add to your playbook:
---
- name: Deploy my application
hosts: localhost
roles:
- role: my-app
Advanced Usage
Backup and Restore
Create a New Backup
Create an on-demand backup using tags:
# Backup a specific application
ansible-playbook --tags backup playbook.yml
Configure backup retention and options in your role's meta vars:
# In roles/my-app/meta/main.yml
dependencies:
- role: docker_compose_app
vars:
app_backup_subdirectories:
- "{{ my_app_data_path }}"
- "{{ my_app_config_path }}"
app_backup_retention_days_controller: 90 # Keep backups for 90 days
app_backup_retention_days_remote: 7 # Keep remote backups for 7 days
app_backup_stop_services: true # Stop containers during backup
Automated Backups
For scheduled backups:
# Run daily backup at 2 AM - only runs backup tasks
0 2 * * * ansible-playbook -i inventory --tags backup my-playbook.yml
Tag-Based Execution
The role supports selective execution using tags:
# Setup only - doesn't start the containers
ansible-playbook --tags setup playbook.yml
# Full deployment - setup + start containers
ansible-playbook --tags deploy playbook.yml
# Restore and deploy
ansible-playbook --tags restore,deploy playbook.yml
# Backup only
ansible-playbook --tags backup playbook.yml
# Update only
ansible-playbook --tags update playbook.yml
# Backup then update
ansible-playbook --tags backup,update playbook.yml
Restore from Backup
Restore from the latest backup:
# Setup directories, restore from backup, then deploy
ansible-playbook --tags setup,restore,deploy playbook.yml
Configure restore options in your role's meta vars:
# In roles/my-app/meta/main.yml
dependencies:
- role: docker_compose_app
vars:
app_restore_source: controller # or 'remote'
app_restore_max_age_days: 30 # Only restore backups newer than 30 days
Restore from a specific archive by setting the variable at runtime:
ansible-playbook --tags restore playbook.yml \
-e app_restore_archive=/path/to/specific/backup-20240315-120000.tar.gz
Health Checks
Configure health monitoring:
- role: my-app
vars:
app_name: my-app
app_health_check: true
app_health_check_method: http
app_health_check_url: "http://localhost:8080/health"
app_health_check_retries: 30
app_health_check_delay: 10
Updates
Update application containers using tags:
# Update a specific application
ansible-playbook --tags update playbook.yml
# Update all applications in a playbook
ansible-playbook --tags update site.yml
Update process:
- Stops the application
- Pulls latest images for all services
- Recreates containers with new images
- Runs health checks (if enabled)
Rollbacks
Rollback using the restore functionality:
# First, create a backup then update
ansible-playbook --tags backup,update playbook.yml
# If update fails, rollback from backup
ansible-playbook --tags restore playbook.yml
Important Notes:
- Updates do NOT create automatic backups - create backups manually beforehand
- Rollbacks must be triggered manually using the restore functionality
- Using
latesttags prevents effective rollbacks since the old image is overwritten - For production, use specific version tags instead of
latest
Multiple Instances
Deploy multiple instances of the same application:
- role: jellyfin
vars:
app_name: jellyfin-movies
jellyfin_http_port: 8096
- role: jellyfin
vars:
app_name: jellyfin-tv
jellyfin_http_port: 8097
Custom Templates and Files
Override template location:
- role: my-app
vars:
app_compose_template: /path/to/custom/compose.yml.j2
Use a static compose file:
If you have an existing docker-compose.yml file that doesn't need templating:
- role: my-app
vars:
app_name: my-app
app_compose_file: /path/to/existing/docker-compose.yml
The file will be copied as-is to the application directory without Jinja2 processing.
Use inline content:
- role: docker_compose_app
vars:
app_name: simple-app
app_role_name: simple-app
app_compose_content: |
services:
app:
image: nginx:alpine
ports:
- "80:80"
Configuration Reference
Core Variables
| Variable | Default | Description |
|---|---|---|
app_name |
Required | Unique application instance name |
role_name |
Required | Role name for template paths |
app_dir |
{{ host_root_path }}/{{ app_name }} |
Application directory |
app_uid |
{{ ansible_facts.user_uid }} |
File ownership UID |
app_gid |
{{ ansible_facts.user_gid }} |
File ownership GID |
app_permission_mode |
"0640" |
File permission mode |
Deployment Options
| Variable | Default | Description |
|---|---|---|
app_compose_template |
{{ app_templates_path }}/compose.yml.j2 |
Template file path |
app_compose_file |
- | Static compose file path |
app_compose_content |
- | Inline compose content |
app_compose_validate |
true |
Validate compose syntax |
app_compose_pull |
policy |
Image pull strategy |
app_compose_recreate |
auto |
Container recreate strategy |
Backup Configuration
| Variable | Default | Description |
|---|---|---|
app_backup_subdirectories |
[] |
Specific directories to backup |
app_backup_stop_services |
true |
Stop containers during backup |
app_backup_retention_days_controller |
90 |
Controller backup retention |
app_backup_retention_days_remote |
7 |
Remote backup retention |
Restore Configuration
| Variable | Default | Description |
|---|---|---|
app_restore_source |
controller |
Restore source (controller/remote) |
app_restore_archive |
- | Specific archive file to restore (overrides latest) |
app_restore_max_age_days |
30 |
Maximum backup age for restore (when finding latest) |
Health Check Configuration
| Variable | Default | Description |
|---|---|---|
app_health_check |
true |
Enable health checks |
app_health_check_method |
docker |
Check method (docker/http) |
app_health_check_url |
- | HTTP endpoint for health check |
app_health_check_retries |
30 |
Number of check retries |
app_health_check_delay |
10 |
Delay between checks (seconds) |
app_health_check_status_codes |
[200, 201, 202] |
Valid HTTP status codes |
Directory Management
| Variable | Default | Description |
|---|---|---|
app_subdirectories |
[] |
Directories to create in app_dir |
app_extra_templates |
[] |
Additional templates to render |
Example app_extra_templates:
app_extra_templates:
- src: config.json.j2
dest: "{{ app_dir }}/config/app.json"
- src: env.j2
dest: "{{ app_dir }}/.env"
Best Practices
- Use semantic versioning for container tags instead of
latest - Test restore procedures regularly to ensure backups are valid
- Use specific directories for backups instead of entire app directory
- Monitor disk usage on backup storage locations
Architecture
The role is organized into logical task files for selective execution:
├── setup.yaml # Validation, directories, and templates
├── restore.yaml # Backup restoration logic
├── deploy.yaml # Docker Compose deployment and startup
├── health_check.yaml # Health monitoring and verification
├── backup.yaml # Backup creation and management
├── update.yaml # Container update and image pulling
└── manage_compose.yaml # Docker Compose lifecycle management
Task Execution Flow
-
Setup (
setup.yaml) - [setup, deploy]- Docker/Compose validation
- Variable validation and security checks
- Directory creation
- Additional template deployment
-
Restore (
restore.yaml) - [restore, never]- Backup file selection and validation
- Service stopping
- Archive extraction
- Service restart
-
Deploy (
deploy.yaml) - [deploy]- Docker Compose file creation
- Container startup and management
-
Health Check (
health_check.yaml) - [deploy, healthcheck]- Service health verification
- Endpoint monitoring
-
Backup (
backup.yaml) - [backup, never]- Service stopping (optional)
- Archive creation
- Backup copying and cleanup
- Service restart
-
Update (
update.yaml) - [update, never]- Service stopping
- Image pulling
- Container recreation
- Health verification
Each task file is designed to be idempotent and can be run multiple times safely.