Resolved multiple critical discovery system issues: ## Discovery System Fixes - Fixed console commands not being discovered on first run - Implemented fallback discovery for empty caches - Added context-aware caching with separate cache keys - Fixed object serialization preventing __PHP_Incomplete_Class ## Cache System Improvements - Smart caching that only caches meaningful results - Separate caches for different execution contexts (console, web, test) - Proper array serialization/deserialization for cache compatibility - Cache hit logging for debugging and monitoring ## Object Serialization Fixes - Fixed DiscoveredAttribute serialization with proper string conversion - Sanitized additional data to prevent object reference issues - Added fallback for corrupted cache entries ## Performance & Reliability - All 69 console commands properly discovered and cached - 534 total discovery items successfully cached and restored - No more __PHP_Incomplete_Class cache corruption - Improved error handling and graceful fallbacks ## Testing & Quality - Fixed code style issues across discovery components - Enhanced logging for better debugging capabilities - Improved cache validation and error recovery Ready for production deployment with stable discovery system. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
231 lines
7.3 KiB
YAML
231 lines
7.3 KiB
YAML
---
|
|
# Production Container Deployment Playbook
|
|
# Deploys pre-built container images for Custom PHP Framework
|
|
|
|
- name: Deploy Custom PHP Framework Application
|
|
hosts: web_servers
|
|
become: true
|
|
gather_facts: true
|
|
|
|
vars:
|
|
# Environment variable with proper fallback
|
|
deployment_env: "{{ deploy_environment | default('production') }}"
|
|
app_path: "/var/www/html"
|
|
backup_path: "/var/www/backups"
|
|
image_tag: "{{ IMAGE_TAG | default('latest') }}"
|
|
domain_name: "{{ DOMAIN_NAME | default('michaelschiemer.de') }}"
|
|
backup_enabled: "{{ BACKUP_ENABLED | default(true) | bool }}"
|
|
backup_retention_days: "{{ BACKUP_RETENTION_DAYS | default(30) }}"
|
|
cdn_update: "{{ CDN_UPDATE | default(false) | bool }}"
|
|
# Pfade für Templates/Compose relativ zum Playbook-Verzeichnis
|
|
compose_base_src: "{{ playbook_dir }}/../../../docker-compose.yml"
|
|
compose_overlay_src: "{{ playbook_dir }}/../../applications/docker-compose.{{ deployment_env }}.yml"
|
|
env_template_src: "{{ playbook_dir }}/../../applications/environments/.env.{{ deployment_env }}.template"
|
|
# Compose-Projektname: Standardmäßig Verzeichnisname von app_path (z. B. 'html')
|
|
compose_project: "{{ compose_project_name | default(app_path | basename) }}"
|
|
|
|
pre_tasks:
|
|
- name: Verify deployment requirements
|
|
assert:
|
|
that:
|
|
- app_path is defined
|
|
- domain_name is defined
|
|
- image_tag is defined
|
|
- image_tag != 'latest' or deployment_env != 'production'
|
|
fail_msg: "Production deployment requires specific image tag (not 'latest')"
|
|
tags: always
|
|
|
|
- name: Create required directories
|
|
ansible.builtin.file:
|
|
path: "{{ item }}"
|
|
state: directory
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0755'
|
|
loop:
|
|
- "{{ app_path }}"
|
|
- "{{ backup_path }}"
|
|
- /var/log/applications
|
|
tags: always
|
|
|
|
- name: Store current image tag for rollback
|
|
ansible.builtin.shell: |
|
|
if [ -f {{ app_path }}/.env.{{ deployment_env }} ]; then
|
|
grep '^IMAGE_TAG=' {{ app_path }}/.env.{{ deployment_env }} | cut -d'=' -f2 > {{ app_path }}/.last_release || echo 'none'
|
|
fi
|
|
ignore_errors: true
|
|
tags: backup
|
|
|
|
tasks:
|
|
- name: Check for existing deployment
|
|
ansible.builtin.stat:
|
|
path: "{{ app_path }}/docker-compose.yml"
|
|
register: existing_deployment
|
|
tags: deploy
|
|
|
|
- name: Render environment file from template
|
|
ansible.builtin.template:
|
|
src: "{{ env_template_src }}"
|
|
dest: "{{ app_path }}/.env.{{ deployment_env }}"
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0600'
|
|
backup: true
|
|
vars:
|
|
IMAGE_TAG: "{{ image_tag }}"
|
|
DOMAIN_NAME: "{{ domain_name }}"
|
|
# no_log: true # Disabled for debugging
|
|
tags: deploy
|
|
|
|
- name: Copy Docker Compose files (base + overlay)
|
|
ansible.builtin.copy:
|
|
src: "{{ item.src }}"
|
|
dest: "{{ app_path }}/{{ item.dest }}"
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0644'
|
|
loop:
|
|
- { src: "{{ compose_base_src }}", dest: "docker-compose.yml" }
|
|
- { src: "{{ compose_overlay_src }}", dest: "docker-compose.{{ deployment_env }}.yml" }
|
|
tags: deploy
|
|
|
|
- name: Stop existing services gracefully if present
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ app_path }}"
|
|
files:
|
|
- docker-compose.yml
|
|
- "docker-compose.{{ deployment_env }}.yml"
|
|
env_files:
|
|
- ".env.{{ deployment_env }}"
|
|
state: stopped
|
|
timeout: 60
|
|
when: existing_deployment.stat.exists
|
|
ignore_errors: true
|
|
tags: deploy
|
|
|
|
- name: Create storage volumes with proper permissions
|
|
ansible.builtin.file:
|
|
path: "{{ app_path }}/{{ item }}"
|
|
state: directory
|
|
owner: www-data
|
|
group: www-data
|
|
mode: '0775'
|
|
loop:
|
|
- storage
|
|
- storage/logs
|
|
- storage/cache
|
|
- var
|
|
- var/logs
|
|
- src/Framework/Cache/storage
|
|
- src/Framework/Cache/storage/cache
|
|
tags: deploy
|
|
|
|
- name: Deploy application with Docker Compose v2
|
|
community.docker.docker_compose_v2:
|
|
project_src: "{{ app_path }}"
|
|
files:
|
|
- docker-compose.yml
|
|
- "docker-compose.{{ deployment_env }}.yml"
|
|
env_files:
|
|
- ".env.{{ deployment_env }}"
|
|
pull: "always"
|
|
build: "never"
|
|
state: present
|
|
recreate: "auto"
|
|
remove_orphans: true
|
|
timeout: 300
|
|
tags: deploy
|
|
|
|
- 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"
|
|
)
|
|
tags: deploy
|
|
|
|
- name: Run database migrations
|
|
community.docker.docker_container_exec:
|
|
container: "{{ php_info.containers[0].Id }}"
|
|
command: php console.php db:migrate --force
|
|
chdir: /var/www/html
|
|
tags: deploy
|
|
|
|
- name: Clear application caches
|
|
community.docker.docker_container_exec:
|
|
container: "{{ php_info.containers[0].Id }}"
|
|
command: "php console.php {{ item }}"
|
|
chdir: /var/www/html
|
|
loop:
|
|
- cache:clear
|
|
- view:clear
|
|
ignore_errors: true
|
|
tags: deploy
|
|
|
|
- name: Wait for application to be ready
|
|
ansible.builtin.uri:
|
|
url: "https://{{ domain_name }}/health"
|
|
method: GET
|
|
status_code: 200
|
|
timeout: 30
|
|
headers:
|
|
User-Agent: "Mozilla/5.0 (Ansible Health Check)"
|
|
validate_certs: true
|
|
register: http_health
|
|
retries: 15
|
|
delay: 10
|
|
until: http_health.status == 200
|
|
tags: deploy
|
|
|
|
- name: Store successful deployment tag
|
|
ansible.builtin.copy:
|
|
content: "{{ image_tag }}"
|
|
dest: "{{ app_path }}/.last_successful_release"
|
|
owner: deploy
|
|
group: deploy
|
|
mode: '0644'
|
|
tags: deploy
|
|
|
|
post_tasks:
|
|
- name: Clean up old backups
|
|
ansible.builtin.find:
|
|
paths: "{{ backup_path }}"
|
|
age: "{{ backup_retention_days }}d"
|
|
file_type: directory
|
|
register: old_backups
|
|
when: backup_enabled
|
|
tags: cleanup
|
|
|
|
- name: Remove old backup directories
|
|
ansible.builtin.file:
|
|
path: "{{ item.path }}"
|
|
state: absent
|
|
loop: "{{ old_backups.files }}"
|
|
when: backup_enabled and old_backups.files is defined
|
|
tags: cleanup
|
|
|
|
- name: CDN update notification
|
|
ansible.builtin.debug:
|
|
msg: "CDN update would be executed here (run separate CDN playbook)"
|
|
when: cdn_update | default(false) | bool
|
|
tags: cdn
|
|
|
|
- name: Deployment success notification
|
|
ansible.builtin.debug:
|
|
msg:
|
|
- "Application deployment completed successfully"
|
|
- "Image Tag: {{ image_tag }}"
|
|
- "Environment: {{ deployment_env }}"
|
|
- "Domain: {{ domain_name }}"
|
|
- "CDN Updated: {{ cdn_update }}"
|
|
tags: always |