# Deployment-Infrastruktur ## Hosting-Provider Infomaniak Public Cloud (OpenStack) unter dem Dach-Account **PowerOnUniverse** (ID 17397). Horizon Dashboard: `https://api.pub1.infomaniak.cloud/horizon` ## Projektstruktur Jeder Service-Bereich ist ein eigenes OpenStack-Projekt mit eigenem Netzwerk, eigenen Security Groups, eigenen Floating IPs. Die Kommunikation zwischen Projekten laeuft ueber oeffentliche Floating IPs. | Projekt | OpenStack-ID | Zweck | |---|---|---| | **Porta** | PCP-OUJTOXY | Plattform-Kern (Frontend, Backend, DB) | | **Service-LLM** | PCP-MPXPVCR | Private LLM (Ollama + Flask, GPU) | | **Service-Teamsbot** | PCP-KO2UYXT | Teams-Browser-Bot | ## Naming Convention ### Schema ``` {bereich}-{env}-{komponente} ``` - **bereich:** `porta` (Plattform-Kern) oder `service` (eigenstaendiger Service) - **env:** `main` (Produktion) oder `int` (Integration) - **komponente:** Forgejo-Repo-Name oder `db` ### Regeln 1. Alles fuer PORTA laeuft im Projekt **Porta** mit: - `porta-main-` fuer alle Produktions-Komponenten - `porta-int-` fuer alle Integrations-Komponenten 2. Alle eigenstaendigen Services laufen je als **separates Projekt** mit: - `service-main-` fuer Produktion - `service-int-` fuer Integration (falls vorhanden) ### Instanzen #### Projekt: Porta (PCP-OUJTOXY) | Instanzname | Env | Komponente | Flavor | Intern IP | Floating IP | DNS | |---|---|---|---|---|---|---| | `porta-main-ui-nyla` | main | Frontend (React/Vite) | a2-ram4-disk20-perf1 | 10.20.0.92 | 37.156.43.5 | `porta.poweron.swiss` | | `porta-main-platform-core` | main | Backend (FastAPI) | a2-ram4-disk50-perf1 | 10.20.0.197 | 83.228.234.207 | `api.poweron.swiss` | | `porta-main-db` | main | PostgreSQL + pgvector | a2-ram4-disk80-perf1 | 10.20.0.21 | 37.156.40.141 | `db.poweron.swiss` | | `porta-int-ui-nyla` | int | Frontend (React/Vite) | a2-ram4-disk20-perf1 | 10.20.0.182 | 37.156.41.74 | `porta-int.poweron.swiss` | | `porta-int-platform-core` | int | Backend (FastAPI) | a2-ram4-disk50-perf1 | 10.20.0.74 | 37.156.43.14 | `api-int.poweron.swiss` | | `porta-int-db` | int | PostgreSQL + pgvector | a2-ram4-disk80-perf1 | 10.20.0.175 | 37.156.42.67 | `db-int.poweron.swiss` | Key Pair: `ida-laptop` (alle Instanzen) #### Projekt: Service-LLM (PCP-MPXPVCR) | Instanzname | Env | Komponente | Flavor | DNS / IP | |---|---|---|---|---| | `service-main-llm-private` | main | Ollama + FastAPI (Vision-LLM) | GPU L4 (24 GB VRAM), 8 vCPU, 16 GB RAM, 150 GB | `llm.poweron.swiss` / `83.228.200.109` (Port 8000, HTTPS) | **Geplante Migration → FireStorm (Zug/Zuerich):** | Anbieter | Produkt | GPU | VRAM | CPU | RAM | Storage | Preis | |---|---|---|---|---|---|---|---| | FireStorm ISP | GPU Pro | RTX PRO 6000 Blackwell Max-Q | 96 GB GDDR7 | AMD Threadripper 3970X (32C/64T) | 256 GB DDR4 ECC | 8 TB NVMe RAID 10 | CHF 749/Mt. + CHF 1'900 Setup | Status: Code vorbereitet (Modell-Definitionen in `aicorePluginPrivateLlm.py`), Hardware noch zu bestellen. DNS-Umschaltung `llm.poweron.swiss` bei Migration. #### Projekt: Service-Teamsbot (PCP-KO2UYXT) | Instanzname | Env | Komponente | Flavor | Floating IP | DNS | |---|---|---|---|---|---| | `service-main-teams-browser-bot` | main | Docker + Playwright/Chrome | a2-ram4-disk20 | 179.237.73.4 | `teamsbot.poweron.swiss` | Key Pair: `teamsbot-deploy-key` ## Deployment-Patterns ### VM-Grundkonfiguration (bei Neuinstallation) Auf jeder neuen VM (UI + Backend) nach Erstprovisionierung: ```bash # needrestart: nur melden, nicht automatisch Services neustarten. # Verhindert, dass unattended-upgrades laufende Services (nginx, gateway) # waehrend eines apt-Upgrades killt, wenn DNS kurzzeitig nicht verfuegbar ist. echo '$nrconf{restart} = '"'"'l'"'"';' | sudo tee /etc/needrestart/conf.d/99-no-auto-restart.conf ``` **Hintergrund:** `unattended-upgrades` aktualisiert OS-Pakete naechtlich. Dabei startet `systemd-networkd` kurz neu (DNS-Ausfall). Wenn `needrestart` gleichzeitig nginx restartet, schlaegt `proxy_pass`-DNS-Aufloesung fehl → nginx crasht und bleibt down. Mit `'l'` (list-only) werden nur betroffene Services gemeldet; der Restart erfolgt kontrolliert beim naechsten Deployment. ### Porta (git pull + systemd restart) Deploy-Workflow: `.forgejo/workflows/main_porta-main-platform-core.yml` in `platform-core` 1. Forgejo Actions Runner verbindet per SSH auf die VM 2. `git fetch origin main && git reset --hard origin/main` 3. `pip install -r requirements.txt` 4. `sudo systemctl restart gateway` ### Private LLM (rsync + systemd restart) Deploy-Workflow: `.github/workflows/deploy.yml` in `service-llm-private` 1. GitHub Actions (noch nicht migriert auf Forgejo) verbindet per SSH 2. `rsync` des Codes nach `/opt/ollama-webapp/app/` 3. `pip install -r requirements.txt` 4. `sudo systemctl restart ollama-webapp` ### Teams-Bot (rsync + docker compose, geplant) Deploy-Workflow: `.forgejo/workflows/deploy.yml` in `service-teams-browser-bot` 1. Forgejo Actions Runner verbindet per SSH auf die VM 2. `rsync` des Codes nach `/opt/teamsbot/` 3. `docker compose build && docker compose up -d` 4. Health-Check auf Port 4100 ## DB-Setup bei neuer Installation Bei einer neuen DB-Instanz (`porta-*-db`) muessen folgende Schritte ausgefuehrt werden: ### 1. pgvector Extension installieren (OS-Package) SSH auf die DB-VM (via API-Server als Jump-Host, da DB-VMs kein externes SSH haben): ```bash # Vom API-Server aus: ssh -i /tmp/ida-laptop.pem ubuntu@ bash << 'EOF' echo 'deb http://apt.postgresql.org/pub/repos/apt jammy-pgdg main' | sudo tee /etc/apt/sources.list.d/pgdg.list wget -qO- https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo tee /etc/apt/trusted.gpg.d/pgdg.asc > /dev/null sudo apt update -qq sudo apt install -y postgresql-14-pgvector sudo systemctl restart postgresql EOF ``` ### 2. Extension in Datenbanken aktivieren ```bash ssh -i /tmp/ida-laptop.pem ubuntu@ bash << 'EOF' sudo -u postgres psql -d poweron_knowledge -c 'CREATE EXTENSION IF NOT EXISTS vector;' sudo -u postgres psql -d poweron_commcoach -c 'CREATE EXTENSION IF NOT EXISTS vector;' EOF ``` ### 3. Verifizierung ```bash ssh -i /tmp/ida-laptop.pem ubuntu@ \ "sudo -u postgres psql -d poweron_knowledge -c '\dx vector'" ``` Erwartete Ausgabe: `vector | 0.8.x | public | vector data type and ivfflat and hnsw access methods` **Wichtig:** - Der DB-User `poweron_dev` hat keine SUPERUSER-Rechte -- Extension muss als `postgres` User erstellt werden - DB-VMs sind nicht direkt per SSH von aussen erreichbar; Zugang via API-Server (`porta-*-platform-core`) im internen Netzwerk - Ohne pgvector funktioniert keine RAG-Indexierung (semanticSearch) und kein Content-Index (browseContainer, summarizeContent, searchInFileContent) ## Zugriff | Ressource | URL / Pfad | |---|---| | Infomaniak Cloud Console | `https://www.infomaniak.com/cloud-computing` | | OpenStack Horizon | `https://api.pub1.infomaniak.cloud/horizon` | | Forgejo (Git + CI/CD) | `https://git.poweron.swiss` | | SSH Key (LLM) | `ollama-deploy-key.pem` | | SSH Key (Teamsbot) | `teamsbot-deploy-key.pem` (geplant) | Credentials: siehe lokale Datei `local/notes/key.txt` (nicht im Repo).