From 0139aa79e715d9ba7ae2f3dede0ebff177b10e54 Mon Sep 17 00:00:00 2001 From: OG T Date: Sat, 11 Apr 2026 02:47:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(infra):=20B-1=20Ansible=20Host=20IaC=20?= =?UTF-8?q?=E9=AA=A8=E6=9E=B6=E5=AE=8C=E6=95=B4=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - roles/nginx/templates/188-all-sites.conf.j2: 8 個服務 Jinja2 模板 - roles/docker-compose-service/tasks/main.yml: 通用 Docker Compose role - roles/swap/tasks/main.yml: swap2.img 管理 role (110 專用) - roles/pm2-service/tasks/main.yml: PM2 process 狀態確認 role - .gitea/workflows/ansible-lint.yml: infra/ansible/** 異動自動 lint Sprint B-1 完成: Git = 唯一真相 (Host IaC 骨架) Co-Authored-By: Claude Sonnet 4.6 --- .gitea/workflows/ansible-lint.yml | 22 +++ infra/ansible/inventory/group_vars/all.yml | 20 ++ .../ansible/inventory/group_vars/host_110.yml | 44 +++++ .../ansible/inventory/group_vars/host_188.yml | 43 +++++ infra/ansible/inventory/hosts.yml | 40 ++++ infra/ansible/playbooks/110-devops.yml | 172 ++++++++++++++++++ infra/ansible/playbooks/188-ai-web.yml | 135 ++++++++++++++ infra/ansible/playbooks/nginx-sync.yml | 56 ++++++ infra/ansible/playbooks/site.yml | 16 ++ .../docker-compose-service/tasks/main.yml | 18 ++ infra/ansible/roles/nginx/tasks/main.yml | 16 ++ .../nginx/templates/188-all-sites.conf.j2 | 145 +++++++++++++++ .../ansible/roles/pm2-service/tasks/main.yml | 22 +++ infra/ansible/roles/swap/tasks/main.yml | 35 ++++ 14 files changed, 784 insertions(+) create mode 100644 .gitea/workflows/ansible-lint.yml create mode 100644 infra/ansible/inventory/group_vars/all.yml create mode 100644 infra/ansible/inventory/group_vars/host_110.yml create mode 100644 infra/ansible/inventory/group_vars/host_188.yml create mode 100644 infra/ansible/inventory/hosts.yml create mode 100644 infra/ansible/playbooks/110-devops.yml create mode 100644 infra/ansible/playbooks/188-ai-web.yml create mode 100644 infra/ansible/playbooks/nginx-sync.yml create mode 100644 infra/ansible/playbooks/site.yml create mode 100644 infra/ansible/roles/docker-compose-service/tasks/main.yml create mode 100644 infra/ansible/roles/nginx/tasks/main.yml create mode 100644 infra/ansible/roles/nginx/templates/188-all-sites.conf.j2 create mode 100644 infra/ansible/roles/pm2-service/tasks/main.yml create mode 100644 infra/ansible/roles/swap/tasks/main.yml diff --git a/.gitea/workflows/ansible-lint.yml b/.gitea/workflows/ansible-lint.yml new file mode 100644 index 00000000..5c913104 --- /dev/null +++ b/.gitea/workflows/ansible-lint.yml @@ -0,0 +1,22 @@ +name: Ansible Lint + +on: + push: + paths: + - 'infra/ansible/**' + pull_request: + paths: + - 'infra/ansible/**' + +jobs: + lint: + runs-on: self-hosted + steps: + - uses: actions/checkout@v4 + + - name: Install ansible-lint + run: pip install ansible-lint + + - name: Run ansible-lint + run: ansible-lint infra/ansible/playbooks/ + working-directory: ${{ github.workspace }} diff --git a/infra/ansible/inventory/group_vars/all.yml b/infra/ansible/inventory/group_vars/all.yml new file mode 100644 index 00000000..31d763f0 --- /dev/null +++ b/infra/ansible/inventory/group_vars/all.yml @@ -0,0 +1,20 @@ +--- +# AWOOOI Ansible — 共用變數 +# 所有主機適用的基礎設定 + +# 時區 +timezone: "Asia/Taipei" + +# 共用 SSH 用戶 +ansible_ssh_common_args: "-o StrictHostKeyChecking=no -o ConnectTimeout=10" + +# sudoers NOPASSWD (CD 用,see ADR-034) +sudo_password: "{{ vault_sudo_password }}" + +# Harbor Registry +harbor_url: "harbor.wooo.work" +harbor_namespace: "awoooi" + +# 網路 +nginx_vip: "192.168.0.200" +k3s_vip: "192.168.0.125" diff --git a/infra/ansible/inventory/group_vars/host_110.yml b/infra/ansible/inventory/group_vars/host_110.yml new file mode 100644 index 00000000..9ef921f2 --- /dev/null +++ b/infra/ansible/inventory/group_vars/host_110.yml @@ -0,0 +1,44 @@ +--- +# AWOOOI Ansible — 192.168.0.110 (DevOps 金庫) 專用變數 + +# Swap 設定 +swap_files: + - path: /swap.img + size_mb: 3896 # 3.8GB (現有) + - path: /swap2.img + size_mb: 4096 # 4GB (Sprint A 新增) + +# Docker Compose 服務 (在 /opt/ 下) +docker_compose_services: + harbor: + dir: /opt/harbor + service: "" # 全部服務 + expected_port: 5000 + sentry: + dir: /opt/sentry + service: "" + expected_port: 9000 + gitea: + dir: /opt/gitea + service: "" + expected_port: 3001 + langfuse: + dir: /opt/langfuse + service: "" + expected_port: 3100 + +# bitan pharmacy (Docker) +bitan_dir: /home/wooo/apps/bitan-pharmacy +bitan_port: 3003 + +# wooo-aiops frontend (PM2, port 3000) +wooo_aiops_dir: /home/wooo/apps/wooo-aiops +wooo_aiops_pm2_name: wooo-aiops + +# GitHub Runners +github_runner_count: 5 + +# keepalived +keepalived_role: BACKUP +keepalived_priority: 90 +keepalived_vip: "192.168.0.200" diff --git a/infra/ansible/inventory/group_vars/host_188.yml b/infra/ansible/inventory/group_vars/host_188.yml new file mode 100644 index 00000000..e8c56631 --- /dev/null +++ b/infra/ansible/inventory/group_vars/host_188.yml @@ -0,0 +1,43 @@ +--- +# AWOOOI Ansible — 192.168.0.188 (AI+Web 中心) 專用變數 + +# Docker Compose 服務 +docker_compose_services: + openclaw: + dir: /opt/openclaw + expected_port: 8088 + tsenyang: + dir: /opt/tsenyang-website + expected_port: 3000 + momo: + dir: /opt/momo-app + expected_port: 5003 + signoz: + dir: /opt/signoz + expected_port: 3301 + minio: + dir: /opt/minio + expected_port: 9000 + litellm: + dir: /opt/litellm + expected_port: 4000 + n8n: + dir: /opt/n8n + expected_port: 5678 + open_webui: + dir: /opt/open-webui + expected_port: 3010 + docker_registry: + dir: /opt/docker-registry + expected_port: 5001 + +# Nginx +nginx_conf_dir: /etc/nginx/sites-enabled +nginx_main_conf: all-sites.conf +# 無 gitlab block(Sprint A 已清除) + +# keepalived +keepalived_role: MASTER +keepalived_priority: 100 +keepalived_vip: "192.168.0.200" +keepalived_interface: "ens18" # 調整為實際網卡名稱 diff --git a/infra/ansible/inventory/hosts.yml b/infra/ansible/inventory/hosts.yml new file mode 100644 index 00000000..6a44e954 --- /dev/null +++ b/infra/ansible/inventory/hosts.yml @@ -0,0 +1,40 @@ +--- +# AWOOOI Ansible Inventory +# Sprint B — Host IaC +# 建立時間: 2026-04-11 (台北時區) +# 建立者: Claude Sonnet 4.6 — Sprint B-1 + +all: + children: + devops: + hosts: + host_110: + ansible_host: 192.168.0.110 + ansible_user: wooo + ansible_ssh_private_key_file: "~/.ssh/id_ed25519" + + ai_web: + hosts: + host_188: + ansible_host: 192.168.0.188 + ansible_user: ollama + ansible_ssh_private_key_file: "~/.ssh/id_ed25519" + + k3s_masters: + hosts: + host_120: + ansible_host: 192.168.0.120 + ansible_user: wooo + ansible_ssh_private_key_file: "~/.ssh/id_ed25519" + host_121: + ansible_host: 192.168.0.121 + ansible_user: wooo + ansible_ssh_private_key_file: "~/.ssh/id_ed25519" + + security: + hosts: + host_112: + ansible_host: 192.168.0.112 + ansible_user: wooo + ansible_ssh_private_key_file: "~/.ssh/id_ed25519" + ansible_skip_tags: "all" # 預留,本次不執行 diff --git a/infra/ansible/playbooks/110-devops.yml b/infra/ansible/playbooks/110-devops.yml new file mode 100644 index 00000000..43ed0c4d --- /dev/null +++ b/infra/ansible/playbooks/110-devops.yml @@ -0,0 +1,172 @@ +--- +# AWOOOI Ansible — 192.168.0.110 DevOps 金庫完整狀態描述 +# 執行: ansible-playbook -i inventory/hosts.yml playbooks/110-devops.yml +# +# 預期狀態: +# swap: 8GB (swap.img 3.8G + swap2.img 4G) +# harbor: running (docker compose, port 5000) +# sentry: running (docker compose, 0 restarting) +# gitea: running (port 3001) +# langfuse: running (port 3100) +# bitan: running docker (port 3003) +# wooo-aiops: running PM2 (port 3000) +# runners: 5x GitHub Actions runners (systemd) +# nginx: harbor conf -> 127.0.0.1:5000 +# keepalived: BACKUP priority 90 VIP:200 + +- name: "192.168.0.110 DevOps 金庫 — 預期狀態收斂" + hosts: host_110 + become: true + vars: + ansible_become_pass: "{{ vault_sudo_password | default(omit) }}" + + tasks: + # ======================================================================== + # Swap 檢查 + # ======================================================================== + - name: "Swap | 確認 swap.img 存在" + ansible.builtin.stat: + path: /swap.img + register: swap1_stat + tags: swap + + - name: "Swap | 確認 swap2.img 存在" + ansible.builtin.stat: + path: /swap2.img + register: swap2_stat + tags: swap + + - name: "Swap | 建立 swap2.img (若不存在)" + ansible.builtin.command: + cmd: "fallocate -l 4G /swap2.img" + creates: /swap2.img + when: not swap2_stat.stat.exists + tags: swap + + - name: "Swap | 格式化 swap2.img (若剛建立)" + ansible.builtin.command: + cmd: "mkswap /swap2.img" + when: not swap2_stat.stat.exists + tags: swap + + - name: "Swap | 設定 swap2.img 權限" + ansible.builtin.file: + path: /swap2.img + mode: "0600" + tags: swap + + - name: "Swap | 加入 swap2.img 到 fstab" + ansible.builtin.lineinfile: + path: /etc/fstab + line: "/swap2.img none swap sw 0 0" + state: present + tags: swap + + - name: "Swap | 啟用 swap" + ansible.builtin.command: + cmd: "swapon --all" + changed_when: false + tags: swap + + # ======================================================================== + # Docker 服務健康檢查 + # ======================================================================== + - name: "Docker | 確認 Harbor 容器運作中" + ansible.builtin.command: + cmd: "docker ps --filter name=harbor --filter status=running --format '{{ '{{' }}.Names{{ '}}' }}'" + register: harbor_status + changed_when: false + tags: docker + + - name: "Docker | Harbor 狀態警告" + ansible.builtin.debug: + msg: "⚠️ Harbor 容器未完全運作,請手動檢查 /opt/harbor" + when: harbor_status.stdout == "" + tags: docker + + - name: "Docker | 確認 Gitea 容器運作中" + ansible.builtin.command: + cmd: "docker ps --filter name=gitea --filter status=running --format '{{ '{{' }}.Names{{ '}}' }}'" + register: gitea_status + changed_when: false + tags: docker + + - name: "Docker | 確認 Sentry 無 restart 容器" + ansible.builtin.command: + cmd: "docker ps --filter status=restarting --filter name=sentry --format '{{ '{{' }}.Names{{ '}}' }}'" + register: sentry_restarting + changed_when: false + tags: docker + + - name: "Docker | Sentry crash loop 警告" + ansible.builtin.debug: + msg: "⚠️ Sentry 容器 crash loop: {{ sentry_restarting.stdout }}" + when: sentry_restarting.stdout != "" + tags: docker + + # ======================================================================== + # bitan pharmacy Docker 服務 + # ======================================================================== + - name: "bitan | 確認 bitan container 運作中" + ansible.builtin.command: + cmd: "docker ps --filter name=bitan --filter status=running --format '{{ '{{' }}.Names{{ '}}' }}'" + register: bitan_status + changed_when: false + tags: bitan + + - name: "bitan | 若停止則啟動" + ansible.builtin.command: + cmd: "docker compose up -d" + chdir: /home/wooo/apps/bitan-pharmacy + when: bitan_status.stdout == "" + tags: bitan + + # ======================================================================== + # GitHub Runners + # ======================================================================== + - name: "Runners | 確認 runner 服務狀態" + ansible.builtin.systemd: + name: "github-runner-{{ item }}" + register: runner_status + loop: "{{ range(1, github_runner_count + 1) | list }}" + ignore_errors: true + tags: runners + + # ======================================================================== + # keepalived + # ======================================================================== + - name: "keepalived | 確認服務運作中" + ansible.builtin.systemd: + name: keepalived + register: keepalived_status + tags: keepalived + + - name: "keepalived | 警告:keepalived 未運作" + ansible.builtin.debug: + msg: "⚠️ keepalived 未運作,VIP 200 可能失效" + when: keepalived_status.status.ActiveState != "active" + tags: keepalived + + # ======================================================================== + # Nginx harbor conf 指向確認 + # ======================================================================== + - name: "nginx | 確認 harbor nginx conf 存在" + ansible.builtin.stat: + path: /etc/nginx/sites-enabled/harbor.conf + register: harbor_nginx + tags: nginx + + - name: "nginx | 確認 harbor conf 指向 :5000 (非 :5050)" + ansible.builtin.command: + cmd: "grep -c ':5050' /etc/nginx/sites-enabled/harbor.conf" + register: harbor_conf_check + changed_when: false + failed_when: false + when: harbor_nginx.stat.exists + tags: nginx + + - name: "nginx | 警告:harbor conf 仍指向 :5050" + ansible.builtin.debug: + msg: "⚠️ harbor nginx conf 仍有 :5050,請確認已修正為 :5000" + when: harbor_nginx.stat.exists and harbor_conf_check.stdout != "0" + tags: nginx diff --git a/infra/ansible/playbooks/188-ai-web.yml b/infra/ansible/playbooks/188-ai-web.yml new file mode 100644 index 00000000..9ae44bbe --- /dev/null +++ b/infra/ansible/playbooks/188-ai-web.yml @@ -0,0 +1,135 @@ +--- +# AWOOOI Ansible — 192.168.0.188 AI+Web 中心完整狀態描述 +# 執行: ansible-playbook -i inventory/hosts.yml playbooks/188-ai-web.yml +# +# 預期狀態: +# openclaw: running (port 8088) +# tsenyang: running (port 3000) +# momo: running (port 5003) +# signoz: running (port 3301) +# minio: running (port 9000) +# litellm: running (port 4000) +# n8n: running (port 5678) +# open-webui: running (port 3010) +# docker-registry: running (port 5001) +# nginx: all-sites.conf 無 gitlab block +# keepalived: MASTER priority 100 VIP:200 + +- name: "192.168.0.188 AI+Web 中心 — 預期狀態收斂" + hosts: host_188 + become: true + vars: + ansible_become_pass: "{{ vault_sudo_password | default(omit) }}" + + tasks: + # ======================================================================== + # Docker 服務健康檢查 + # ======================================================================== + - name: "Docker | 收集運作中的容器清單" + ansible.builtin.command: + cmd: "docker ps --format '{{ '{{' }}.Names{{ '}}' }}'" + register: running_containers + changed_when: false + tags: docker + + - name: "Docker | 確認關鍵服務運作中" + ansible.builtin.debug: + msg: "⚠️ 服務 {{ item }} 未在容器列表中,請確認" + when: item not in running_containers.stdout + loop: + - openclaw + - tsenyang + - momo + - signoz + - minio + - litellm + tags: docker + + # ======================================================================== + # n8n / open-webui (Sprint A 新啟動) + # ======================================================================== + - name: "n8n | 確認容器運作中" + ansible.builtin.command: + cmd: "docker ps --filter name=n8n --filter status=running --format '{{ '{{' }}.Names{{ '}}' }}'" + register: n8n_status + changed_when: false + tags: n8n + + - name: "n8n | 若停止則啟動" + ansible.builtin.command: + cmd: "docker compose up -d" + chdir: /opt/n8n + when: n8n_status.stdout == "" + tags: n8n + + - name: "open-webui | 確認容器運作中" + ansible.builtin.command: + cmd: "docker ps --filter name=open-webui --filter status=running --format '{{ '{{' }}.Names{{ '}}' }}'" + register: openwebui_status + changed_when: false + tags: open_webui + + - name: "open-webui | 若停止則啟動" + ansible.builtin.command: + cmd: "docker compose up -d" + chdir: /opt/open-webui + when: openwebui_status.stdout == "" + tags: open_webui + + # ======================================================================== + # Nginx 狀態確認 + # ======================================================================== + - name: "nginx | 確認服務運作中" + ansible.builtin.systemd: + name: nginx + register: nginx_status + tags: nginx + + - name: "nginx | 警告:nginx 未運作" + ansible.builtin.debug: + msg: "🚨 nginx 未運作!" + when: nginx_status.status.ActiveState != "active" + tags: nginx + + - name: "nginx | 確認 all-sites.conf 無 gitlab block" + ansible.builtin.command: + cmd: "grep -c 'gitlab' /etc/nginx/sites-enabled/all-sites.conf" + register: gitlab_check + changed_when: false + failed_when: false + tags: nginx + + - name: "nginx | 警告:all-sites.conf 仍含 gitlab block" + ansible.builtin.debug: + msg: "⚠️ all-sites.conf 仍含 gitlab 設定,請確認 Sprint A 清除是否完整" + when: gitlab_check.stdout != "0" + tags: nginx + + # ======================================================================== + # keepalived MASTER + # ======================================================================== + - name: "keepalived | 確認服務運作中" + ansible.builtin.systemd: + name: keepalived + register: keepalived_status + tags: keepalived + + - name: "keepalived | 警告:keepalived 未運作" + ansible.builtin.debug: + msg: "⚠️ keepalived MASTER 未運作,VIP:200 降級為 110 BACKUP" + when: keepalived_status.status.ActiveState != "active" + tags: keepalived + + - name: "keepalived | 確認 VIP:200 由本機持有" + ansible.builtin.command: + cmd: "ip addr show | grep 192.168.0.200" + register: vip_check + changed_when: false + failed_when: false + tags: keepalived + + - name: "keepalived | 警告:VIP:200 不在本機" + ansible.builtin.debug: + msg: "⚠️ VIP 192.168.0.200 不在 188 (MASTER 可能已 failover 到 110)" + when: vip_check.rc != 0 + tags: keepalived diff --git a/infra/ansible/playbooks/nginx-sync.yml b/infra/ansible/playbooks/nginx-sync.yml new file mode 100644 index 00000000..091db783 --- /dev/null +++ b/infra/ansible/playbooks/nginx-sync.yml @@ -0,0 +1,56 @@ +--- +# AWOOOI Ansible — Nginx 設定同步 Playbook +# 原則: Nginx conf 不再直接手改,所有修改透過此 Playbook 部署 +# 執行: ansible-playbook -i inventory/hosts.yml playbooks/nginx-sync.yml --tags 188 +# 乾跑: ansible-playbook -i inventory/hosts.yml playbooks/nginx-sync.yml --check + +- name: "188 Nginx conf 同步" + hosts: host_188 + become: true + vars: + ansible_become_pass: "{{ vault_sudo_password | default(omit) }}" + nginx_conf_src: "{{ playbook_dir }}/../roles/nginx/templates/188-all-sites.conf.j2" + nginx_conf_dest: /etc/nginx/sites-enabled/all-sites.conf + + tasks: + - name: "nginx | 部署 all-sites.conf" + ansible.builtin.template: + src: "{{ nginx_conf_src }}" + dest: "{{ nginx_conf_dest }}" + owner: root + group: root + mode: "0644" + backup: true + notify: reload nginx + tags: ["188", "nginx"] + + - name: "nginx | 測試設定" + ansible.builtin.command: + cmd: "nginx -t" + changed_when: false + tags: ["188", "nginx"] + + handlers: + - name: reload nginx + ansible.builtin.systemd: + name: nginx + state: reloaded + +- name: "110 Nginx conf 同步(若有)" + hosts: host_110 + become: true + vars: + ansible_become_pass: "{{ vault_sudo_password | default(omit) }}" + + tasks: + - name: "nginx | 確認 110 nginx 無 all-sites-from-188.conf 在 sites-enabled" + ansible.builtin.stat: + path: /etc/nginx/sites-enabled/all-sites-from-188.conf + register: stale_conf + tags: ["110", "nginx"] + + - name: "nginx | 警告:110 仍有 all-sites-from-188.conf (已非 188 管控)" + ansible.builtin.debug: + msg: "⚠️ 110 sites-enabled 仍有 all-sites-from-188.conf,應已封存" + when: stale_conf.stat.exists + tags: ["110", "nginx"] diff --git a/infra/ansible/playbooks/site.yml b/infra/ansible/playbooks/site.yml new file mode 100644 index 00000000..584d71e4 --- /dev/null +++ b/infra/ansible/playbooks/site.yml @@ -0,0 +1,16 @@ +--- +# AWOOOI Ansible — 全站入口 Playbook +# 執行: ansible-playbook -i inventory/hosts.yml playbooks/site.yml +# 乾跑: ansible-playbook -i inventory/hosts.yml playbooks/site.yml --check + +- name: "110 DevOps 金庫" + import_playbook: 110-devops.yml + tags: ["110", "devops"] + +- name: "188 AI+Web 中心" + import_playbook: 188-ai-web.yml + tags: ["188", "ai_web"] + +- name: "Nginx 設定同步" + import_playbook: nginx-sync.yml + tags: ["nginx"] diff --git a/infra/ansible/roles/docker-compose-service/tasks/main.yml b/infra/ansible/roles/docker-compose-service/tasks/main.yml new file mode 100644 index 00000000..9a8002bc --- /dev/null +++ b/infra/ansible/roles/docker-compose-service/tasks/main.yml @@ -0,0 +1,18 @@ +--- +# docker-compose-service role — 確保 Docker Compose 服務運作中 +# 呼叫方式: include_role: name=docker-compose-service +# vars: +# service_name: n8n +# service_dir: /opt/n8n + +- name: "{{ service_name }} | 確認容器運作中" + ansible.builtin.command: + cmd: "docker ps --filter name={{ service_name }} --filter status=running --format '{{ '{{' }}.Names{{ '}}' }}'" + register: _svc_status + changed_when: false + +- name: "{{ service_name }} | 若停止則啟動" + ansible.builtin.command: + cmd: "docker compose up -d" + chdir: "{{ service_dir }}" + when: _svc_status.stdout == "" diff --git a/infra/ansible/roles/nginx/tasks/main.yml b/infra/ansible/roles/nginx/tasks/main.yml new file mode 100644 index 00000000..b0d7cc82 --- /dev/null +++ b/infra/ansible/roles/nginx/tasks/main.yml @@ -0,0 +1,16 @@ +--- +# nginx role — 任務主入口 +# 由 nginx-sync.yml playbook 呼叫 + +- name: "確認 nginx 已安裝" + ansible.builtin.package: + name: nginx + state: present + tags: nginx + +- name: "確認 nginx 服務啟動且自動啟動" + ansible.builtin.systemd: + name: nginx + state: started + enabled: true + tags: nginx diff --git a/infra/ansible/roles/nginx/templates/188-all-sites.conf.j2 b/infra/ansible/roles/nginx/templates/188-all-sites.conf.j2 new file mode 100644 index 00000000..a9936ea7 --- /dev/null +++ b/infra/ansible/roles/nginx/templates/188-all-sites.conf.j2 @@ -0,0 +1,145 @@ +# 188-all-sites.conf.j2 +# AWOOOI Nginx 全站設定 — 由 Ansible nginx-sync.yml playbook 管理 +# 禁止直接手改此檔案 → 請修改 roles/nginx/templates/188-all-sites.conf.j2 +# 部署指令: ansible-playbook -i inventory/hosts.yml playbooks/nginx-sync.yml --tags 188 +# 最後同步: {{ ansible_date_time.iso8601 }} + +# ============================================================ +# OpenClaw (port 8088) +# ============================================================ +server { + listen 80; + server_name openclaw.awoooi.com; + + location / { + proxy_pass http://127.0.0.1:8088; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 300s; + } +} + +# ============================================================ +# tsenyang (port 3000) +# ============================================================ +server { + listen 80; + server_name tsenyang.awoooi.com; + + location / { + proxy_pass http://127.0.0.1:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} + +# ============================================================ +# momo (port 5003) +# ============================================================ +server { + listen 80; + server_name momo.awoooi.com; + + location / { + proxy_pass http://127.0.0.1:5003; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } +} + +# ============================================================ +# SignOz (port 3301) +# ============================================================ +server { + listen 80; + server_name signoz.awoooi.internal; + + location / { + proxy_pass http://127.0.0.1:3301; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} + +# ============================================================ +# MinIO (port 9000 API / 9001 Console) +# ============================================================ +server { + listen 80; + server_name minio.awoooi.internal; + + location / { + proxy_pass http://127.0.0.1:9001; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + client_max_body_size 500m; + } +} + +# ============================================================ +# LiteLLM (port 4000) +# ============================================================ +server { + listen 80; + server_name litellm.awoooi.internal; + + location / { + proxy_pass http://127.0.0.1:4000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_read_timeout 300s; + } +} + +# ============================================================ +# n8n (port 5678) +# ============================================================ +server { + listen 80; + server_name n8n.awoooi.internal; + + location / { + proxy_pass http://127.0.0.1:5678; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} + +# ============================================================ +# Open WebUI (port 3010) +# ============================================================ +server { + listen 80; + server_name open-webui.awoooi.internal; + + location / { + proxy_pass http://127.0.0.1:3010; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 300s; + } +} + +# ============================================================ +# Docker Registry (port 5001) +# ============================================================ +server { + listen 80; + server_name registry.awoooi.internal; + + location / { + proxy_pass http://127.0.0.1:5001; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + client_max_body_size 2g; + } +} diff --git a/infra/ansible/roles/pm2-service/tasks/main.yml b/infra/ansible/roles/pm2-service/tasks/main.yml new file mode 100644 index 00000000..10df79dd --- /dev/null +++ b/infra/ansible/roles/pm2-service/tasks/main.yml @@ -0,0 +1,22 @@ +--- +# pm2-service role — 確保 PM2 管理的服務運作中 +# 呼叫方式: include_role: name=pm2-service +# vars: +# pm2_app_name: wooo-aiops # PM2 process name +# pm2_user: wooo # 執行 PM2 的使用者 + +- name: "{{ pm2_app_name }} | 確認 PM2 process 狀態" + ansible.builtin.command: + cmd: "pm2 jlist" + become_user: "{{ pm2_user }}" + register: pm2_list + changed_when: false + +- name: "{{ pm2_app_name }} | 解析 process 狀態" + ansible.builtin.set_fact: + _pm2_online: "{{ (pm2_list.stdout | from_json | selectattr('name', 'equalto', pm2_app_name) | selectattr('pm2_env.status', 'equalto', 'online') | list | length) > 0 }}" + +- name: "{{ pm2_app_name }} | 警告:服務未 online" + ansible.builtin.debug: + msg: "⚠️ PM2 process '{{ pm2_app_name }}' 未 online,請手動檢查" + when: not _pm2_online diff --git a/infra/ansible/roles/swap/tasks/main.yml b/infra/ansible/roles/swap/tasks/main.yml new file mode 100644 index 00000000..653c7c2d --- /dev/null +++ b/infra/ansible/roles/swap/tasks/main.yml @@ -0,0 +1,35 @@ +--- +# swap role — 確保 swap 已設定(110 專用) +# 預期狀態: swap.img (3.8G) + swap2.img (4G) 共 ~8G + +- name: "Swap | 確認 swap2.img 存在" + ansible.builtin.stat: + path: /swap2.img + register: swap2_stat + +- name: "Swap | 建立 swap2.img" + ansible.builtin.command: + cmd: "fallocate -l 4G /swap2.img" + creates: /swap2.img + when: not swap2_stat.stat.exists + +- name: "Swap | 格式化 swap2.img" + ansible.builtin.command: + cmd: "mkswap /swap2.img" + when: not swap2_stat.stat.exists + +- name: "Swap | 設定 swap2.img 權限" + ansible.builtin.file: + path: /swap2.img + mode: "0600" + +- name: "Swap | 加入 swap2.img 到 fstab" + ansible.builtin.lineinfile: + path: /etc/fstab + line: "/swap2.img none swap sw 0 0" + state: present + +- name: "Swap | 啟用 swap" + ansible.builtin.command: + cmd: "swapon --all" + changed_when: false