From c5d4ee8bfa5fe72cad9a26e72c2c3976ca6b98d3 Mon Sep 17 00:00:00 2001 From: Christoph Emsenhuber Date: Mon, 15 Jun 2026 14:42:52 +0200 Subject: [PATCH] =?UTF-8?q?TP2=20=F0=9F=93=8B=20Komodo-Migration=20geplant?= =?UTF-8?q?:=20Core/Periphery/MCP=20Compose=20+=20MIGRATION.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Portainer CE 2.40 hat keinen passenden portainer-mcp (erst ab 2.41) → Entscheidung: Ablösung durch Komodo + Samik081/mcp-komodo (selber Autor wie pve-mcp). - mcp/komodo/MIGRATION.md — 5-Phasen-Plan (Export → Core → Periphery → Stacks → MCP) - mcp/komodo/core-compose.yml — Komodo Core + MongoDB auf pve-LXC (.126:9120) - mcp/komodo/periphery.compose.yml — Agent-Template für DS923/.10, odroid/.7, macmini/.167, nas-fm - mcp/komodo/komodo-mcp-compose.yml — MCP-Adapter, macvlan .176, SSE :3000 - mcp/komodo/.env.example — Secret-Vorlage - mcp/INVENTORY.md — portainer-mcp auf ⏳ retiring, komodo-mcp als 🟡 geplant eingetragen Co-Authored-By: Claude Sonnet 4.6 --- mcp/INVENTORY.md | 3 +- mcp/komodo/.env.example | 16 ++ mcp/komodo/MIGRATION.md | 255 ++++++++++++++++++++++++++++++ mcp/komodo/core-compose.yml | 56 +++++++ mcp/komodo/komodo-mcp-compose.yml | 34 ++++ mcp/komodo/periphery.compose.yml | 21 +++ 6 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 mcp/komodo/.env.example create mode 100644 mcp/komodo/MIGRATION.md create mode 100644 mcp/komodo/core-compose.yml create mode 100644 mcp/komodo/komodo-mcp-compose.yml create mode 100644 mcp/komodo/periphery.compose.yml diff --git a/mcp/INVENTORY.md b/mcp/INVENTORY.md index 02ea9ce..d4e433b 100644 --- a/mcp/INVENTORY.md +++ b/mcp/INVENTORY.md @@ -12,7 +12,8 @@ | **pve-mcp** (samik081) | Proxmox VE API (Host `.100`) | DS923 (`.10`), macvlan-IP **`.173`** | SSE `http://10.40.41.173:3000/sse` | `ghcr.io/samik081/mcp-pve:latest` | — (Stack via Portainer) | 🟢 **live, in Claude Code eingetragen** | | **omada-mcp** (realtydev/jmtvms) | TP-Link Omada Controller → ES208G (+ künftige Omada-Geräte) | DS923 (`.10`), macvlan-IP **`.174`** | SSE `http://10.40.41.174:3000/sse` (`MCP_TRANSPORT=sse`) | `jmtvms/tplink-omada-mcp:latest` | `mcp/omada/` ✓ (`.env` befüllt) | 🔴 **Container nicht deployed — nächster Schritt: Stack via Portainer endpointId=14** | | **omada-controller** | Omada Software Controller (keine MCP) | DS923 (`.10`), macvlan-IP **`.175`** | HTTPS `https://10.40.41.175:8043` | `mbentley/omada-controller:6.2` | `omada/docker-compose.yml` | 🟢 **live, configured, Wizard ✅** | -| **portainer-mcp** (offiziell) | Docker-Überblick **5 Hosts** via Portainer | Portainer läuft auf `.126:9443` v2.40.0 | stdio (uvx) o. Docker-HTTP | `portainer/portainer-mcp` | `mcp/portainer/` (Token .env ✓) | 🟠 **zurückgestellt — Portainer ablösung durch Komodo geplant** | +| **komodo-mcp** (samik081) | Docker-Management **5 Hosts** via Komodo Core (ersetzt Portainer) | DS923 (`.10`), macvlan-IP **`.176`** | SSE `http://10.40.41.176:3000/sse` | `ghcr.io/samik081/mcp-komodo:latest` | `mcp/komodo/` ✓ (`.env.example` → `.env` nach Phase 1) | 🟡 **geplant — Migration: `mcp/komodo/MIGRATION.md`** | +| ~~portainer-mcp~~ (offiziell) | Docker-Überblick via Portainer CE 2.40.0 | `.126:9443` | — | `portainer/portainer-mcp` | `mcp/portainer/` (Token .env ✓) | ⏳ **retired nach Komodo-Migration — Token aufheben bis Phase 4** | | ~~ALLNET-MCP~~ | ALLNET ALL-SG8316M Core-Switch | — | — | — | — | ⛔ **bewusst NICHT** (Telnet/1-VTY/15-min-Lock auf Core = zu fragil). User-Entscheid: erst beschriebener Weg, sonst Omada-Core-Tausch. | Legende: 🟢 live · 🟡 staged (Config da, nicht deployed) · 🔴 blockiert · ⛔ bewusst nicht gemacht diff --git a/mcp/komodo/.env.example b/mcp/komodo/.env.example new file mode 100644 index 0000000..39ebc00 --- /dev/null +++ b/mcp/komodo/.env.example @@ -0,0 +1,16 @@ +# Komodo Secrets — Vorlage (gitignored: .env) +# Kopieren nach .env und befüllen + +# Core (core-compose.yml) +KOMODO_HOST=http://10.40.41.126:9120 +KOMODO_DB_PASSWORD= +KOMODO_JWT_SECRET= +KOMODO_PASSKEY= + +# komodo-mcp (komodo-mcp-compose.yml) — nach Phase 1 befüllen +KOMODO_URL=http://10.40.41.126:9120 +KOMODO_API_KEY= +KOMODO_API_SECRET= +MCP_TRANSPORT=http +PORT=3000 +ACCESS_LEVEL=read-execute diff --git a/mcp/komodo/MIGRATION.md b/mcp/komodo/MIGRATION.md new file mode 100644 index 0000000..d3f0237 --- /dev/null +++ b/mcp/komodo/MIGRATION.md @@ -0,0 +1,255 @@ +# Portainer → Komodo Migration + +**Entscheidung (2026-06-15):** Portainer CE 2.40.0 wird durch [Komodo](https://komo.do) ersetzt. +- Portainer-MCP braucht 2.41/2.42 (kein Match für 2.40) → Blocker für portainer-mcp +- Komodo hat nativen MCP-Server ([Samik081/mcp-komodo](https://github.com/Samik081/mcp-komodo), selber Autor wie pve-mcp) +- Komodo = modernes Portainer-Äquivalent mit Git-Deploy, Prozeduren, Monitoring + +--- + +## Architektur-Übersicht + +``` +Claude Code (Mac) + └── komodo-mcp (.176, SSE) ── Komodo Core (.126:9120) ──┬── Periphery auf .126 (self) + └── MongoDB ├── Periphery auf .10 (DS923) + ├── Periphery auf .7 (odroid) + ├── Periphery auf .167 (macmini) + └── Periphery auf nas-fm +``` + +**Komodo besteht aus zwei Teilen:** +- **Core** — Web-UI + API + Orchestrierung (läuft auf .126, Port 9120) +- **Periphery** — leichter Agent auf jedem verwalteten Host (managed Docker direkt lokal) +- **mcp-komodo** — MCP-Adapter zwischen Claude Code und Komodo-API + +--- + +## Phase 0 — Vorbereitung: Portainer-Inventar exportieren + +Bevor Portainer abgeschaltet wird, alle Stacks + Endpunkte dokumentieren: + +```bash +# API-Token aus mcp/portainer/.env +source mcp/portainer/.env + +# Endpunkte (= die 5 Hosts) +curl -sk "$PORTAINER_URL/api/endpoints" \ + -H "X-API-Key: $PORTAINER_API_KEY" | jq '.[] | {id, name, URL}' + +# Alle Stacks (pro Endpoint) +curl -sk "$PORTAINER_URL/api/stacks" \ + -H "X-API-Key: $PORTAINER_API_KEY" | jq '.[] | {Id, Name, EndpointId}' + +# Stack-Compose je Stack (Beispiel Stack-ID 1): +curl -sk "$PORTAINER_URL/api/stacks/1/file" \ + -H "X-API-Key: $PORTAINER_API_KEY" | jq -r '.StackFileContent' +``` + +Bekannte Portainer-Endpunkte: +| endpointId | Host | IP | +|---|---|---| +| (lokal) | pve-LXC | 10.40.41.126 | +| 14 | nas-bf (DS923+) | 10.40.41.10 | +| ? | odroid-m1 | 10.40.41.7 | +| ? | macmini | 10.40.41.167 | +| ? | nas-fm (DS415+) | (IP prüfen) | + +--- + +## Phase 1 — Komodo Core deployen (auf pve-LXC, .126) + +Komodo Core ersetzt Portainer auf demselben Host. Portainer läuft während der Migration parallel +(Port 9443 ≠ Port 9120). Erst nach Abschluss von Phase 4 wird Portainer gestoppt. + +### 1a — Secrets anlegen + +```bash +# Datei: mcp/komodo/.env (gitignored via mcp/.gitignore) +KOMODO_HOST=http://10.40.41.126:9120 +KOMODO_DB_PASSWORD= +KOMODO_JWT_SECRET= +KOMODO_PASSKEY= +# Nach Core-Start befüllen: +# KOMODO_API_KEY=... +# KOMODO_API_SECRET=... +``` + +### 1b — Docker Compose für Core + +Datei: `mcp/komodo/core-compose.yml` (liegt neben dieser Datei) + +Deployment via Portainer endpointId=lokal (.126 selbst) **oder** direkt per SSH: + +```bash +ssh +mkdir -p /opt/komodo && cd /opt/komodo +# compose + .env hochladen / eintragen +docker compose -f core-compose.yml up -d +``` + +UI erreichbar: `http://10.40.41.126:9120` + +### 1c — Initialer Admin-User + +Beim ersten Öffnen des UI → Admin-Account anlegen → danach: +`Settings → API Keys → neues Key-Paar generieren` → in `.env` eintragen. + +--- + +## Phase 2 — Periphery-Agent auf den 5 Hosts + +Komodo Core managt seinen eigenen Docker-Host (pve-LXC) nativ über `localhost`. +Für alle weiteren Hosts muss ein Periphery-Agent installiert werden. + +### Methode A — Docker Container (bevorzugt, wo Docker schon läuft) + +```yaml +# periphery.compose.yml (auf dem jeweiligen Host ablegen, z.B. /opt/komodo/) +services: + periphery: + image: ghcr.io/moghtech/komodo-periphery:latest + restart: unless-stopped + network_mode: host # muss direkt erreichbar sein + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /etc/komodo:/etc/komodo # periphery root (compose-Dateien landen hier) + environment: + PERIPHERY_ALLOWED_IPS: 10.40.41.126 # nur Core darf reden + PERIPHERY_PORT: 8120 +``` + +### Methode B — systemd-Binary (für Hosts ohne Docker oder wenn Methode A nicht passt) + +```bash +# Einzeiler vom Komodo-Onboarding-Wizard (im UI generiert): +curl -sSL https://raw.githubusercontent.com/moghtech/komodo/main/scripts/setup-periphery.sh \ + | bash -s -- --core-addr http://10.40.41.126:9120 \ + --name \ + --passkey +``` + +### Host-Matrix + +| Host | IP | Periphery-Methode | Besonderheit | +|---|---|---|---| +| pve-LXC | 10.40.41.126 | **lokal** (Core selbst) | kein Agent nötig — Core = erster Server | +| DS923 | 10.40.41.10 | Docker Container | Portainer endpointId=14 → Bootstrap via Portainer API | +| odroid-m1 | 10.40.41.7 | Docker Container | IP prüfen; Docker vorhanden | +| macmini | 10.40.41.167 | Docker Container o. systemd | `ssh macmini` → compose up | +| nas-fm | (IP prüfen) | Docker Container | IP + SSH-Zugang vorher klären | + +**DS923-Bootstrap (einmalig, vor Phase 3):** +```bash +source mcp/portainer/.env +# periphery.compose.yml via Portainer API auf DS923 deployen: +curl -sk -X POST "$PORTAINER_URL/api/stacks/create/standalone/string?endpointId=14" \ + -H "X-API-Key: $PORTAINER_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"komodo-periphery\",\"stackFileContent\":\"$(cat mcp/komodo/periphery.compose.yml | jq -Rs .)\"}" +``` + +--- + +## Phase 3 — Stacks in Komodo eintragen + +Nach Phase 1+2: alle vorhandenen Stacks aus Phase 0 in Komodo nachpflegen. + +**Komodo Stack-Konzept:** +- UI → `Stacks → + New Stack` +- Compose-Inhalt: direkt im UI editieren **oder** aus Git-Repo (Webhook-Auto-Deploy) +- Komodo schreibt die Compose-Datei zur Deploy-Zeit auf den Host ins Periphery-Root + +Bestehende Stacks (nach Portainer-Export bekannt): +- omada-controller (DS923, `.175`) +- omada-mcp (DS923, `.174`) — noch nicht deployed, wird direkt über Komodo erstdeployed +- pve-mcp (DS923, `.173`) — laufend, nahtlos umziehen + +**Empfehlung:** Stacks zunächst in Komodo anlegen (disabled), dann umschalten, Portainer-Stack +deaktivieren (nicht löschen) → erst nach Verifikation aus Portainer entfernen. + +--- + +## Phase 4 — Portainer abschalten + +Wenn alle Stacks auf Komodo laufen und verifiziert: + +```bash +# Auf pve-LXC: +docker stop portainer && docker rm portainer +# docker volume portainer_data → optional behalten als Backup +``` + +`mcp/INVENTORY.md` aktualisieren: portainer-mcp-Zeile auf `retired` setzen. + +--- + +## Phase 5 — komodo-mcp deployen + Claude Code eintragen + +**Image:** `ghcr.io/samik081/mcp-komodo:latest` (selber Autor wie pve-mcp ✓) +**Macvlan-IP:** `10.40.41.176` (folgt .173/.174/.175) + +### 5a — Komodo API-Key erzeugen + +Komodo UI → `Settings → API Keys → New Key` +→ Key + Secret in `mcp/komodo/.env` als `KOMODO_API_KEY` + `KOMODO_API_SECRET` + +### 5b — compose.yml + +Datei: `mcp/komodo/komodo-mcp-compose.yml` (liegt neben dieser Datei) + +Stack via Komodo selbst deployen (Stack auf DS923, macvlan .176): +- Komodo UI → Stacks → New Stack → Ziel: DS923 (Periphery da) + +### 5c — Claude Code eintragen + +```bash +# ~/.claude/settings.json ergänzen (neben pve-mcp/.173): +# "komodo-mcp": { +# "type": "sse", +# "url": "http://10.40.41.176:3000/sse" +# } +``` + +Oder via CLI: +```bash +claude mcp add --transport sse komodo-mcp http://10.40.41.176:3000/sse -s user +``` + +Verfügbar nach Claude Code Neustart. Tools prüfen: +``` +/mcp → komodo-mcp → 40 Tools sichtbar +``` + +--- + +## Abhängigkeiten & Reihenfolge + +``` +Phase 0 (Export) + ↓ +Phase 1 (Core auf .126) + ↓ +Phase 2 (Periphery auf .10, .7, .167, nas-fm) + ↓ +Phase 3 (Stacks umziehen) + ↓ +Phase 4 (Portainer stop) + ↓ +Phase 5 (komodo-mcp .176 + Claude Code) +``` + +Phasen 0–2 sind unabhängig von laufenden Stacks und können ohne Downtime vorbereitet werden. +Phasen 3–5 erfordern kurze Downtime je Stack beim Umschalten (Sekunden). + +--- + +## Referenzen + +- [Komodo Docs](https://komo.do/docs/intro) +- [Core Setup](https://komo.do/docs/setup) +- [Connect Servers (Periphery)](https://komo.do/docs/setup/connect-servers) +- [Docker Compose Stacks](https://komo.do/docs/deploy/compose) +- [Samik081/mcp-komodo](https://github.com/Samik081/mcp-komodo) — MCP-Adapter +- [MP-Tool/komodo-mcp-server](https://github.com/MP-Tool/komodo-mcp-server) — Alternative (70 Tools, aber kein GHCR-Image) +- [moghtech/komodo (GitHub)](https://github.com/moghtech/komodo) — Upstream diff --git a/mcp/komodo/core-compose.yml b/mcp/komodo/core-compose.yml new file mode 100644 index 0000000..d7d7340 --- /dev/null +++ b/mcp/komodo/core-compose.yml @@ -0,0 +1,56 @@ +# Komodo Core — BF (ersetzt Portainer CE auf pve-LXC 10.40.41.126) +# Deploy auf: pve-LXC (.126), per SSH oder direkt +# Web-UI: http://10.40.41.126:9120 +# Doku: https://komo.do/docs/setup +# +# Secrets aus .env (gitignored): +# KOMODO_HOST, KOMODO_DB_PASSWORD, KOMODO_JWT_SECRET, KOMODO_PASSKEY + +services: + komodo-core: + image: ghcr.io/moghtech/komodo:latest + restart: unless-stopped + depends_on: + komodo-mongo: + condition: service_healthy + ports: + - "9120:9120" + environment: + KOMODO_HOST: ${KOMODO_HOST} + KOMODO_TITLE: "BF Komodo" + KOMODO_PASSKEY: ${KOMODO_PASSKEY} # Periphery-Onboarding-Secret + KOMODO_DATABASE_ADDRESS: komodo-mongo:27017 + KOMODO_DATABASE_USERNAME: komodo + KOMODO_DATABASE_PASSWORD: ${KOMODO_DB_PASSWORD} + KOMODO_JWT_SECRET: ${KOMODO_JWT_SECRET} + KOMODO_JWT_TTL: 1d + KOMODO_LOG_LEVEL: info + volumes: + - komodo-repos:/etc/komodo/repos + networks: + - komodo-internal + + komodo-mongo: + image: mongo:7 + restart: unless-stopped + command: --quiet + environment: + MONGO_INITDB_ROOT_USERNAME: komodo + MONGO_INITDB_ROOT_PASSWORD: ${KOMODO_DB_PASSWORD} + volumes: + - komodo-mongo-data:/data/db + networks: + - komodo-internal + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.runCommand('ping').ok"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + komodo-repos: + komodo-mongo-data: + +networks: + komodo-internal: + driver: bridge diff --git a/mcp/komodo/komodo-mcp-compose.yml b/mcp/komodo/komodo-mcp-compose.yml new file mode 100644 index 0000000..57b031f --- /dev/null +++ b/mcp/komodo/komodo-mcp-compose.yml @@ -0,0 +1,34 @@ +# komodo-mcp (Samik081) — BF +# Image: ghcr.io/samik081/mcp-komodo (selber Autor wie pve-mcp/.173) +# Host: DS923 (.10), macvlan-IP 10.40.41.176 +# Transport: SSE (MCP_TRANSPORT=http → streamable HTTP auf Port 3000) +# Doku: https://github.com/Samik081/mcp-komodo +# +# Deploy via Komodo Core (Stack auf DS923-Periphery) — NACH Phase 1-4. +# Secrets aus .env: +# KOMODO_URL, KOMODO_API_KEY, KOMODO_API_SECRET +# +# Claude Code eintragen: +# claude mcp add --transport sse komodo-mcp http://10.40.41.176:3000/sse -s user +# (oder ~/.claude/settings.json → "komodo-mcp": {"type":"sse","url":"http://10.40.41.176:3000/sse"}) + +services: + komodo-mcp: + image: ghcr.io/samik081/mcp-komodo:latest + container_name: komodo-mcp + restart: unless-stopped + networks: + default_external: + ipv4_address: 10.40.41.176 + env_file: .env + # Env-Vars (in .env, nie hier): + # KOMODO_URL=http://10.40.41.126:9120 + # KOMODO_API_KEY=... + # KOMODO_API_SECRET=... + # MCP_TRANSPORT=http # SSE/streamable HTTP + # PORT=3000 + # ACCESS_LEVEL=read-execute # oder: read-only | full + +networks: + default_external: + external: true diff --git a/mcp/komodo/periphery.compose.yml b/mcp/komodo/periphery.compose.yml new file mode 100644 index 0000000..bfe07af --- /dev/null +++ b/mcp/komodo/periphery.compose.yml @@ -0,0 +1,21 @@ +# Komodo Periphery-Agent — BF +# Deploy auf: jeden verwalteten Host (DS923, odroid, macmini, nas-fm) +# Doku: https://komo.do/docs/setup/connect-servers +# +# Anpassungen pro Host: +# PERIPHERY_ALLOWED_IPS: nur Komodo Core (.126) darf connecten +# +# Nach dem Start: im Komodo-UI unter Servers → New Server → Passkey eintragen + +services: + periphery: + image: ghcr.io/moghtech/komodo-periphery:latest + restart: unless-stopped + network_mode: host # Core muss Periphery direkt erreichen können + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /etc/komodo:/etc/komodo # Periphery-Root: Compose-Dateien + Repos landen hier + environment: + PERIPHERY_ALLOWED_IPS: 10.40.41.126 # nur Core darf sich verbinden + PERIPHERY_PORT: 8120 + PERIPHERY_ROOT_DIRECTORY: /etc/komodo