Die perfekte UI für Docker-Management - schlanker als Portainer, mächtiger als Dockge | Komodo

Die perfekte UI für Docker-Management - schlanker als Portainer, mächtiger als Dockge | Komodo

Übersicht

In diesem Beitrag stelle ich euch Komodo vor - eine moderne und durchdachte Alternative zu bekannten Docker-UIs wie Portainer und Dockge. Während Portainer oft zu überladen wirkt und Dockge sich eher auf die absoluten Basics beschränkt, trifft Komodo genau den Sweet Spot: ein leistungsstarkes, aber übersichtliches Tool mit allen Funktionen, die man im Alltag wirklich braucht.

Komodo überzeugt nicht nur durch seine klare, moderne Benutzeroberfläche, sondern bringt auch smarte Extras mit: automatisches Klonen von Git-Repos für Compose-Dateien, einfaches Deployen ganzer Stacks, integriertes Server-Monitoring à la Beszel und eine clevere Update-Erkennung für Docker-Stacks – inklusive optionaler Auto-Updates.

Video zum Beitrag: https://youtu.be/O22C8Q1u4fA


Installation

Docker

Als erstes benötigen wir natürlich Docker auf unserem Host. Docker kann ganz einfach mit dem offiziellen Convenience Script installiert werden.

curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh

Komodo Compose & env

Nachdem Docker auf dem System installiert ist, kommen wir auch schon zu Komodo. In meinem Fall habe ich die offizielle Compose so verändert, dass sie am Ende ganz normal mit sudo docker compose up -d gestartet werden kann. Den Port für die Weboberfläche habe ich auskommentiert, da ich Komodo am Ende nur über Caddy, was ebenfalls auf dem Host läuft, erreichen möchte.

Mehr Informationen zu Caddy findet ihr hier.

Compose

In der Compose passen wir nichts weiter an. Alle wichtigen Bearbeitungen nehmen wir gleich im Environment-File vor.

compose.yaml

###################################
# 🦎 KOMODO COMPOSE - POSTGRES 🦎 #
###################################

## This compose file will deploy:
##   1. Postgres + FerretDB Mongo adapter (https://www.ferretdb.com)
##   2. Komodo Core
##   3. Komodo Periphery

services:
  postgres:
    image: postgres:17
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    logging:
      driver: ${COMPOSE_LOGGING_DRIVER:-local}
    # ports:
    #   - 5432:5432
    volumes:
      - ./pg-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=${KOMODO_DB_USERNAME}
      - POSTGRES_PASSWORD=${KOMODO_DB_PASSWORD}
      - POSTGRES_DB=${KOMODO_DATABASE_DB_NAME:-komodo}
    networks:
      - komodo_internal

  ferretdb:
    image: ghcr.io/ferretdb/ferretdb:1
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    depends_on:
      - postgres
    logging:
      driver: ${COMPOSE_LOGGING_DRIVER:-local}
    # ports:
    #   - 27017:27017
    environment:
      - FERRETDB_POSTGRESQL_URL=postgres://postgres:5432/${KOMODO_DATABASE_DB_NAME:-komodo}
    networks:
      - komodo_internal
  
  core:
    image: ghcr.io/moghtech/komodo-core:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
    container_name: komodo-core
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    depends_on:
      - ferretdb
    logging:
      driver: ${COMPOSE_LOGGING_DRIVER:-local}
    #ports: mit caddy als reverse proxy
    #  - 9120:9120
    env_file: .env
    environment:
      KOMODO_DATABASE_URI: mongodb://${KOMODO_DB_USERNAME}:${KOMODO_DB_PASSWORD}@ferretdb:27017/${KOMODO_DATABASE_DB_NAME:-komodo}?authMechanism=PLAIN
    volumes:
      ## Core cache for repos for latest commit hash / contents
      - ./repo-cache:/repo-cache
      ## Store sync files on server
      # - /path/to/syncs:/syncs
      ## Optionally mount a custom core.config.toml
      # - /path/to/core.config.toml:/config/config.toml
    ## Allows for systemd Periphery connection at 
    ## "http://host.docker.internal:8120"
    # extra_hosts:
    #   - host.docker.internal:host-gateway
    networks:
      - komodo_internal
      - caddy_net

  ## Deploy Periphery container using this block,
  ## or deploy the Periphery binary with systemd using 
  ## https://github.com/moghtech/komodo/tree/main/scripts
  periphery:
    image: ghcr.io/moghtech/komodo-periphery:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    logging:
      driver: ${COMPOSE_LOGGING_DRIVER:-local}
    env_file: .env
    environment:
      PERIPHERY_REPO_DIR: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/repos
      PERIPHERY_STACK_DIR: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/stacks
      PERIPHERY_SSL_KEY_FILE: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/ssl/key.pem
      PERIPHERY_SSL_CERT_FILE: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/ssl/cert.pem
    volumes:
      ## Mount external docker socket
      - /var/run/docker.sock:/var/run/docker.sock
      ## Allow Periphery to see processes outside of container
      - /proc:/proc
      ## Specify the Periphery agent root directory.
      ## Must be the same inside and outside the container,
      ## or docker will get confused. See https://github.com/moghtech/komodo/discussions/180.
      ## Default: /etc/komodo.
      - ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}:${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}
    networks:
      - komodo_internal

networks:
  komodo_internal:
  caddy_net:
    external: true

Environment-Datei

Kommen wir zur Environment-Datei. Hier nehmen wir alle individuellen Anpassungen vor. Es werden alle Werte bereits gut erklärt. Wir müssen vor allem die Passwörter und den Passkey für zusätzliche Server setzen. Außerdem kann bei Bedarf eine Authentifizierung, zum Beispiel über Authentik oder auch Entra, konfiguriert werden. Wir geben auch unsere Domain an, über die wir Komodo später mittels Caddy aufrufen wollen, und lassen zumindest für den ersten Start die Variable KOMODO_DISABLE_USER_REGISTRATION=false bestehen, um unseren ersten Account anlegen zu können. Danach kann die Variable gerne auf true gesetzt werden und somit die Registrierung weiterer Benutzer verhindert werden.

.env

####################################
# 🦎 KOMODO COMPOSE - VARIABLES 🦎 #
####################################

## These compose variables can be used with all Komodo deployment options.
## Pass these variables to the compose up command using `--env-file komodo/compose.env`.
## Additionally, they are passed to both Komodo Core and Komodo Periphery with `env_file: ./compose.env`,
## so you can pass any additional environment variables to Core / Periphery directly in this file as well.

## Stick to a specific version, or use `latest`
COMPOSE_KOMODO_IMAGE_TAG=latest

## Note: 🚨 Podman does NOT support local logging driver 🚨. See Podman options here:
## `https://docs.podman.io/en/v4.6.1/markdown/podman-run.1.html#log-driver-driver`
COMPOSE_LOGGING_DRIVER=local # Enable log rotation with the local driver.

## DB credentials - Ignored for Sqlite
KOMODO_DB_USERNAME=komododbuser
KOMODO_DB_PASSWORD= #am besten ohne Sonderzeichen (Führt beim DB-String gerne zu Problemen)

## Configure a secure passkey to authenticate between Core / Periphery.
KOMODO_PASSKEY=

#=-------------------------=#
#= Komodo Core Environment =#
#=-------------------------=#

## Full variable list + descriptions are available here:
## 🦎 https://github.com/moghtech/komodo/blob/main/config/core.config.toml 🦎

## Note. Secret variables also support `${VARIABLE}_FILE` syntax to pass docker compose secrets.
## Docs: https://docs.docker.com/compose/how-tos/use-secrets/#examples

## Used for Oauth / Webhook url suggestion / Caddy reverse proxy.
KOMODO_HOST=https://komodo.example.de
## Displayed in the browser tab.
KOMODO_TITLE=Komodo
## Create a server matching this address as the "first server".
## Use `https://host.docker.internal:8120` when using systemd-managed Periphery.
KOMODO_FIRST_SERVER=https://periphery:8120
## Make all buttons just double-click, rather than the full confirmation dialog.
KOMODO_DISABLE_CONFIRM_DIALOG=false

## Rate Komodo polls your servers for
## status / container status / system stats / alerting.
## Options: 1-sec, 5-sec, 15-sec, 1-min, 5-min.
## Default: 15-sec
KOMODO_MONITORING_INTERVAL="15-sec"
## Rate Komodo polls Resources for updates,
## like outdated commit hash.
## Options: 1-min, 5-min, 15-min, 30-min, 1-hr.
## Default: 5-min
KOMODO_RESOURCE_POLL_INTERVAL="5-min"

## Used to auth incoming webhooks. Alt: KOMODO_WEBHOOK_SECRET_FILE
KOMODO_WEBHOOK_SECRET=
## Used to generate jwt. Alt: KOMODO_JWT_SECRET_FILE
KOMODO_JWT_SECRET=

## Enable login with username + password.
KOMODO_LOCAL_AUTH=true
## Disable new user signups.
KOMODO_DISABLE_USER_REGISTRATION=false
## All new logins are auto enabled
KOMODO_ENABLE_NEW_USERS=false
## Disable non-admins from creating new resources.
KOMODO_DISABLE_NON_ADMIN_CREATE=false
## Allows all users to have Read level access to all resources.
KOMODO_TRANSPARENT_MODE=false

## Time to live for jwt tokens.
## Options: 1-hr, 12-hr, 1-day, 3-day, 1-wk, 2-wk
KOMODO_JWT_TTL="1-day"

## OIDC Login
KOMODO_OIDC_ENABLED=false
## Must reachable from Komodo Core container
# KOMODO_OIDC_PROVIDER=https://oidc.provider.internal/application/o/komodo
## Change the host to one reachable be reachable by users (optional if it is the same as above).
## DO NOT include the `path` part of the URL.
# KOMODO_OIDC_REDIRECT_HOST=https://oidc.provider.external
## Your OIDC client id
# KOMODO_OIDC_CLIENT_ID= # Alt: KOMODO_OIDC_CLIENT_ID_FILE
## Your OIDC client secret.
## If your provider supports PKCE flow, this can be ommitted.
# KOMODO_OIDC_CLIENT_SECRET= # Alt: KOMODO_OIDC_CLIENT_SECRET_FILE
## Make usernames the full email.
## Note. This does not work for all OIDC providers.
# KOMODO_OIDC_USE_FULL_EMAIL=true
## Add additional trusted audiences for token claims verification.
## Supports comma separated list, and passing with _FILE (for compose secrets).
# KOMODO_OIDC_ADDITIONAL_AUDIENCES=abc,123 # Alt: KOMODO_OIDC_ADDITIONAL_AUDIENCES_FILE

## Github Oauth
KOMODO_GITHUB_OAUTH_ENABLED=false
# KOMODO_GITHUB_OAUTH_ID= # Alt: KOMODO_GITHUB_OAUTH_ID_FILE
# KOMODO_GITHUB_OAUTH_SECRET= # Alt: KOMODO_GITHUB_OAUTH_SECRET_FILE

## Google Oauth
KOMODO_GOOGLE_OAUTH_ENABLED=false
# KOMODO_GOOGLE_OAUTH_ID= # Alt: KOMODO_GOOGLE_OAUTH_ID_FILE
# KOMODO_GOOGLE_OAUTH_SECRET= # Alt: KOMODO_GOOGLE_OAUTH_SECRET_FILE

## Aws - Used to launch Builder instances and ServerTemplate instances.
KOMODO_AWS_ACCESS_KEY_ID= # Alt: KOMODO_AWS_ACCESS_KEY_ID_FILE
KOMODO_AWS_SECRET_ACCESS_KEY= # Alt: KOMODO_AWS_SECRET_ACCESS_KEY_FILE

## Hetzner - Used to launch ServerTemplate instances
## Hetzner Builder not supported due to Hetzner pay-by-the-hour pricing model
KOMODO_HETZNER_TOKEN= # Alt: KOMODO_HETZNER_TOKEN_FILE

#=------------------------------=#
#= Komodo Periphery Environment =#
#=------------------------------=#

## Full variable list + descriptions are available here:
## 🦎 https://github.com/moghtech/komodo/blob/main/config/periphery.config.toml 🦎

## Periphery passkeys must include KOMODO_PASSKEY to authenticate.
PERIPHERY_PASSKEYS=${KOMODO_PASSKEY}

## Specify the root directory used by Periphery agent.
PERIPHERY_ROOT_DIRECTORY=/opt/komodo

## Enable SSL using self signed certificates.
## Connect to Periphery at https://address:8120.
PERIPHERY_SSL_ENABLED=true

## If the disk size is overreporting, can use one of these to 
## whitelist / blacklist the disks to filter them, whichever is easier.
## Accepts comma separated list of paths.
## Usually whitelisting just /etc/hostname gives correct size.
PERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname
# PERIPHERY_EXCLUDE_DISK_MOUNTS=/snap,/etc/repos

Caddy

Abschließend richten wir zum Beispiel in Caddy (alternativ auch Nginx Proxy Manager) unseren Eintrag für Komodo ein, um es über den Domain-Namen aufrufen zu können. Bei Caddy kommt der Eintrag in das Caddyfile.

{
    acme_dns cloudflare api-key
}

komodo.example.de {
    reverse_proxy komodo-core:9120
}

In meinem Fall nutze ich die DNS-Challenge und habe in meinem DNS-Server zuhause (AdGuard) eine Umschreibung für die Domain auf die IP des Servers.


Erster Start

Nachdem wir alle nötigen Dateien erstellt haben, können wir Komodo jetzt starten.

sudo docker compose up -d

Sobald alles gestartet ist, erreichen wir Komodo unter unserer vergebenen Domain. Wir werden von einem Login-Fenster begrüßt, wo wir jetzt unseren gewünschten Namen und Passwort eingeben und anschließend auf Sign Up klicken.


Servers

Im Untermenü Servers finden wir all unsere Komodo Server. Gleichzeitig kann die Übersicht der einzelnen Server auch super als Monitoring genutzt werden, da wir ähnliche Einsichten wie auch in Beszel haben!

Weitere Server hinzufügen

Wir haben in Komodo die Möglichkeit, weitere Server hinzuzufügen. Dadurch können wir später dann per Drop-Down einfach auswählen, auf welchem Server unser Docker Stack deployed werden soll.

Zum Hinzufügen weiterer Server gibt es wieder verschiedene Varianten. Wir haben die Möglichkeit, den Periphery-Service direkt als Systemd-Dienst zu installieren oder auch hier wieder mit Docker zu arbeiten.

Für die Dienst-Variante direkt auf dem Host gibt es ein Installations-Script, was die Installation super einfach macht. Für Docker habe ich die compose und .env wieder ein wenig gepimpt.

Docker

Im Prinzip benötigen wir für einen zusätzlichen Host nur den Periphery-Teil der Compose und des Environments vom Core-Server.

Wir geben Port 8120 diesmal frei, da der Container auf einem anderen Server läuft. Ihr solltet hier den Zugang per Firewall-Regeln einschränken.

compose.yaml

####################################
# 🦎 KOMODO COMPOSE - PERIPHERY 🦎 #
####################################

## This compose file will deploy:
##   1. Komodo Periphery

services:
  periphery:
    image: ghcr.io/moghtech/komodo-periphery:${COMPOSE_KOMODO_IMAGE_TAG:-latest}
    labels:
      komodo.skip: # Prevent Komodo from stopping with StopAllContainers
    restart: unless-stopped
    ports:
      - 8120:8120
    logging:
      driver: ${COMPOSE_LOGGING_DRIVER:-local}
    ## https://komo.do/docs/connect-servers#configuration
    environment:
      PERIPHERY_REPO_DIR: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/repos
      PERIPHERY_STACK_DIR: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/stacks
      PERIPHERY_SSL_KEY_FILE: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/ssl/key.pem
      PERIPHERY_SSL_CERT_FILE: ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}/ssl/cert.pem
      ## Enable SSL using self-signed certificates.
      ## Connect to Periphery at https://address:8120.
      PERIPHERY_SSL_ENABLED: true
      ## Pass the same passkey as used by the Komodo Core connecting to this Periphery agent.
      PERIPHERY_PASSKEYS: ${PERIPHERY_PASSKEYS}
      ## If the disk size is overreporting, can use one of these to
      ## whitelist / blacklist the disks to filter them, whichever is easier.
      ## Accepts comma separated list of paths.
      ## Usually whitelisting just /etc/hostname gives correct size.
      PERIPHERY_INCLUDE_DISK_MOUNTS: /etc/hostname
      # PERIPHERY_EXCLUDE_DISK_MOUNTS: /snap,/etc/repos
    volumes:
      ## Mount external docker socket
      - /var/run/docker.sock:/var/run/docker.sock
      ## Allow Periphery to see processes outside of container
      - /proc:/proc
      ## Specify the Periphery agent root directory.
      ## Must be the same inside and outside the container,
      ## or Docker will get confused. See https://github.com/moghtech/komodo/discussions/180.
      ## Default: /etc/komodo.
      - ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}:${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}

.env

#=------------------------------=#
#= Komodo Periphery Environment =#
#=------------------------------=#

## Full variable list + descriptions are available here:
## 🦎 https://github.com/moghtech/komodo/blob/main/config/periphery.config.toml 🦎

## Periphery passkeys must include KOMODO_PASSKEY to authenticate.
PERIPHERY_PASSKEYS= #Passkey von der Core-Installation

## Specify the root directory used by Periphery agent.
PERIPHERY_ROOT_DIRECTORY=/opt/komodo

## Enable SSL using self-signed certificates.
## Connect to Periphery at https://address:8120.
PERIPHERY_SSL_ENABLED=true

## If the disk size is overreporting, can use one of these to 
## whitelist / blacklist the disks to filter them, whichever is easier.
## Accepts comma separated list of paths.
## Usually whitelisting just /etc/hostname gives correct size.
PERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname
# PERIPHERY_EXCLUDE_DISK_MOUNTS=/snap,/etc/repos

Dem Environment-File fügen wir nur noch den Passkey hinzu, den wir im File für den Core-Server vergeben haben, damit sich die beiden Server gleich verbinden können. Anschließend können wir die Compose starten und den Server im Dashboard hinzufügen.

Jetzt aktivieren wir den Server noch in den Einstellungen, und dann sollte er als Up angezeigt werden.

Stacks

Das Herzstück von Komodo. Hier werden all unsere Docker Compose Stacks aufgelistet. Wir haben in diesem Menüpunkt die Möglichkeit, unsere Stacks anzupassen und neuzustarten. Außerdem können wir hier Infos über verfügbare Updates einholen und die Stacks auch direkt updaten.

Um Docker-Stacks auf dem Host über Komodo zu verwalten, müssen wir diese zu Komodo hinzufügen. Dafür stehen drei Varianten zur Verfügung, die wir uns hier anschauen.

Komodo sucht standardmäßig immer nach Compose-Files mit dem exakten Namen compose.yaml. Um es sich also möglichst einfach zu machen, könnt ihr eure Compose-Files in Zukunft so benennen. Alternativ können jedoch auch andere Namen angegeben werden.

UI Defined

Wenn wir einen neuen Stack hinzufügen und UI Defined auswählen, haben wir von Anfang an die Möglichkeit, die Compose- und env-Files direkt in der GUI anzulegen und zu bearbeiten.

Run on Server

Diese Variante können wir zum Beispiel bei bereits bestehenden Stacks verwenden, die schon aktiv laufen. Sobald wir den Punkt auswählen, haben wir die Möglichkeit, den Pfad anzugeben, wo sich die compose-Datei des Stacks befindet.

Der Pfad muss im Periphery-Container gemountet sein, ansonsten funktioniert das nicht.

Alternativ kann der Stack auch einfach nach /opt/komodo/stacks kopiert werden.

Falls die Compose-Datei nicht compose.yaml heißt, könnt ihr darunter auch den Namen des Files angeben.

Wichtig ist hierbei auch noch der Punkt Project Name. Dieser Name muss genauso heißen wie der aktive Stack auf dem System. Falls ihr den Namen nicht wisst, könnt ihr ihn mit einem Befehl herausfinden. Per Default nimmt Komodo den Namen des erstellten Stacks.

sudo docker compose ls

Environment

Falls euer Environment-File einen bestimmten Namen hat, könnt ihr das unter dem Punkt Environment entsprechend angeben.

Git Repo

Zuletzt haben wir die Variante mit einem Git Repo. Hier haben wir die Möglichkeit, eine Compose direkt aus einem Repo zu klonen und zu verwenden.

Um ein Repo verwenden zu können, müssen wir zuerst einen GitHub- oder GitLab-Account unter den Einstellungen hinzufügen.

Token

Für den Account benötigt ihr einen Token. Bei GitHub erhaltet ihr diesen zum Beispiel unter den Entwicklereinstellungen. Hier könnt ihr entweder einen Token mit sehr filigranen Rechten nehmen und diesen nur für bestimmte Repos berechtigen oder einen klassischen Token.

Klonen eines Repos

Nachdem wir jetzt Zugang zu einem Repository haben, können wir dieses in einen Stack klonen.

Jetzt sehen wir unter Info die compose aus der Repo. Wir haben nun auch die Möglichkeit, Änderungen an der Compose in der Repo vorzunehmen und dann die neueste Version der Compose in unserem Stack in Komodo zu erhalten.

Alerters

Wir überspringen einige "Advanced"-Punkte und landen jetzt bei den Alerters. Hier haben wir die Möglichkeit, uns Benachrichtigungen für sämtliche Infos und Meldungen einzurichten. Zwei coole und wichtige Sachen sind dabei einmal die Alerts für das Monitoring der Komodo Server und zum anderen können wir uns auch Benachrichtigungen für verfügbare Updates der Stacks geben lassen. Damit kann Komodo also auch Tools wie Watchtower oder WuD ersetzen.

Updates

Kommen wir zum Schluss noch zu der Möglichkeit, uns informieren zu lassen bei möglichen Updates. Wir haben hier die Wahl zwischen Benachrichtigungen, wenn Updates verfügbar sind, oder wir lassen Komodo direkt selbständig den ganzen Stack updaten.

Alles, was wir für die Funktionen tun müssen, ist, bei den gewünschten Stacks unter Auto Update die gewünschten Haken zu setzen.

Setzen wir nur den ersten Haken, erhalten wir eine Info, wenn ein Container aus dem Stack ein Update hat.

Setzen wir den zweiten Haken ebenfalls, werden die Container automatisch immer aktuell gehalten.

Sobald ein Update verfügbar ist, wird das in der Weboberfläche angezeigt.

Wenn ihr entsprechende Alerts konfiguriert habt, erhaltet ihr auch Benachrichtigungen an den eingerichteten Service.