# 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