--- # Ansible Playbook: Update Production Deployment # Purpose: Pull new Docker image and update services with zero-downtime # Usage: Called by Gitea Actions or manual deployment - name: Update Production Services with New Image hosts: production_server become: no vars: image_tag: "{{ image_tag | default('latest') }}" git_commit_sha: "{{ git_commit_sha | default('unknown') }}" deployment_timestamp: "{{ deployment_timestamp | default(ansible_date_time.iso8601) }}" registry_url: "git.michaelschiemer.de:5000" image_name: "framework" stack_name: "framework" tasks: - name: Log deployment start debug: msg: | 🚀 Starting deployment Image: {{ registry_url }}/{{ image_name }}:{{ image_tag }} Commit: {{ git_commit_sha }} Time: {{ deployment_timestamp }} - name: Pull new Docker image docker_image: name: "{{ registry_url }}/{{ image_name }}" tag: "{{ image_tag }}" source: pull force_source: yes register: image_pull retries: 3 delay: 5 until: image_pull is succeeded - name: Tag image as latest locally docker_image: name: "{{ registry_url }}/{{ image_name }}:{{ image_tag }}" repository: "{{ registry_url }}/{{ image_name }}" tag: latest source: local - name: Update web service with rolling update docker_swarm_service: name: "{{ stack_name }}_web" image: "{{ registry_url }}/{{ image_name }}:{{ image_tag }}" force_update: yes update_config: parallelism: 1 delay: 10s failure_action: rollback monitor: 30s max_failure_ratio: 0.3 rollback_config: parallelism: 1 delay: 5s state: present register: web_update - name: Update queue-worker service docker_swarm_service: name: "{{ stack_name }}_queue-worker" image: "{{ registry_url }}/{{ image_name }}:{{ image_tag }}" force_update: yes update_config: parallelism: 1 delay: 10s failure_action: rollback state: present register: worker_update - name: Wait for services to stabilize pause: seconds: 20 - name: Verify service status shell: | docker service ps {{ stack_name }}_web --filter "desired-state=running" --format "{{`{{.CurrentState}}`}}" | head -1 register: service_state changed_when: false - name: Check if deployment succeeded fail: msg: "Service deployment failed: {{ service_state.stdout }}" when: "'Running' not in service_state.stdout" - name: Get running replicas count shell: | docker service ls --filter "name={{ stack_name }}_web" --format "{{`{{.Replicas}}`}}" register: replicas changed_when: false - name: Record deployment in history copy: content: | Deployment: {{ deployment_timestamp }} Image: {{ registry_url }}/{{ image_name }}:{{ image_tag }} Commit: {{ git_commit_sha }} Status: SUCCESS Replicas: {{ replicas.stdout }} dest: "/home/deploy/deployments/{{ image_tag }}.log" mode: '0644' - name: Display deployment summary debug: msg: | ✅ Deployment completed successfully Image: {{ registry_url }}/{{ image_name }}:{{ image_tag }} Commit: {{ git_commit_sha }} Web Service: {{ web_update.changed | ternary('UPDATED', 'NO CHANGE') }} Worker Service: {{ worker_update.changed | ternary('UPDATED', 'NO CHANGE') }} Replicas: {{ replicas.stdout }} Time: {{ deployment_timestamp }} handlers: - name: Cleanup old images shell: docker image prune -af --filter "until=72h" changed_when: false