infra/roles/services/tasks/main.yml
jack fde51352d7 feat: migrate monitoring to tools server, fix Outline S3 uploads
Monitoring stack (Prometheus, AlertManager, Grafana, Loki, Uptime Kuma)
moved from main to tools server. Prometheus now scrapes main exporters
over network (ip_main:9100/8080). Promtail pushes logs to ip_tools:3100.
Traefik routes for dash/status.walava.io updated to ip_tools. discord-bot
PROMETHEUS_URL updated to http://ip_tools:9090.

Outline S3 fix: remove AWS_S3_ACL=private (Timeweb doesn't support
per-object ACLs — caused upload failures). Add CORS configuration task
for browser-side presigned uploads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 04:10:28 +07:00

141 lines
4.2 KiB
YAML

---
- 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 }}"