- Change FileCache CACHE_PATH from relative to absolute path - Change FileCacheCleaner cache folder to absolute path - Resolves read-only file system issue in production containers - Cache now uses writable /var/www/html/storage/cache location
235 lines
7.2 KiB
YAML
235 lines
7.2 KiB
YAML
---
|
|
# Application Rollback Playbook
|
|
# Rolls back to a specific image tag using container deployment
|
|
---
|
|
# Rollback Playbook: setzt IMAGE_TAG zurück und recreatet Services
|
|
|
|
- name: Rollback Custom PHP Framework Application
|
|
hosts: web_servers
|
|
become: true
|
|
gather_facts: false
|
|
|
|
vars:
|
|
app_path: "/var/www/html"
|
|
domain_name: "{{ DOMAIN_NAME | default('michaelschiemer.de') }}"
|
|
rollback_tag: "{{ ROLLBACK_TAG | default('') }}"
|
|
compose_project: "{{ compose_project_name | default(app_path | basename) }}"
|
|
|
|
pre_tasks:
|
|
- name: Validate ROLLBACK_TAG is provided
|
|
ansible.builtin.fail:
|
|
msg: "Setze ROLLBACK_TAG auf ein gültiges Image-Tag."
|
|
when: rollback_tag | length == 0
|
|
|
|
tasks:
|
|
- name: Ensure environment file exists
|
|
ansible.builtin.stat:
|
|
path: "{{ app_path }}/.env.{{ environment }}"
|
|
register: env_file
|
|
|
|
- name: Fail if environment file is missing
|
|
ansible.builtin.fail:
|
|
msg: "Environment-Datei fehlt: {{ app_path }}/.env.{{ environment }}"
|
|
when: not env_file.stat.exists
|
|
|
|
- name: Write IMAGE_TAG to env file
|
|
ansible.builtin.lineinfile:
|
|
path: "{{ app_path }}/.env.{{ environment }}"
|
|
regexp: '^IMAGE_TAG='
|
|
line: "IMAGE_TAG={{ rollback_tag }}"
|
|
create: no
|
|
backrefs: false
|
|
mode: "0600"
|
|
|
|
- name: Recreate services with rollback tag
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ app_path }}"
|
|
files:
|
|
- docker-compose.yml
|
|
- "docker-compose.{{ environment }}.yml"
|
|
env_files:
|
|
- ".env.{{ environment }}"
|
|
pull: false
|
|
build: false
|
|
state: present
|
|
recreate: smart
|
|
remove_orphans: true
|
|
timeout: 300
|
|
|
|
- name: Wait for PHP container to be healthy (label-based)
|
|
community.docker.docker_container_info:
|
|
filters:
|
|
label:
|
|
- "com.docker.compose.service=php"
|
|
- "com.docker.compose.project={{ compose_project }}"
|
|
register: php_info
|
|
retries: 20
|
|
delay: 10
|
|
until: php_info.containers is defined and
|
|
(php_info.containers | length) > 0 and
|
|
(
|
|
(php_info.containers[0].State.Health is defined and php_info.containers[0].State.Health.Status == "healthy")
|
|
or
|
|
php_info.containers[0].State.Status == "running"
|
|
)
|
|
|
|
- name: Verify application HTTP health
|
|
ansible.builtin.uri:
|
|
url: "https://{{ domain_name }}/health"
|
|
method: GET
|
|
status_code: 200
|
|
timeout: 30
|
|
validate_certs: true
|
|
register: http_health
|
|
retries: 15
|
|
delay: 10
|
|
until: http_health.status == 200
|
|
|
|
post_tasks:
|
|
- name: Rollback completed
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "Rollback erfolgreich"
|
|
- "Neues aktives Image-Tag: {{ rollback_tag }}"
|
|
- name: Rollback Custom PHP Framework Application
|
|
hosts: web_servers
|
|
become: true
|
|
gather_facts: true
|
|
|
|
vars:
|
|
app_path: "/var/www/html"
|
|
rollback_tag: "{{ ROLLBACK_TAG | mandatory }}"
|
|
domain_name: "{{ DOMAIN_NAME | default('michaelschiemer.de') }}"
|
|
environment: "{{ ENV | default('production') }}"
|
|
|
|
pre_tasks:
|
|
- name: Verify rollback requirements
|
|
assert:
|
|
that:
|
|
- rollback_tag is defined
|
|
- rollback_tag != ''
|
|
- rollback_tag != 'latest'
|
|
fail_msg: "Rollback requires specific ROLLBACK_TAG (not 'latest')"
|
|
tags: always
|
|
|
|
- name: Check if target tag exists locally
|
|
community.docker.docker_image_info:
|
|
name: "{{ project_name | default('michaelschiemer') }}:{{ rollback_tag }}"
|
|
register: rollback_image_info
|
|
ignore_errors: true
|
|
tags: always
|
|
|
|
- name: Pull rollback image if not available locally
|
|
community.docker.docker_image:
|
|
name: "{{ project_name | default('michaelschiemer') }}:{{ rollback_tag }}"
|
|
source: pull
|
|
force_source: true
|
|
when: rollback_image_info.images | length == 0
|
|
tags: always
|
|
|
|
- name: Store current deployment for emergency recovery
|
|
shell: |
|
|
if [ -f {{ app_path }}/.env.{{ environment }} ]; then
|
|
grep '^IMAGE_TAG=' {{ app_path }}/.env.{{ environment }} | cut -d'=' -f2 > {{ app_path }}/.emergency_recovery_tag || echo 'none'
|
|
fi
|
|
tags: backup
|
|
|
|
tasks:
|
|
- name: Update environment with rollback tag
|
|
template:
|
|
src: "{{ environment }}.env.template"
|
|
dest: "{{ app_path }}/.env.{{ environment }}"
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0600'
|
|
backup: true
|
|
vars:
|
|
IMAGE_TAG: "{{ rollback_tag }}"
|
|
DOMAIN_NAME: "{{ domain_name }}"
|
|
no_log: true
|
|
tags: rollback
|
|
|
|
- name: Stop current services
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ app_path }}"
|
|
files:
|
|
- docker-compose.yml
|
|
- "docker-compose.{{ environment }}.yml"
|
|
env_files:
|
|
- ".env.{{ environment }}"
|
|
state: stopped
|
|
timeout: 120
|
|
tags: rollback
|
|
|
|
- name: Deploy rollback version
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ app_path }}"
|
|
files:
|
|
- docker-compose.yml
|
|
- "docker-compose.{{ environment }}.yml"
|
|
env_files:
|
|
- ".env.{{ environment }}"
|
|
pull: "never" # Use local image
|
|
build: "never"
|
|
state: present
|
|
recreate: "always" # Force recreate for rollback
|
|
timeout: 300
|
|
tags: rollback
|
|
|
|
- name: Wait for containers to be healthy after rollback
|
|
community.docker.docker_container_info:
|
|
name: "{{ item }}"
|
|
register: container_info
|
|
retries: 15
|
|
delay: 10
|
|
until: container_info.container.State.Health.Status == "healthy" or container_info.container.State.Status == "running"
|
|
loop:
|
|
- "{{ ansible_hostname }}_php_1"
|
|
- "{{ ansible_hostname }}_web_1"
|
|
- "{{ ansible_hostname }}_db_1"
|
|
- "{{ ansible_hostname }}_redis_1"
|
|
ignore_errors: true
|
|
tags: rollback
|
|
|
|
- name: Verify application health after rollback
|
|
uri:
|
|
url: "https://{{ domain_name }}/health"
|
|
method: GET
|
|
status_code: 200
|
|
timeout: 30
|
|
headers:
|
|
User-Agent: "Mozilla/5.0 (Ansible Rollback Check)"
|
|
validate_certs: true
|
|
retries: 10
|
|
delay: 15
|
|
tags: rollback
|
|
|
|
- name: Update successful rollback tag
|
|
copy:
|
|
content: "{{ rollback_tag }}"
|
|
dest: "{{ app_path }}/.last_successful_release"
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0644'
|
|
tags: rollback
|
|
|
|
post_tasks:
|
|
- name: Rollback success notification
|
|
debug:
|
|
msg:
|
|
- "Application rollback completed successfully"
|
|
- "Rolled back to: {{ rollback_tag }}"
|
|
- "Environment: {{ environment }}"
|
|
- "Domain: {{ domain_name }}"
|
|
- "Emergency recovery tag stored for further rollback if needed"
|
|
tags: always
|
|
|
|
- name: Log rollback event
|
|
lineinfile:
|
|
path: "{{ app_path }}/rollback.log"
|
|
line: "{{ ansible_date_time.iso8601 }} - Rollback to {{ rollback_tag }} from {{ environment }} completed successfully"
|
|
create: true
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0644'
|
|
tags: always |