415 lines
11 KiB
Markdown
415 lines
11 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
./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`:
|
|
|
|
```yaml
|
|
---
|
|
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`:
|
|
|
|
```yaml
|
|
---
|
|
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:
|
|
|
|
```yaml
|
|
---
|
|
- 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:
|
|
|
|
```bash
|
|
# Backup a specific application
|
|
ansible-playbook --tags backup playbook.yml
|
|
```
|
|
|
|
Configure backup retention and options in your role's meta vars:
|
|
|
|
```yaml
|
|
# 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:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# Setup directories, restore from backup, then deploy
|
|
ansible-playbook --tags setup,restore,deploy playbook.yml
|
|
```
|
|
|
|
Configure restore options in your role's meta vars:
|
|
|
|
```yaml
|
|
# 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:
|
|
|
|
```bash
|
|
ansible-playbook --tags restore playbook.yml \
|
|
-e app_restore_archive=/path/to/specific/backup-20240315-120000.tar.gz
|
|
```
|
|
|
|
### Health Checks
|
|
|
|
Configure health monitoring:
|
|
|
|
```yaml
|
|
- 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:
|
|
|
|
```bash
|
|
# Update a specific application
|
|
ansible-playbook --tags update playbook.yml
|
|
|
|
# Update all applications in a playbook
|
|
ansible-playbook --tags update site.yml
|
|
```
|
|
|
|
**Update process:**
|
|
1. Stops the application
|
|
2. Pulls latest images for all services
|
|
3. Recreates containers with new images
|
|
4. Runs health checks (if enabled)
|
|
|
|
|
|
### Rollbacks
|
|
|
|
Rollback using the restore functionality:
|
|
|
|
```bash
|
|
# 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 `latest` tags 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:
|
|
|
|
```yaml
|
|
- 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:
|
|
|
|
```yaml
|
|
- 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:
|
|
|
|
```yaml
|
|
- 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:
|
|
|
|
```yaml
|
|
- 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`:
|
|
```yaml
|
|
app_extra_templates:
|
|
- src: config.json.j2
|
|
dest: "{{ app_dir }}/config/app.json"
|
|
- src: env.j2
|
|
dest: "{{ app_dir }}/.env"
|
|
```
|
|
|
|
|
|
## Best Practices
|
|
|
|
1. **Use semantic versioning** for container tags instead of `latest`
|
|
2. **Test restore procedures** regularly to ensure backups are valid
|
|
3. **Use specific directories** for backups instead of entire app directory
|
|
4. **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
|
|
|
|
1. **Setup** (`setup.yaml`) - [setup, deploy]
|
|
- Docker/Compose validation
|
|
- Variable validation and security checks
|
|
- Directory creation
|
|
- Additional template deployment
|
|
|
|
2. **Restore** (`restore.yaml`) - [restore, never]
|
|
- Backup file selection and validation
|
|
- Service stopping
|
|
- Archive extraction
|
|
- Service restart
|
|
|
|
3. **Deploy** (`deploy.yaml`) - [deploy]
|
|
- Docker Compose file creation
|
|
- Container startup and management
|
|
|
|
4. **Health Check** (`health_check.yaml`) - [deploy, healthcheck]
|
|
- Service health verification
|
|
- Endpoint monitoring
|
|
|
|
5. **Backup** (`backup.yaml`) - [backup, never]
|
|
- Service stopping (optional)
|
|
- Archive creation
|
|
- Backup copying and cleanup
|
|
- Service restart
|
|
|
|
6. **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. |