Files
michaelschiemer/deployment/ansible/playbooks/deploy-image.yml
Michael Schiemer 333dc04404
Some checks failed
Security Vulnerability Scan / Check for Dependency Changes (push) Successful in 33s
🚀 Build & Deploy Image / Build Runtime Base Image (push) Successful in 15s
🚀 Build & Deploy Image / Run Tests & Quality Checks (push) Has been skipped
Security Vulnerability Scan / Composer Security Audit (push) Has been skipped
🚀 Build & Deploy Image / Build Docker Image (push) Successful in 14s
🚀 Build & Deploy Image / Auto-deploy to Staging (push) Failing after 1m11s
🚀 Build & Deploy Image / Auto-deploy to Production (push) Has been skipped
🚀 Build & Deploy Image / Determine Build Necessity (push) Successful in 32s
fix: Improve registry check and image pull error handling
- Add registry_accessible flag to safely check registry status
- Fix 'argument of type bool is not iterable' error in when conditions
- Only pull image if registry is accessible
- Add ignore_errors to image pull task to prevent failures
- Improves handling of registry connectivity issues
2025-11-08 15:44:50 +01:00

156 lines
5.5 KiB
YAML

---
- name: Deploy Docker Image to Application Stack
hosts: "{{ deployment_hosts | default('production') }}"
gather_facts: yes
become: no
vars:
# Application code directory (where docker-compose files are located)
application_code_dest: "/home/deploy/michaelschiemer/current"
application_compose_suffix: >-
{%- if deployment_environment == 'staging' -%}
staging.yml
{%- else -%}
production.yml
{%- endif -%}
# Image to deploy (can be overridden via -e image_tag=...)
image_tag: "{{ image_tag | default('latest') }}"
docker_registry: "{{ docker_registry | default('registry.michaelschiemer.de') }}"
app_name_default: "framework"
# Deployment environment (staging or production)
deployment_environment: "{{ deployment_environment | default('production') }}"
tasks:
- name: Set app_name from provided value or default
ansible.builtin.set_fact:
app_name: "{{ app_name if (app_name is defined and app_name != '') else app_name_default }}"
- name: Set deploy_image from registry, app_name and tag
ansible.builtin.set_fact:
deploy_image: "{{ docker_registry }}/{{ app_name }}:{{ image_tag }}"
- name: Determine Docker registry password from vault or extra vars
ansible.builtin.set_fact:
registry_password: >-
{%- if docker_registry_password is defined and docker_registry_password | string | trim != '' -%}
{{ docker_registry_password }}
{%- elif vault_docker_registry_password is defined and vault_docker_registry_password | string | trim != '' -%}
{{ vault_docker_registry_password }}
{%- else -%}
{{ '' }}
{%- endif -%}
no_log: yes
- name: Check if registry is accessible
ansible.builtin.uri:
url: "https://{{ docker_registry }}/v2/"
method: GET
status_code: [200, 401]
timeout: 5
validate_certs: no
register: registry_check
ignore_errors: yes
delegate_to: "{{ inventory_hostname }}"
become: no
- name: Set registry accessible flag
ansible.builtin.set_fact:
registry_accessible: >-
{%- if registry_check.status is defined and registry_check.status | int in [200, 401] -%}
true
{%- else -%}
false
{%- endif -%}
- name: Login to Docker registry
community.docker.docker_login:
registry_url: "{{ docker_registry }}"
username: "{{ docker_registry_username | default('admin') }}"
password: "{{ registry_password }}"
when:
- registry_password | string | trim != ''
- registry_accessible | bool
no_log: yes
ignore_errors: yes
register: docker_login_result
- name: Pull Docker image
community.docker.docker_image:
name: "{{ deploy_image }}"
source: pull
pull: true
when: registry_accessible | bool
register: image_pull_result
ignore_errors: yes
failed_when: false
- name: Verify image exists locally
community.docker.docker_image_info:
name: "{{ deploy_image }}"
register: image_info
failed_when: image_info.failed | default(false)
- name: Update docker-compose file with new image tag
ansible.builtin.replace:
path: "{{ application_code_dest }}/docker-compose.{{ application_compose_suffix }}"
regexp: '^(\s+image:\s+)({{ docker_registry }}/{{ app_name }}:)(.*)$'
replace: '\1\2{{ image_tag }}'
register: compose_update_result
failed_when: false
changed_when: compose_update_result.changed | default(false)
- name: Update docker-compose file with new image (alternative pattern)
ansible.builtin.replace:
path: "{{ application_code_dest }}/docker-compose.{{ application_compose_suffix }}"
regexp: 'image:\s+{{ docker_registry }}/{{ app_name }}:.*'
replace: 'image: {{ deploy_image }}'
register: compose_update_alt
when: compose_update_result.changed == false
failed_when: false
changed_when: compose_update_alt.changed | default(false)
- name: Ensure Docker networks exist
community.docker.docker_network:
name: "{{ item }}"
state: present
loop:
- traefik-public
- app-internal
ignore_errors: yes
- name: Deploy application stack with new image
shell: |
cd {{ application_code_dest }}
docker compose -f docker-compose.base.yml -f docker-compose.{{ application_compose_suffix }} up -d --pull missing --force-recreate --remove-orphans
register: compose_deploy_result
changed_when: true
- name: Wait for containers to start
ansible.builtin.pause:
seconds: 15
- name: Check container status
shell: |
cd {{ application_code_dest }}
docker compose -f docker-compose.base.yml -f docker-compose.{{ application_compose_suffix }} ps
register: container_status
changed_when: false
- name: Display deployment summary
ansible.builtin.debug:
msg: |
========================================
Image Deployment Summary
========================================
Image: {{ deploy_image }}
Tag: {{ image_tag }}
Environment: {{ deployment_environment }}
Stack: {{ application_code_dest }}
Status: SUCCESS
========================================
Container Status:
{{ container_status.stdout | default('Not available') }}
========================================