--- - import_tasks: directories.yml - import_tasks: configs.yml - name: Pull Docker images one by one ansible.builtin.command: docker pull {{ item }} loop: - "{{ traefik_image }}" - "{{ forgejo_image }}" - "{{ forgejo_db_image }}" - "{{ plane_frontend_image }}" - "{{ plane_admin_image }}" - "{{ plane_space_image }}" - "{{ plane_backend_image }}" - "{{ plane_db_image }}" - "{{ plane_redis_image }}" - "{{ plane_minio_image }}" - "{{ act_runner_image }}" - "{{ node_exporter_image }}" - "{{ cadvisor_image }}" - "{{ promtail_image }}" - "{{ crowdsec_image }}" - "{{ outline_image }}" - "{{ outline_db_image }}" - "{{ outline_redis_image }}" - "{{ n8n_image }}" register: pull_result changed_when: "'Status: Downloaded newer image' in pull_result.stdout" retries: 5 delay: 30 until: pull_result.rc == 0 # ── UFW: allow tools Prometheus to scrape exporters on main ────────────────── - name: Allow tools server to scrape node-exporter community.general.ufw: rule: allow port: "9100" proto: tcp src: "{{ ip_tools }}" - name: Allow tools server to scrape cAdvisor community.general.ufw: rule: allow port: "8080" proto: tcp src: "{{ ip_tools }}" - name: Remove legacy SMTP relay UFW rule (port 1025) community.general.ufw: rule: allow port: "1025" proto: tcp src: "{{ ip_tools }}" delete: true failed_when: false - name: Deploy Docker Compose stack community.docker.docker_compose_v2: project_src: "{{ services_root }}" state: present pull: never remove_orphans: true retries: 3 delay: 15 register: compose_result until: compose_result is succeeded notify: Stack deployed - name: Wait for MinIO to be ready ansible.builtin.command: docker exec plane-minio curl -sf http://localhost:9000/minio/health/live register: minio_ready changed_when: false retries: 15 delay: 10 until: minio_ready.rc == 0 - name: Get plane-internal network name ansible.builtin.shell: > docker inspect plane-minio | python3 -c "import sys,json; d=json.load(sys.stdin)[0]; print([k for k in d['NetworkSettings']['Networks'] if 'plane-internal' in k][0])" register: plane_internal_network changed_when: false - name: Create MinIO uploads bucket via mc container # minio/mc entrypoint = mc, поэтому нужен --entrypoint sh # access-key = имя пользователя MinIO (plane-minio), secret-key = пароль ansible.builtin.shell: | docker run --rm \ --entrypoint sh \ --network "{{ plane_internal_network.stdout | trim }}" \ -e MC_ACCESS="{{ plane_minio_password }}" \ minio/mc:RELEASE.2025-05-21T01-59-54Z \ -c 'mc alias set local http://plane-minio:9000 plane-minio "{{ plane_minio_password }}" 2>/dev/null \ && mc mb --ignore-existing local/uploads \ && echo "Bucket created or already exists"' register: minio_bucket changed_when: "'Bucket created' in minio_bucket.stdout" retries: 5 delay: 10 until: minio_bucket.rc == 0 # ── Forgejo Discord webhooks (deploys → #deploys channel) ──────────────────── - name: Check Discord webhooks on Forgejo repos ansible.builtin.uri: url: "https://{{ domain_git }}/api/v1/repos/jack/{{ item }}/hooks" method: GET headers: Authorization: "token {{ forgejo_api_token }}" status_code: 200 register: forgejo_hooks failed_when: false changed_when: false loop: - infra - discord-bot - name: Create Discord webhook on Forgejo repos ansible.builtin.uri: url: "https://{{ domain_git }}/api/v1/repos/jack/{{ item.item }}/hooks" method: POST headers: Authorization: "token {{ forgejo_api_token }}" Content-Type: "application/json" body_format: json body: type: "discord" config: url: "{{ discord_webhook_deploys }}" content_type: "json" username: "Forgejo" icon_url: "" events: ["push", "create"] active: true status_code: 201 when: > item.status == 200 and (item.json | selectattr('type', 'eq', 'discord') | list | length == 0) loop: "{{ forgejo_hooks.results }}" loop_control: label: "{{ item.item }}"