--- - name: Prüfe erforderliche Variablen assert: that: - deploy_root is defined - deploy_user is defined fail_msg: "Erforderliche Variablen fehlen: deploy_root und/oder deploy_user nicht definiert" success_msg: "Alle erforderlichen Variablen sind korrekt definiert" tags: [always] - name: Projektverzeichnisse erstellen file: path: "{{ item }}" state: directory owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0755' loop: - "{{ deploy_root }}" - "{{ deploy_root }}/ssl" - "{{ deploy_root }}/public" - "{{ deploy_root }}/src" - "{{ deploy_root }}/docker" - name: SSL-Zertifikate prüfen stat: path: "/etc/letsencrypt/live/{{ app_domain }}/fullchain.pem" register: ssl_certs - name: SSL-Zertifikate kopieren (falls vorhanden) copy: src: "{{ item.src }}" dest: "{{ item.dest }}" remote_src: yes owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' loop: - { src: "/etc/letsencrypt/live/{{ app_domain }}/fullchain.pem", dest: "{{ deploy_root }}/ssl/fullchain.pem" } - { src: "/etc/letsencrypt/live/{{ app_domain }}/privkey.pem", dest: "{{ deploy_root }}/ssl/privkey.pem" } when: ssl_certs.stat.exists - name: Lokales public-Verzeichnis prüfen stat: path: "{{ playbook_dir }}/../../public" register: public_dir delegate_to: localhost become: false - name: public-Verzeichnis synchronisieren synchronize: src: "{{ playbook_dir }}/../../public/" dest: "{{ deploy_public }}/" delete: yes recursive: yes when: public_dir.stat.exists and public_dir.stat.isdir - name: Lokale docker-compose.yml Datei prüfen stat: path: "{{ playbook_dir }}/../../docker-compose.yml" register: docker_compose_file delegate_to: localhost become: false - name: Projekt-Stammdaten kopieren copy: src: "{{ playbook_dir }}/../../docker-compose.yml" dest: "{{ deploy_root }}/docker-compose.yml" owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' when: docker_compose_file.stat.exists - name: .env-Datei prüfen stat: path: "{{ project_root }}/.env" register: env_file delegate_to: localhost become: false - name: .env kopieren (falls vorhanden) copy: src: "{{ project_root }}/.env" dest: "{{ deploy_root }}/.env" owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' when: env_file.stat.exists - name: Erstelle Standard-.env-Datei, wenn keine existiert copy: dest: "{{ deploy_root }}/.env" content: | COMPOSE_PROJECT_NAME=michaelschiemer owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' when: not env_file.stat.exists - name: Lokales src-Verzeichnis prüfen stat: path: "{{ playbook_dir }}/../../src" register: src_dir delegate_to: localhost become: false - name: Quellcode synchronisieren synchronize: src: "{{ playbook_dir }}/../../src/" dest: "{{ deploy_root }}/src/" delete: yes recursive: yes when: src_dir.stat.exists and src_dir.stat.isdir - name: Docker-Verzeichnis prüfen stat: path: "{{ project_root }}/docker" register: docker_dir delegate_to: localhost become: false - name: Docker-Configs synchronisieren (falls vorhanden) synchronize: src: "{{ project_root }}/docker/" dest: "{{ deploy_root }}/docker/" delete: yes recursive: yes when: docker_dir.stat.exists - name: Rechte im Zielverzeichnis korrigieren file: path: "{{ deploy_root }}" state: directory owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0755' recurse: yes # Cache-Verzeichnis für UID/GID 1000 (z.B. appuser im Container) - name: Stelle Schreibrechte für Cache-Verzeichnis her file: path: "{{ deploy_root }}/cache" state: directory owner: 1000 group: 1000 mode: '0775' recurse: yes - name: Erstelle .env-Datei für Docker Compose copy: dest: "{{ deploy_root }}/.env" content: | COMPOSE_PROJECT_NAME=michaelschiemer APP_ENV=production APP_PORT=80 APP_SSL_PORT=443 COMPOSER_INSTALL_FLAGS=--no-dev --optimize-autoloader owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' when: not env_file.stat.exists - name: Prüfe docker-compose.yml im project_root stat: path: "{{ project_root }}/docker-compose.yml" register: compose_file delegate_to: localhost become: false - name: Docker-Compose-Konfiguration für Deployment anpassen copy: dest: "{{ deploy_root }}/docker-compose-deploy.yml" content: | version: '3.8' services: php: build: context: {{ deploy_root }}/docker/php dockerfile: Dockerfile-simple volumes: - {{ deploy_root }}/src:/var/www/html/src:rw - {{ deploy_root }}/public:/var/www/html/public:rw networks: - backend nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - {{ deploy_root }}/public:/var/www/html/public:ro - {{ deploy_root }}/docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - {{ deploy_root }}/docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro depends_on: - php networks: - frontend - backend redis: image: redis:alpine networks: - cache networks: frontend: backend: cache: owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' - name: Stelle sicher, dass die Nginx-Verzeichnisstruktur korrekt ist file: path: "{{ deploy_root }}/docker/nginx" state: directory mode: '0755' - name: Bereinige nginx.conf Verzeichnis falls es existiert shell: | if [ -d "{{ deploy_root }}/docker/nginx/nginx.conf" ]; then rm -rf "{{ deploy_root }}/docker/nginx/nginx.conf" fi args: executable: /bin/bash ignore_errors: yes - name: Erstelle Dockerfile für Nginx copy: dest: "{{ deploy_root }}/docker/nginx/Dockerfile" content: | FROM nginx:alpine # Konfigurationen kopieren COPY nginx.conf /etc/nginx/nginx.conf COPY default.conf /etc/nginx/conf.d/default.conf # Erstelle Verzeichnis für SSL RUN mkdir -p /etc/nginx/ssl # Starte nginx im Vordergrund CMD ["nginx", "-g", "daemon off;"] mode: '0644' - name: Docker-Compose-Datei für Deployment anpassen (PHP Dockerfile) replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: 'dockerfile: docker/php/Dockerfile' replace: 'dockerfile: {{ deploy_root }}/docker/php/Dockerfile' --- # App Deployment Tasks - name: Prüfe erforderliche Variablen assert: that: - deploy_root is defined - deploy_user is defined fail_msg: "Erforderliche Variablen fehlen: deploy_root und/oder deploy_user nicht definiert" success_msg: "Alle erforderlichen Variablen sind korrekt definiert" tags: [always] - name: Projektverzeichnisse erstellen file: path: "{{ item }}" state: directory owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0755' loop: - "{{ deploy_root }}" - "{{ deploy_root }}/ssl" - "{{ deploy_root }}/public" - "{{ deploy_root }}/src" - "{{ deploy_root }}/docker" - name: Erstelle einfache Test-HTML-Datei copy: dest: "{{ deploy_root }}/public/index.html" content: | App ist aktiv

Anwendung ist aktiv!

Diese Seite bestätigt, dass das App-Deployment erfolgreich war.

Server: {{ inventory_hostname }}

mode: '0644' owner: "{{ deploy_user }}" group: "{{ deploy_user }}" - name: Docker-Compose-Datei für Deployment anpassen (Nginx Context) replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: 'context: docker/nginx' replace: 'context: {{ deploy_root }}/docker/nginx' - name: Docker-Volumes in docker-compose.yml anpassen (korrigiert) replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: '(\s+-)?\s+\./(.+?)(?::cached|:delegated)?(?::rw|:ro)?$' replace: '\1 {{ deploy_root }}/\2' with_items: - volumes - volume - name: Docker-Volumes für Redis anpassen replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: '\./docker/redis/redis.conf' replace: '{{ deploy_root }}/docker/redis/redis.conf' - name: Korrigiere spezielle Volume-Optionen (cached, delegated) replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: '{{ deploy_root }}/([^:]+):cached' replace: '{{ deploy_root }}/\1:rw' - name: Korrigiere spezielle Volume-Optionen (delegated) replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: '{{ deploy_root }}/([^:]+):delegated' replace: '{{ deploy_root }}/\1:rw' - name: Finde und korrigiere ungültige Volume-Spezifikationen shell: | sed -i 's|{{ deploy_root }}/var/www/html:|{{ deploy_root }}:|g' {{ deploy_root }}/docker-compose-deploy.yml sed -i 's|:cached:rw|:rw|g' {{ deploy_root }}/docker-compose-deploy.yml sed -i 's|:delegated:rw|:rw|g' {{ deploy_root }}/docker-compose-deploy.yml cat {{ deploy_root }}/docker-compose-deploy.yml | grep -A 20 volumes args: chdir: "{{ deploy_root }}" register: volume_debug - name: Erstelle einfache Docker Compose-Datei als Fallback copy: dest: "{{ deploy_root }}/docker-compose-simple.yml" content: | version: '3.8' services: php: build: context: {{ deploy_root }}/docker/php dockerfile: Dockerfile-simple volumes: - {{ deploy_root }}/src:/var/www/html/src:rw - {{ deploy_root }}/public:/var/www/html/public:rw networks: - backend nginx: image: nginx:alpine ports: - "80:80" - "443:443" volumes: - {{ deploy_root }}/public:/var/www/html/public:ro - {{ deploy_root }}/docker/nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - php networks: - frontend - backend redis: image: redis:alpine networks: - cache networks: frontend: backend: cache: owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' - name: Erstelle composer.lock-Datei wenn diese nicht existiert file: path: "{{ deploy_root }}/composer.lock" state: touch owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' register: composer_lock_created - name: Prüfe ob Dockerfile existiert stat: path: "{{ project_root }}/docker/php/Dockerfile" register: dockerfile_exists delegate_to: localhost become: false - name: Erstelle angepasste Dockerfile für PHP copy: dest: "{{ deploy_root }}/docker/php/Dockerfile-deploy" content: | FROM php:8.4-fpm RUN apt-get update && apt-get install -y \ git \ unzip \ libzip-dev \ zip \ && docker-php-ext-install zip pdo pdo_mysql \ && docker-php-ext-install opcache \ && docker-php-ext-install pcntl posix shmop \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /var/www/html # Kopiere Projektdateien COPY . /var/www/html/ # Stelle sicher, dass der Webserver Zugriff auf Dateien hat RUN chown -R www-data:www-data /var/www/html CMD ["php-fpm"] owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' # Task entfernt, da wir jetzt direkt eine vollständige Dockerfile erstellen # und nicht mehr eine vorhandene Datei anpassen müssen - name: Erstelle vereinfachte Dockerfile für PHP copy: dest: "{{ deploy_root }}/docker/php/Dockerfile-simple" content: | FROM php:8.4-fpm RUN apt-get update && apt-get install -y \ git \ unzip \ libzip-dev \ zip \ && docker-php-ext-install zip pdo pdo_mysql \ && docker-php-ext-install opcache \ && docker-php-ext-install pcntl posix shmop \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* WORKDIR /var/www/html # Kein Composer-Befehl hier CMD ["php-fpm"] owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' - name: Docker-Compose-Datei anpassen um die modifizierte Dockerfile zu verwenden replace: path: "{{ deploy_root }}/docker-compose-deploy.yml" regexp: 'dockerfile: {{ deploy_root }}/docker/php/Dockerfile' replace: 'dockerfile: {{ deploy_root }}/docker/php/Dockerfile-simple' - name: Erstelle composer.json für Docker-Build copy: dest: "{{ deploy_root }}/composer.json" content: | { "name": "michaelschiemer/website", "description": "Michael Schiemer Website", "type": "project", "require": { "php": "^8.1" }, "minimum-stability": "stable" } owner: "{{ deploy_user }}" group: "{{ deploy_user }}" mode: '0644' - name: Debug-Info für Docker Compose debug: msg: "Versuche, Container zu starten mit Docker Compose-Datei: {{ deploy_root }}/docker-compose-simple.yml" - name: Zeige Docker Images shell: docker images register: docker_images ignore_errors: yes - name: Docker Images anzeigen debug: var: docker_images.stdout_lines - name: Zeige laufende Docker Container shell: docker ps -a register: docker_containers ignore_errors: yes - name: Docker Container anzeigen debug: var: docker_containers.stdout_lines - name: Docker Compose Container stoppen shell: | cd {{ deploy_root }} && \ docker-compose -f {{ deploy_root }}/docker-compose-simple.yml -p michaelschiemer down --remove-orphans || true args: chdir: "{{ deploy_root }}" environment: COMPOSE_IGNORE_ORPHANS: "True" - name: Prüfe ob docker-compose-simple.yml existiert stat: path: "{{ deploy_root }}/docker-compose-simple.yml" register: simple_compose_file - name: Anzeigen des Inhalts der docker-compose-simple.yml Datei shell: cat {{ deploy_root }}/docker-compose-simple.yml register: compose_content when: simple_compose_file.stat.exists - name: Anzeigen des Inhalts der docker-compose-simple.yml Datei debug: var: compose_content.stdout_lines when: compose_content is defined - name: Verzeichnisse in nginx Docker Verzeichnis anzeigen shell: "ls -la {{ deploy_root }}/docker/nginx" register: nginx_dir_content - name: Nginx Verzeichnisinhalt anzeigen debug: var: nginx_dir_content.stdout_lines - name: Stoppe alle Docker Container shell: | cd {{ deploy_root }} && \ docker-compose -f {{ deploy_root }}/docker-compose-simple.yml -p michaelschiemer down --remove-orphans args: chdir: "{{ deploy_root }}" ignore_errors: yes environment: COMPOSE_IGNORE_ORPHANS: "True" - name: Bereinige Docker-Systemressourcen shell: docker system prune -f ignore_errors: yes - name: Docker Compose neu bauen und starten (vereinfachte Version) shell: | cd {{ deploy_root }} && \ export DOCKER_BUILDKIT=0 && \ docker-compose -f {{ deploy_root }}/docker-compose-simple.yml -p michaelschiemer up -d --build args: chdir: "{{ deploy_root }}" ignore_errors: yes environment: COMPOSE_IGNORE_ORPHANS: "True" - name: Warte kurz bis Docker-Container gestartet sind pause: seconds: 5 - name: Prüfe welche Prozesse an Port 80 gebunden sind shell: | netstat -tulpn | grep LISTEN | grep ':80' || echo "Kein Prozess an Port 80 gebunden" register: port_80_check ignore_errors: yes - name: Zeige Port 80 Bindung debug: var: port_80_check.stdout_lines - name: Prüfe Docker-Container Netzwerkeinstellungen shell: | docker inspect michaelschiemer-nginx-1 | grep -A 20 "NetworkSettings" || echo "Container nicht gefunden" register: container_network ignore_errors: yes - name: Zeige Container-Netzwerkeinstellungen debug: var: container_network.stdout_lines - name: PHP-Container für Composer starten shell: docker-compose -f {{ deploy_root }}/docker-compose-simple.yml -p michaelschiemer up -d php args: chdir: "{{ deploy_root }}" - name: Kurze Wartezeit bis PHP-Container bereit wait_for: timeout: 5 - name: Composer Abhängigkeiten installieren (deaktiviert) debug: msg: "Composer-Installation übersprungen - keine PHP-Anwendung vorhanden" register: composer_result - name: Composer-Ergebnis anzeigen debug: var: composer_result.stdout_lines when: composer_result.stdout is defined - name: Composer-Fehler anzeigen debug: var: composer_result.stderr_lines when: composer_result.stderr is defined