wiki/b-reference/platform/infrastructure.md

175 lines
7.1 KiB
Markdown

<!-- status: canonical -->
<!-- lastReviewed: 2026-05-28 -->
# 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-<repo|db>` fuer alle Produktions-Komponenten
- `porta-int-<repo|db>` fuer alle Integrations-Komponenten
2. Alle eigenstaendigen Services laufen je als **separates Projekt** mit:
- `service-main-<repo>` fuer Produktion
- `service-int-<repo>` 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@<DB_INTERNAL_IP> 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@<DB_INTERNAL_IP> 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@<DB_INTERNAL_IP> \
"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).