Files
gh-basher83-lunar-claude-pl…/skills/ansible-best-practices/examples/02-infisical-secrets/docker-deployment.yml
2025-11-29 18:00:24 +08:00

212 lines
7.4 KiB
YAML

---
# =============================================================================
# Docker Deployment with Infisical Secrets
# =============================================================================
# This playbook demonstrates best practices from Virgo-Core:
# - Infisical secrets management (using reusable task)
# - Proper error handling with changed_when/failed_when
# - Idempotent command execution
# - No secrets in logs (no_log: true)
# - Fully qualified module names (FQCN)
# - Task organization with blocks
- name: Deploy Docker application with secrets from Infisical
hosts: docker_hosts
become: true
gather_facts: true
vars:
app_name: "my-application"
app_dir: "/opt/{{ app_name }}"
infisical_project_id: "7b832220-24c0-45bc-a5f1-ce9794a31259"
infisical_env: "prod"
infisical_path: "/doggos-cluster"
# ==========================================================================
# Pre-flight Checks
# ==========================================================================
pre_tasks:
- name: Validate required variables
ansible.builtin.assert:
that:
- app_name is defined and app_name | length > 0
- app_dir is defined
- infisical_project_id is defined
fail_msg: "Required variables not set"
success_msg: "All required variables present"
tags: [always]
- name: Check if Docker is installed
ansible.builtin.command: which docker
register: docker_check
changed_when: false
failed_when: false
tags: [always]
- name: Fail if Docker not installed
ansible.builtin.fail:
msg: |
Docker is not installed on {{ inventory_hostname }}
Please install Docker first: sudo apt install docker.io
when: docker_check.rc != 0
tags: [always]
# ==========================================================================
# Main Tasks
# ==========================================================================
tasks:
# ========================================================================
# Retrieve Secrets from Infisical
# ========================================================================
- name: Secrets Management Block
block:
- name: Retrieve database password from Infisical
ansible.builtin.include_tasks: ../../tasks/infisical-secret-lookup.yml
vars:
secret_name: 'DB_PASSWORD'
secret_var_name: 'db_password'
fallback_env_var: 'DB_PASSWORD' # Optional fallback
- name: Retrieve API key from Infisical
ansible.builtin.include_tasks: ../../tasks/infisical-secret-lookup.yml
vars:
secret_name: 'API_KEY'
secret_var_name: 'api_key'
fallback_env_var: 'API_KEY'
- name: Retrieve Redis password from Infisical
ansible.builtin.include_tasks: ../../tasks/infisical-secret-lookup.yml
vars:
secret_name: 'REDIS_PASSWORD'
secret_var_name: 'redis_password'
fallback_env_var: 'REDIS_PASSWORD'
tags: [secrets, config]
# ========================================================================
# Application Setup
# ========================================================================
- name: Application Deployment Block
block:
- name: Create application directory
ansible.builtin.file:
path: "{{ app_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Deploy application configuration
ansible.builtin.template:
src: app-config.yml.j2
dest: "{{ app_dir }}/config.yml"
owner: root
group: root
mode: '0600' # Secure permissions for config with secrets
notify: Restart application
no_log: true # Config contains secrets
- name: Deploy Docker Compose file
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ app_dir }}/docker-compose.yml"
owner: root
group: root
mode: '0644'
rescue:
- name: Report deployment failure
ansible.builtin.fail:
msg: "Failed to deploy application configuration"
tags: [deploy, config]
# ========================================================================
# Docker Operations (with proper idempotency)
# ========================================================================
- name: Docker Management Block
block:
- name: Check if container is already running
ansible.builtin.command: docker ps --filter name={{ app_name }} --format "{{ '{{' }}.Names{{ '}}' }}"
register: container_check
changed_when: false
failed_when: false
- name: Pull Docker images
ansible.builtin.command: docker-compose -f {{ app_dir }}/docker-compose.yml pull
args:
chdir: "{{ app_dir }}"
register: pull_result
changed_when: "'Downloaded newer image' in pull_result.stdout"
when: container_check.stdout != app_name
- name: Start Docker containers
ansible.builtin.command: docker-compose -f {{ app_dir }}/docker-compose.yml up -d
args:
chdir: "{{ app_dir }}"
register: compose_up
changed_when: "'Creating' in compose_up.stderr or 'Starting' in compose_up.stderr"
when: container_check.stdout != app_name
- name: Wait for application to be healthy
ansible.builtin.uri:
url: "http://localhost:8080/health"
status_code: 200
register: health_check
until: health_check.status == 200
retries: 30
delay: 10
changed_when: false
rescue:
- name: Show container logs on failure
ansible.builtin.command: docker-compose -f {{ app_dir }}/docker-compose.yml logs --tail=50
args:
chdir: "{{ app_dir }}"
register: container_logs
changed_when: false
- name: Report Docker failure
ansible.builtin.fail:
msg: |
Docker deployment failed
Logs: {{ container_logs.stdout }}
tags: [deploy, docker]
# ========================================================================
# Verification
# ========================================================================
- name: Verify application is running
ansible.builtin.command: docker ps --filter name={{ app_name }} --filter status=running --format "{{ '{{' }}.Status{{ '}}' }}"
register: running_check
changed_when: false
failed_when: "'Up' not in running_check.stdout"
tags: [verify]
- name: Report deployment success
ansible.builtin.debug:
msg: |
✓ Application deployed successfully
Container: {{ app_name }}
Status: {{ running_check.stdout }}
Health endpoint: http://{{ inventory_hostname }}:8080/health
tags: [verify]
# ==========================================================================
# Handlers
# ==========================================================================
handlers:
- name: Restart application
ansible.builtin.command: docker-compose -f {{ app_dir }}/docker-compose.yml restart
args:
chdir: "{{ app_dir }}"
changed_when: true