From 1693330162fdb672df7d739e512f6d8f59d8e1f7 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Mon, 24 Aug 2026 10:48:42 +0200 Subject: [PATCH] Terminal-Browser, konfigurierbarer Admin-Port und Einstellungsmenue Der NGINX Proxy Manager laesst sich jetzt auch dann einrichten, wenn seine Oberflaeche auf Port 81 aus dem Netz nicht erreichbar ist. browser Terminal-Browser in einem eigenen Container, gestartet mit "run --rm -it --network host" - damit erreicht er 127.0.0.1 genau wie der Proxy Manager selbst. Engines: browsh und carbonyl (rendern einen echten Browser und koennen JavaScript, das die Adminoberflaeche benoetigt) sowie links2/w3m/lynx und eine Shell mit curl/jq/openssl fuer Diagnose. Werkzeug-Image unter containers/browser/. Bewusst kein Compose-Dienst: ein Browser ist interaktiv, und podman-compose behandelt Profile unzuverlaessig. npm-port Port der Adminoberflaeche frei waehlbar. Das Image bindet fest auf 81 ("listen 81 default;"), eine Umgebungsvariable dafuer gibt es in 2.15.1 noch nicht. Ein abweichender Port wird deshalb ueber den nginx- Erweiterungspunkt /data/nginx/custom/http.conf bereitgestellt. Nur der markierte Block wird verwaltet, eigene Eintraege bleiben erhalten. Port 81 lauscht weiterhin lokal und ist per Firewall zu sperren. config Alle Werte der .env sind menuegefuehrt bzw. ueber config get/set aenderbar - der Editor bleibt als Menuepunkt erhalten. Geprueft wird beim Setzen: Portbereich und Kollisionen, Site-Namen, vollqualifizierte Image-Namen, installierte Runtime, Zahlen- und URL-Felder. Fehlerbehebungen - ui_*-Funktionen initialisieren sich selbst; eine von aussen gesetzte UI_BIN fuehrte unter "set -u" zum Abbruch. - Eine nicht installierte CMK_RUNTIME machte das gesamte Werkzeug unbenutzbar, auch den Aufruf zum Korrigieren. Jetzt wird gewarnt und selbst gesucht. - env_set setzt Werte mit Leerzeichen in Anfuehrungszeichen und laesst optional leere Werte zu. README auf 22 Kapitel erweitert: Kapitel 11 (Terminal-Browser inkl. NPM-API als Fallback fuer den Zertifikats-Upload), Kapitel 12 (Admin-Port) und Abschnitt 14.3 (Einstellungsmenue). Co-Authored-By: Claude Opus 5 (1M context) --- .env.example | 127 +- .gitignore | 2 + README.md | 636 ++++++++- containers/browser/Containerfile | 37 + docker-compose.yml | 8 +- images/.gitkeep | 0 install.sh | 15 +- scripts/cmk-manage.sh | 1224 ++++++++++++++++- scripts/lib/common.sh | 59 +- scripts/migrate_creator.sh | 16 +- systemd/quadlet/checkmk.container | 2 +- systemd/quadlet/nginx-proxy-manager.container | 2 +- 12 files changed, 2015 insertions(+), 113 deletions(-) create mode 100644 containers/browser/Containerfile create mode 100644 images/.gitkeep diff --git a/.env.example b/.env.example index bf86d42..43657f2 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,15 @@ # ===================================================================== # Checkmk + NGINX Proxy Manager - zentrale Konfiguration # Kopieren nach ".env" und anpassen: cp .env.example .env +# +# Diese Datei ist die EINZIGE Quelle der Wahrheit. Sie wird gelesen von +# * docker-compose.yml / podman-compose (Variablen-Ersetzung) +# * der systemd-Unit (EnvironmentFile=) +# * scripts/cmk-manage.sh (source) +# Das Verwaltungsskript SCHREIBT hier nur hinein (z.B. CMK_IMAGE), +# es haelt keine zweite Konfiguration. +# +# Werte mit Leerzeichen bitte in Anfuehrungszeichen setzen. # ===================================================================== # --------------------------------------------------------------------- @@ -8,17 +17,60 @@ # --------------------------------------------------------------------- CMK_RUNTIME= -# --------------------------------------------------------------------- -# Checkmk -# --------------------------------------------------------------------- -# Raw Edition (frei): checkmk/check-mk-raw -# Enterprise (Subskription): checkmk/check-mk-enterprise -CMK_IMAGE_REPO=checkmk/check-mk-raw +# ===================================================================== +# CHECKMK-IMAGE +# ===================================================================== +# Das ist der einzige Wert, den compose/systemd tatsaechlich verwendet. +# +# IMMER VOLLQUALIFIZIERT ANGEBEN (mit Registry-Praefix)! +# Podman loest kurze Namen ueber "unqualified-search-registries" auf - +# auf RHEL steht dort registry.access.redhat.com an erster Stelle. Ein +# kurzer Name wie "checkmk/check-mk-enterprise" wird deshalb dort gesucht +# und nicht gefunden ("image not known") oder es erscheint eine Abfrage. +# +# Beispiele: +# docker.io/checkmk/check-mk-raw:2.3.0-latest +# registry.checkmk.com/enterprise/check-mk-enterprise:2.3.0p23 +# localhost/checkmk/check-mk-enterprise:2.3.0p23 (aus Tarball geladen) +CMK_IMAGE=docker.io/checkmk/check-mk-raw:2.3.0-latest -# WICHTIG bei Migration: Die Version MUSS zur Version der Quell-Site passen, -# sonst schlaegt "omd restore" fehl. Beispiele: 2.3.0-latest, 2.3.0p23, 2.2.0p39 -CMK_IMAGE_TAG=2.3.0-latest +# --------------------------------------------------------------------- +# Nur fuer den Image-Downloader: scripts/cmk-manage.sh image ... +# Daraus wird CMK_IMAGE ermittelt und oben automatisch eingetragen. +# --------------------------------------------------------------------- +# Edition: +# raw Docker Hub, frei (bis 2.4) +# community Docker Hub, frei (ab 2.5, Nachfolger von "raw") +# enterprise NUR registry.checkmk.com oder Tarball - NICHT auf Docker Hub! +# pro Docker Hub (ab 2.5, Nachfolger von "enterprise") +# cloud Docker Hub +# managed Docker Hub (bis 2.4) +# ultimate Docker Hub (ab 2.5) +# ultimatemt Docker Hub (ab 2.5, Nachfolger von "managed") +CMK_EDITION=raw +# Konkrete Version. Fuer den Tarball-Download muss eine exakte Version +# angegeben werden (z.B. 2.3.0p23), "-latest" funktioniert dort nicht. +CMK_VERSION=2.3.0-latest + +# --- Bezugsweg 1: private Registry (Enterprise) ---------------------- +# Zugangsdaten aus dem Checkmk-Kundenportal (portal.checkmk.com) +CMK_REGISTRY=registry.checkmk.com +CMK_REGISTRY_USER= +CMK_REGISTRY_PASSWORD= + +# --- Bezugsweg 2: Image-Tarball vom Download-Portal ------------------ +# Zugangsdaten der Checkmk-Downloadseite. Der Downloader probiert die +# ueblichen Dateinamen unter // durch; mit +# CMK_DOWNLOAD_URL laesst sich die vollstaendige URL fest vorgeben. +CMK_DOWNLOAD_BASEURL=https://download.checkmk.com/checkmk +CMK_DOWNLOAD_URL= +CMK_DOWNLOAD_USER= +CMK_DOWNLOAD_PASSWORD= + +# ===================================================================== +# CHECKMK-LAUFZEIT +# ===================================================================== CMK_CONTAINER_NAME=checkmk CMK_HOSTNAME=checkmk @@ -38,28 +90,59 @@ MAIL_RELAY_HOST= # Zeitzone TZ=Europe/Berlin -# --------------------------------------------------------------------- -# NGINX Proxy Manager (HTTPS-Terminierung, Let's Encrypt ODER self-signed) -# --------------------------------------------------------------------- -NPM_IMAGE=jc21/nginx-proxy-manager:2 +# ===================================================================== +# NGINX PROXY MANAGER (HTTPS: Let's Encrypt ODER selbstsigniert) +# ===================================================================== +# Ebenfalls vollqualifiziert - siehe Hinweis oben zu Podman! +NPM_IMAGE=docker.io/jc21/nginx-proxy-manager:2 NPM_CONTAINER_NAME=nginx-proxy-manager NPM_DISABLE_IPV6=true -# --------------------------------------------------------------------- -# Pfade (relativ zum Projektverzeichnis) - ausschliesslich Bind-Mounts, -# keine Docker/Podman-Volumes! -# --------------------------------------------------------------------- +# Port der Adminoberflaeche. Vorgabe im Image ist fest 81; ein abweichender +# Port wird ueber einen zusaetzlichen nginx-Server bereitgestellt. +# NICHT von Hand aendern - dabei muss die nginx-Zusatzdatei mitgezogen werden: +# ./scripts/cmk-manage.sh npm-port 10443 +# oder im Menue unter "Einstellungen". +NPM_ADMIN_PORT=81 + +# ===================================================================== +# TERMINAL-BROWSER (lokale Bedienung des Proxy Managers) +# Fuer den Fall, dass Port 81 von aussen nicht erreichbar ist. +# Aufruf: ./scripts/cmk-manage.sh browser +# ===================================================================== +# Startseite des Browsers. Leer = automatisch aus NPM_ADMIN_PORT abgeleitet. +NPM_ADMIN_URL= + +# Vorgabe-Engine: browsh | carbonyl | links | w3m | lynx | shell +# ACHTUNG: nur browsh und carbonyl koennen JavaScript und damit die +# Oberflaeche des Proxy Managers darstellen. +BROWSER_ENGINE=browsh + +# Images der Engines (vollqualifiziert - siehe Podman-Hinweis oben) +BROWSH_IMAGE=docker.io/browsh/browsh:v1.8.3 +CARBONYL_IMAGE=docker.io/fathyb/carbonyl:latest + +# Selbst gebautes Werkzeug-Image (Textbrowser, curl, jq, openssl). +# Leer lassen - das Skript waehlt automatisch den zur Runtime passenden +# Namen (Podman braucht das Praefix "localhost/", Docker darf es nicht haben). +BROWSER_TOOLS_IMAGE= + +# ===================================================================== +# PFADE (relativ zum Projektverzeichnis) +# Ausschliesslich Bind-Mounts - keine Docker/Podman-Volumes! +# ===================================================================== CMK_DATA_DIR=./data/checkmk/sites NPM_DATA_DIR=./data/npm/data NPM_LE_DIR=./data/npm/letsencrypt -# Ablage fuer Backups / Migrations-Bundles (Host-Pfad) +# Ablage fuer Backups / Migrations-Bundles und heruntergeladene Images BACKUP_DIR=./backups +IMAGE_DIR=./images -# --------------------------------------------------------------------- -# Self-signed Zertifikat (Vorgaben fuer scripts/cmk-manage.sh cert) -# --------------------------------------------------------------------- +# ===================================================================== +# SELBSTSIGNIERTES ZERTIFIKAT (Vorgaben fuer "cmk-manage.sh cert") +# ===================================================================== CERT_DOMAIN=checkmk.example.local CERT_DAYS=3650 CERT_COUNTRY=DE -CERT_ORG="Beispiel GmbH" # Werte mit Leerzeichen bitte in Anfuehrungszeichen +CERT_ORG="Beispiel GmbH" diff --git a/.gitignore b/.gitignore index 93c84b6..54d9531 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ backups/* !backups/.gitkeep *.tar.gz *.log +images/* +!images/.gitkeep diff --git a/README.md b/README.md index ff7fecd..b99461f 100644 --- a/README.md +++ b/README.md @@ -17,18 +17,21 @@ werden müssen. 5. [Installation auf RHEL/Rocky/Alma/Fedora (Podman)](#5-installation-auf-rhelrockyalmafedora-podman) 6. [Autostart nach einem Neustart des Hosts (Podman)](#6-autostart-nach-einem-neustart-des-hosts-podman) 7. [Konfiguration (`.env`)](#7-konfiguration-env) -8. [Erststart](#8-erststart) -9. [HTTPS einrichten – Let's Encrypt oder selbstsigniert](#9-https-einrichten--lets-encrypt-oder-selbstsigniert) -10. [Firewall](#10-firewall) -11. [Verwaltung: `cmk-manage.sh` (CLI und ncurses-Oberfläche)](#11-verwaltung-cmk-managesh) -12. [Backup](#12-backup) -13. [Restore](#13-restore) -14. [Migration einer Direktinstallation (`migrate_creator.sh`)](#14-migration-einer-direktinstallation-migrate_creatorsh) -15. [Mehrere Sites in einem Container](#15-mehrere-sites-in-einem-container) -16. [Checkmk aktualisieren](#16-checkmk-aktualisieren) -17. [Fehlersuche](#17-fehlersuche) -18. [Sicherheitshinweise](#18-sicherheitshinweise) -19. [Deinstallation](#19-deinstallation) +8. [Checkmk-Image beschaffen (Raw, Enterprise & Co.)](#8-checkmk-image-beschaffen-raw-enterprise--co) +9. [Erststart](#9-erststart) +10. [HTTPS einrichten – Let's Encrypt oder selbstsigniert](#10-https-einrichten--lets-encrypt-oder-selbstsigniert) +11. [Proxy Manager lokal einrichten (Terminal-Browser)](#11-proxy-manager-lokal-einrichten-terminal-browser) +12. [Adminoberfläche auf einen anderen Port legen](#12-adminoberfläche-auf-einen-anderen-port-legen) +13. [Firewall](#13-firewall) +14. [Verwaltung: `cmk-manage.sh` (CLI und ncurses-Oberfläche)](#14-verwaltung-cmk-managesh) +15. [Backup](#15-backup) +16. [Restore](#16-restore) +17. [Migration einer Direktinstallation (`migrate_creator.sh`)](#17-migration-einer-direktinstallation-migrate_creatorsh) +18. [Mehrere Sites in einem Container](#18-mehrere-sites-in-einem-container) +19. [Checkmk aktualisieren](#19-checkmk-aktualisieren) +20. [Fehlersuche](#20-fehlersuche) +21. [Sicherheitshinweise](#21-sicherheitshinweise) +22. [Deinstallation](#22-deinstallation) --- @@ -83,6 +86,10 @@ werden müssen. │ └── lib/ │ └── common.sh # gemeinsame Funktionen + TUI-Helfer │ +├── containers/ +│ └── browser/ +│ └── Containerfile # Werkzeug-Image: Textbrowser, curl, jq, openssl +│ ├── systemd/ │ ├── checkmk-stack.service.example # Compose-basierte Unit (Autostart) │ └── quadlet/ @@ -96,7 +103,8 @@ werden müssen. │ ├── letsencrypt/ # -> /etc/letsencrypt (Zertifikate) │ └── custom-certs/ # selbstsignierte Zertifikate zum Hochladen │ -└── backups/ # Backups und Migrations-Bundles (*.tar.gz) +├── backups/ # Backups und Migrations-Bundles (*.tar.gz) +└── images/ # heruntergeladene Checkmk-Image-Tarballs ``` --- @@ -114,7 +122,7 @@ werden müssen. |---|---|---| | 80/tcp | NGINX Proxy Manager – HTTP, Let's-Encrypt-Challenge | Internet/LAN | | 443/tcp | NGINX Proxy Manager – HTTPS | Internet/LAN | -| 81/tcp | NGINX Proxy Manager – **Adminoberfläche** | nur Admin-Netz! | +| 81/tcp | NGINX Proxy Manager – **Adminoberfläche** (Vorgabe; per [`npm-port`](#12-adminoberfläche-auf-einen-anderen-port-legen) änderbar) | nur Admin-Netz! | | 5000/tcp | Checkmk Apache (Backend) | **nur localhost** – nicht freigeben | | 8000/tcp | Checkmk Agent-Receiver (TLS-registrierte Agents) | überwachte Hosts | | 6557/tcp | Livestatus (nur bei `CMK_LIVESTATUS_TCP=on`) | verteilte Sites | @@ -151,6 +159,10 @@ Anschließend: ```bash sudo $EDITOR /opt/checkmk-stack/.env # mindestens CMK_PASSWORD und CMK_SITE_ID + +# Image festlegen (Raw geht ohne Anmeldung, Enterprise siehe Kapitel 8) +sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0-latest + sudo ./scripts/cmk-manage.sh up sudo ./scripts/cmk-manage.sh status ``` @@ -158,7 +170,7 @@ sudo ./scripts/cmk-manage.sh status Unter Docker sorgt bereits `restart: unless-stopped` dafür, dass die Container nach einem Reboot wieder starten (der Docker-Daemon startet sie). Die systemd-Unit ist trotzdem sinnvoll, weil sie zusätzlich **alle** Sites startet -(siehe [Kapitel 15](#15-mehrere-sites-in-einem-container)). +(siehe [Kapitel 18](#18-mehrere-sites-in-einem-container)). --- @@ -195,10 +207,19 @@ Starten: ```bash sudo $EDITOR /opt/checkmk-stack/.env + +# Image beschaffen - bei Enterprise mit Zugangsdaten, siehe Kapitel 8 +sudo ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \ + --user --password + sudo ./scripts/cmk-manage.sh up # nutzt automatisch podman-compose sudo ./scripts/cmk-manage.sh status ``` +> Auf RHEL unbedingt [Kapitel 8.2](#8-checkmk-image-beschaffen-raw-enterprise--co) +> lesen: kurze Image-Namen und `podman import` statt `podman load` sind die +> beiden Ursachen fuer „Image unbekannt“. + ### SELinux Die Bind-Mounts sind in `docker-compose.yml` mit `:Z` versehen, Podman setzt @@ -330,19 +351,204 @@ Die wichtigsten Schalter: | Variable | Bedeutung | |---|---| | `CMK_RUNTIME` | leer = automatische Erkennung, sonst `docker` oder `podman` | -| `CMK_IMAGE_REPO` | `checkmk/check-mk-raw` (frei) oder `checkmk/check-mk-enterprise` | -| `CMK_IMAGE_TAG` | **Version** – bei einer Migration muss sie zur Quell-Site passen! | +| `CMK_IMAGE` | **das tatsaechlich verwendete Image**, immer vollqualifiziert – siehe [Kapitel 8](#8-checkmk-image-beschaffen-raw-enterprise--co) | +| `CMK_EDITION`, `CMK_VERSION` | nur Vorgaben fuer den Image-Downloader | +| `CMK_REGISTRY_USER/-PASSWORD` | Anmeldung an `registry.checkmk.com` (Enterprise) | +| `CMK_DOWNLOAD_USER/-PASSWORD` | Anmeldung am Checkmk-Downloadportal | | `CMK_SITE_ID` | Site, die der Container anlegt bzw. beim Start hochfährt | | `CMK_PASSWORD` | Startpasswort für den Benutzer `cmkadmin` (nur bei Neuanlage) | | `CMK_LIVESTATUS_TCP` | `on` öffnet Port 6557 für verteilte Überwachung | | `MAIL_RELAY_HOST` | SMTP-Relay für Benachrichtigungen | | `TZ` | Zeitzone, z. B. `Europe/Berlin` | +| `NPM_ADMIN_PORT` | Port der Proxy-Manager-Oberfläche (Vorgabe 81) – nur über `npm-port` bzw. das Menü ändern | +| `NPM_ADMIN_URL` | Startseite des Terminal-Browsers; leer = automatisch aus `NPM_ADMIN_PORT` | | `BACKUP_DIR` | Ablage für Backups/Bundles (Vorgabe `./backups`) | | `CERT_DOMAIN`, `CERT_DAYS` | Vorgaben für selbstsignierte Zertifikate | +### 7.1 Wer liest die `.env` – und warum gibt es sie zusätzlich zum Skript? + +Die `.env` ist die **einzige** Konfigurationsdatei. Es gibt bewusst keine zweite +Konfiguration im Verwaltungsskript: + +``` + .env (einzige Quelle der Wahrheit) + | + +---------------+----------------+------------------+ + | | | | +docker-compose systemd-Unit cmk-manage.sh migrate_creator.sh +(Variablen- (EnvironmentFile) (source) (unabhaengig, laeuft + ersetzung) auf dem Quellserver) +``` + +* **Gelesen** wird sie von compose, von der systemd-Unit und vom Skript. +* **Geschrieben** wird sie durch das Skript – entweder gezielt + (`image …` setzt `CMK_IMAGE`, `import --set-default-site` setzt + `CMK_SITE_ID`, `npm-port` setzt `NPM_ADMIN_PORT`) oder über das + Einstellungsmenü bzw. `config set` (siehe [Kapitel 14](#14-verwaltung-cmk-managesh)). + Ein Editor ist damit nicht mehr nötig, bleibt aber als Menüpunkt erhalten. +* Das Skript selbst haelt nur **Rueckfallwerte** fuer den Fall, dass ein + Schluessel in der `.env` fehlt (in `scripts/lib/common.sh`, Funktion + `load_env`). Es ueberschreibt niemals einen gesetzten Wert. + +Kurz: die `.env` sagt *was* laeuft, das Skript *macht* etwas damit. Doppelt +gepflegt werden muss nichts. + --- -## 8. Erststart +## 8. Checkmk-Image beschaffen (Raw, Enterprise & Co.) + +### 8.1 Welche Edition liegt wo? + +Das ist die haeufigste Stolperfalle: **die Enterprise-Edition liegt nicht auf +Docker Hub.** Im Namensraum `checkmk` auf Docker Hub gibt es ausschliesslich: + +| Edition (`CMK_EDITION`) | Bezugsquelle | Anmeldung | +|---|---|---| +| `raw` (bis 2.4) | `docker.io/checkmk/check-mk-raw` | nein | +| `community` (ab 2.5, Nachfolger von raw) | `docker.io/checkmk/check-mk-community` | nein | +| `cloud` | `docker.io/checkmk/check-mk-cloud` | nein | +| `managed` (bis 2.4) | `docker.io/checkmk/check-mk-managed` | nein | +| `pro` (ab 2.5, Nachfolger von enterprise) | `docker.io/checkmk/check-mk-pro` | nein | +| `ultimate`, `ultimatemt` (ab 2.5) | `docker.io/checkmk/check-mk-ultimate[mt]` | nein | +| **`enterprise` (2.0 – 2.4)** | **`registry.checkmk.com/enterprise/check-mk-enterprise`** oder Image-Tarball aus dem Kundenportal | **ja** | +| `free` (historisch, bis 2.1) | `docker.io/checkmk/check-mk-free` | nein | + +Ab Checkmk 2.5 wurden die Editionen umbenannt (Raw → Community, +Enterprise → Pro, Managed → Ultimate MT); diese Images liegen wieder offen auf +Docker Hub. Wer also eine **2.5 oder neuer** einsetzt, nimmt einfach `pro`. +Fuer **2.2/2.3/2.4-Enterprise** fuehrt nur der Weg ueber `registry.checkmk.com` +oder den Tarball. + +> Frei herunterladbar heisst nicht lizenzfrei – der Lizenzschluessel wird +> anschliessend in Checkmk selbst hinterlegt. + +### 8.2 Zwei Podman-Fallstricke (genau die aus der Praxis) + +**1. Kurze Image-Namen.** Podman kennt keine Vorgabe-Registry. Kurze Namen wie +`checkmk/check-mk-enterprise:2.3.0p23` werden ueber +`unqualified-search-registries` aus `/etc/containers/registries.conf` aufgeloest +– auf RHEL steht dort `registry.access.redhat.com` an **erster** Stelle. Podman +sucht das Image also bei Red Hat, findet es nicht und meldet +`image not known` bzw. fragt interaktiv nach. Deshalb steht in `.env` und +`docker-compose.yml` konsequent der **vollqualifizierte** Name: + +``` +CMK_IMAGE=registry.checkmk.com/enterprise/check-mk-enterprise:2.3.0p23 +``` + +Aktuelle Auflösungsreihenfolge ansehen: + +```bash +grep -A3 unqualified-search-registries /etc/containers/registries.conf +``` + +**2. `import` statt `load`.** Ein heruntergeladener Image-Tarball wird mit +**`load`** eingespielt: + +| Kommando | Erwartet | Ergebnis | +|---|---|---| +| `podman import datei.tar.gz` | ein **Dateisystem**-Archiv (rootfs) | Image **ohne** Entrypoint, ohne Umgebung, ohne Tag → unbrauchbar, „Image unbekannt“ | +| `podman load -i datei.tar.gz` | ein **Image**-Archiv (`docker save`/OCI) | vollstaendiges Image inkl. Metadaten und Tag ✔ | + +Ein mit `import` erzeugtes Fehl-Image wieder loswerden: + +```bash +podman images | grep '' +podman rmi +``` + +`cmk-manage.sh image load` prueft das Archiv vorher auf `manifest.json` bzw. +`oci-layout` und weist ein falsches Archiv mit genau diesem Hinweis ab. + +### 8.3 Zugangsdaten in der `.env` hinterlegen + +```bash +CMK_EDITION=enterprise +CMK_VERSION=2.3.0p23 + +# Bezugsweg 1 - private Registry +CMK_REGISTRY=registry.checkmk.com +CMK_REGISTRY_USER= +CMK_REGISTRY_PASSWORD= + +# Bezugsweg 2 - Tarball vom Downloadportal +CMK_DOWNLOAD_BASEURL=https://download.checkmk.com/checkmk +CMK_DOWNLOAD_USER= +CMK_DOWNLOAD_PASSWORD= +``` + +Die Zugangsdaten stammen aus dem Checkmk-Kundenportal (portal.checkmk.com). +Die `.env` sollte deshalb `chmod 600` haben – `install.sh` setzt das. + +### 8.4 Image holen – drei Wege + +**a) Aus einer Registry (empfohlen)** + +```bash +# frei verfuegbar, ohne Anmeldung +sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0-latest + +# Enterprise mit Anmeldung an registry.checkmk.com +sudo ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \ + --user --password +``` + +**b) Image-Tarball vom Downloadportal (mit Zugangsdaten)** + +```bash +sudo ./scripts/cmk-manage.sh image download --edition enterprise --version 2.3.0p23 \ + --user --password +``` + +Der Downloader probiert die ueblichen Dateinamen unter +`//` durch +(`check-mk-enterprise-.docker.tar.gz` und +`check-mk-enterprise-docker-.tar.gz`). Falls Checkmk das Schema +geaendert hat, laesst sich die vollstaendige URL direkt vorgeben: + +```bash +sudo ./scripts/cmk-manage.sh image download \ + --url 'https://download.checkmk.com/checkmk/2.3.0p23/check-mk-enterprise-2.3.0p23.docker.tar.gz' \ + --user --password +``` + +Die Zugangsdaten werden per temporaerer `.netrc`-Datei an `curl` uebergeben und +tauchen damit **nicht** in der Prozessliste auf. + +**c) Bereits heruntergeladene Datei einspielen** + +Wer die Datei im Browser aus dem Kundenportal geladen hat: + +```bash +sudo ./scripts/cmk-manage.sh image load --file /root/check-mk-enterprise-2.3.0p23.docker.tar.gz +``` + +In allen drei Faellen ermittelt das Skript den **tatsaechlichen** Image-Namen +(bei `load` z. B. `localhost/checkmk/check-mk-enterprise:2.3.0p23`) und traegt +ihn als `CMK_IMAGE` in die `.env` ein. Danach: + +```bash +sudo ./scripts/cmk-manage.sh up +``` + +### 8.5 Nachsehen, was gilt + +```bash +./scripts/cmk-manage.sh image status # konfiguriertes + lokale Images +./scripts/cmk-manage.sh image list # nur lokale Checkmk-Images +./scripts/cmk-manage.sh image use localhost/checkmk/check-mk-enterprise:2.3.0p23 +``` + +`image status` warnt ausdruecklich, wenn `CMK_IMAGE` ein kurzer Name ohne +Registry ist. + +In der ncurses-Oberflaeche liegt derselbe Ablauf unter dem Menuepunkt +**„Checkmk-Image beschaffen/auswaehlen“** (Edition auswaehlen → Version → +Zugangsdaten → holen). + +--- + +## 9. Erststart ```bash sudo ./scripts/cmk-manage.sh up @@ -367,15 +573,24 @@ Zugang NGINX Proxy Manager : http://10.0.0.5:81/ (Erstlogin: admin@example.com / changeme) ``` +Der Port der Adminoberfläche folgt `NPM_ADMIN_PORT` aus der `.env`; die Ausgabe +zeigt immer den tatsächlich eingestellten Wert. + +``` +``` + Anmeldung an Checkmk: Benutzer `cmkadmin`, Passwort aus `CMK_PASSWORD`. --- -## 9. HTTPS einrichten – Let's Encrypt oder selbstsigniert +## 10. HTTPS einrichten – Let's Encrypt oder selbstsigniert ### 9.1 NGINX Proxy Manager vorbereiten -1. `http://:81` aufrufen +1. `http://:81` aufrufen – bzw. den in `NPM_ADMIN_PORT` gesetzten Port + (siehe [Kapitel 12](#12-adminoberfläche-auf-einen-anderen-port-legen)); + ist der Port im Netz gesperrt, hilft der Terminal-Browser aus + [Kapitel 11](#11-proxy-manager-lokal-einrichten-terminal-browser) 2. Erstanmeldung: **admin@example.com** / **changeme** 3. Sofort E-Mail-Adresse und Passwort ändern (wird beim ersten Login erzwungen) @@ -458,7 +673,243 @@ Zertifikat erzeugen“*. --- -## 10. Firewall +## 11. Proxy Manager lokal einrichten (Terminal-Browser) + +Wenn Port 81 aus dem Netz nicht erreichbar ist, muss die Adminoberfläche des +NGINX Proxy Managers **auf der Maschine selbst** bedient werden. Dafür startet +`cmk-manage.sh browser` einen weiteren Container im Host-Netzwerk – der erreicht +`127.0.0.1:81` genauso wie der Proxy Manager selbst. + +```bash +sudo ./scripts/cmk-manage.sh browser +``` + +Das ist bewusst **kein** Dienst in der `docker-compose.yml`: ein Browser ist ein +interaktives Programm mit Terminal, kein Hintergrunddienst. Er wird mit +`run --rm -it` gestartet und verschwindet beim Beenden wieder rückstandslos. + +### 11.1 Warum kein `lynx` + +Die Adminoberfläche des Proxy Managers ist eine JavaScript-Anwendung. Klassische +Textbrowser können sie **nicht** darstellen – man sieht eine leere Seite. Es +gibt deshalb zwei Engines, die einen vollwertigen Browser im Terminal rendern: + +| Engine | Basis | JavaScript | Proxy Manager bedienbar | +|---|---|---|---| +| `browsh` | Firefox | ja | **ja** – Vorgabe, gepflegt | +| `carbonyl` | Chromium | ja | **ja** – schönere Darstellung, Stand 2023 | +| `links` (links2) | Textbrowser | nein | nein | +| `w3m` | Textbrowser | nein | nein | +| `lynx` | Textbrowser | nein | nein | +| `shell` | Bash + curl/jq/openssl | – | für Diagnose und die API | + +Die Textbrowser sind trotzdem eingebaut, weil sie für schnelle Prüfungen +praktisch sind. Wählt man sie, warnt das Skript ausdrücklich. + +### 11.2 Bedienung + +```bash +# Vorgabe: browsh auf http://127.0.0.1:81 +sudo ./scripts/cmk-manage.sh browser + +# andere Engine oder andere Seite +sudo ./scripts/cmk-manage.sh browser --engine carbonyl +sudo ./scripts/cmk-manage.sh browser --engine links --url http://127.0.0.1:5000/cmk/ + +# Shell mit Netzwerkwerkzeugen im Host-Netzwerk +sudo ./scripts/cmk-manage.sh browser --engine shell +``` + +Tastenbelegung in **browsh**: + +| Taste | Wirkung | +|---|---| +| `Strg+L` | Adresszeile | +| `Strg+T` | neuer Tab | +| `Strg+W` | Tab schließen | +| `Strg+Q` | beenden | + +Beim ersten Aufruf einer Textbrowser- oder `shell`-Engine baut das Skript ein +kleines Werkzeug-Image (Debian slim mit links2, w3m, lynx, curl, jq, openssl, +rund 170 MB). Vorab bauen – auch ohne Terminal, etwa im Installationsskript: + +```bash +sudo ./scripts/cmk-manage.sh browser --build-only +``` + +`browsh` und `carbonyl` werden dagegen als fertige Images geladen; die Namen +stehen in der `.env` (`BROWSH_IMAGE`, `CARBONYL_IMAGE`) und sind +vollqualifiziert, damit Podman sie nicht bei `registry.access.redhat.com` sucht. + +In der ncurses-Oberfläche liegt alles unter **„Terminal-Browser (Proxy Manager +lokal bedienen)"**. + +### 11.3 Grenze: Datei-Upload + +Ein Terminal-Browser kann keinen Dateiauswahl-Dialog des Betriebssystems +öffnen. Für **Let's Encrypt** ist das egal (dort werden nur Formularfelder +ausgefüllt), aber das Hochladen eines **selbstsignierten Zertifikats** +(*SSL Certificates → Custom*) funktioniert so nicht zuverlässig. + +Für genau diesen Fall führt der Weg über die REST-Schnittstelle des Proxy +Managers. Zertifikat wie in [Kapitel 10.4](#10-https-einrichten--lets-encrypt-oder-selbstsigniert) +erzeugen, dann: + +```bash +NPM=http://127.0.0.1:81 +CERTDIR=./data/npm/custom-certs/checkmk.intern.example + +# 1) Anmelden und Token holen +TOKEN=$(curl -s -X POST "$NPM/api/tokens" \ + -H 'Content-Type: application/json' \ + -d '{"identity":"admin@example.com","secret":""}' | jq -r .token) + +# 2) Zertifikatseintrag anlegen (provider "other" = eigenes Zertifikat) +CERT_ID=$(curl -s -X POST "$NPM/api/nginx/certificates" \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d '{"provider":"other","nice_name":"checkmk-selfsigned","domain_names":["checkmk.intern.example"]}' \ + | jq -r .id) + +# 3) Schlüssel und Zertifikat hochladen +curl -s -X POST "$NPM/api/nginx/certificates/$CERT_ID/upload" \ + -H "Authorization: Bearer $TOKEN" \ + -F "certificate=@$CERTDIR/fullchain.pem" \ + -F "certificate_key=@$CERTDIR/privkey.pem" + +# 4) Proxy-Host für Checkmk anlegen +curl -s -X POST "$NPM/api/nginx/proxy-hosts" \ + -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \ + -d "{\"domain_names\":[\"checkmk.intern.example\"], + \"forward_scheme\":\"http\", + \"forward_host\":\"127.0.0.1\", + \"forward_port\":5000, + \"certificate_id\":$CERT_ID, + \"ssl_forced\":true, + \"http2_support\":true, + \"block_exploits\":true, + \"allow_websocket_upgrade\":true, + \"advanced_config\":\"client_max_body_size 0;\", + \"enabled\":true, + \"meta\":{}}" +``` + +`curl` und `jq` sind im Werkzeug-Image enthalten, falls der Host sie nicht hat: + +```bash +sudo ./scripts/cmk-manage.sh browser --engine shell +``` + +> Beim allerersten Login erzwingt der Proxy Manager das Ändern von +> E-Mail-Adresse und Kennwort. Das geht am einfachsten im Browser +> (`cmk-manage.sh browser`); danach funktioniert die API mit den neuen Daten. + +### 11.4 Alternative: SSH-Tunnel + +Falls SSH auf die Maschine möglich ist, ist der Tunnel der bequemste Weg – +dann bedient man die Oberfläche im gewohnten Browser: + +```bash +ssh -N -L 8081:127.0.0.1:81 benutzer@checkmk-server +# danach lokal: http://127.0.0.1:8081 +``` + +Das ändert nichts an der Firewall: Port 81 bleibt von außen dicht, der Zugriff +läuft durch die bestehende SSH-Verbindung. + +--- + +## 12. Adminoberfläche auf einen anderen Port legen + +Die Weboberfläche des NGINX Proxy Managers hört im Image **fest auf Port 81** +(`listen 81 default;` in `/etc/nginx/conf.d/production.conf`). Eine +Umgebungsvariable dafür gibt es in den veröffentlichten 2.x-Versionen noch +nicht – im Entwicklungszweig ist `NPM_ADMIN_PORT` bereits vorbereitet, in +Version 2.15.1 aber noch nicht enthalten. Und weil beide Container im +Host-Netzwerk laufen, lässt sich der Port auch nicht per Port-Mapping +verschieben. + +Ist Port 81 im Netz gesperrt, hilft deshalb: + +```bash +sudo ./scripts/cmk-manage.sh npm-port 10443 +``` + +### 12.1 Was dabei passiert + +nginx bindet innerhalb seines `http{}`-Blocks einen offiziellen +Erweiterungspunkt ein: + +``` +include /data/nginx/custom/http.conf; +``` + +`/data` ist unser Bind-Mount `./data/npm/data`. Dort legt das Kommando einen +zusätzlichen Server an, der auf dem gewünschten Port lauscht und an die +Oberfläche auf `127.0.0.1:81` weiterreicht: + +``` +./data/npm/data/nginx/custom/http.conf + +# >>> cmk-manage.sh: Admin-Port - nicht von Hand aendern >>> +server { + listen 10443; + listen [::]:10443; + server_name _; + client_max_body_size 0; + location / { + proxy_pass http://127.0.0.1:81; + ... + } +} +# <<< cmk-manage.sh: Admin-Port <<< +``` + +Nur der Bereich zwischen den beiden Markierungen wird verwaltet – eigene +Ergänzungen in derselben Datei bleiben unangetastet. Anschließend startet das +Skript den Proxy-Manager-Container neu, damit nginx die Datei liest, und trägt +`NPM_ADMIN_PORT` sowie `NPM_ADMIN_URL` in die `.env` ein. Der Terminal-Browser +aus [Kapitel 11](#11-proxy-manager-lokal-einrichten-terminal-browser) startet +dann automatisch auf dem neuen Port. + +### 12.2 Wichtig: Port 81 bleibt lokal bestehen + +Der eingebaute Server auf Port 81 lässt sich so **nicht** abschalten – er +lauscht weiter auf allen Adressen. Das ist unkritisch, solange die Firewall ihn +sperrt, und genau so ist die Empfehlung: + +```bash +# firewalld +sudo firewall-cmd --permanent --add-port=10443/tcp +sudo firewall-cmd --permanent --remove-port=81/tcp 2>/dev/null +sudo firewall-cmd --reload + +# ufw +sudo ufw allow 10443/tcp +sudo ufw delete allow 81/tcp 2>/dev/null +``` + +### 12.3 Stand ansehen und zurücksetzen + +```bash +./scripts/cmk-manage.sh npm-port # aktuellen Stand anzeigen +sudo ./scripts/cmk-manage.sh npm-port 81 # zurück auf die Vorgabe +``` + +Bei `81` wird der verwaltete Block wieder entfernt; ist die Datei danach leer, +verschwindet sie ganz. Es gilt dann wieder ausschließlich die Konfiguration aus +dem Image. + +Das Kommando lehnt Ports ab, die im Stack schon vergeben sind (80, 443, 5000, +8000, 6557), prüft den Zahlenbereich und warnt, wenn auf dem Wunschport bereits +ein anderer Dienst lauscht. + +> Sobald eine NPM-Version mit `NPM_ADMIN_PORT` erscheint, wird dieser Umweg +> überflüssig – dann genügt die Umgebungsvariable. Bis dahin ist der +> Erweiterungspunkt der Weg, der ohne Änderung am Image auskommt. + +--- + +## 13. Firewall **firewalld (RHEL/Rocky/Alma):** @@ -468,6 +919,9 @@ sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --permanent --add-port=8000/tcp # Agent-Receiver sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=10.0.0.0/24 port port=81 protocol=tcp accept' sudo firewall-cmd --reload + +# Bei abweichendem Admin-Port (z.B. 10443) stattdessen dessen Nummer freigeben - +# das passende Kommando gibt "cmk-manage.sh npm-port " direkt aus. ``` **ufw (Debian/Ubuntu):** @@ -485,7 +939,7 @@ Proxy. Port **81** nur aus dem Administrationsnetz freigeben. --- -## 11. Verwaltung: `cmk-manage.sh` +## 14. Verwaltung: `cmk-manage.sh` Das Skript ist gleichzeitig Kommandozeilenwerkzeug **und** ncurses-Oberfläche. @@ -508,8 +962,10 @@ sudo ./scripts/cmk-manage.sh gui │ import Site von Direktinstallation importieren │ │ manage Backups verwalten (Liste/Details/Löschen) │ │ sites Sites im Container verwalten │ + │ image Checkmk-Image beschaffen/auswählen │ + │ browser Terminal-Browser (Proxy Manager lokal) │ │ cert Selbstsigniertes Zertifikat erzeugen │ - │ env Konfiguration (.env) ansehen/bearbeiten │ + │ config Einstellungen (.env) - menügeführt │ │ shell Root-Shell im Checkmk-Container │ │ quit Beenden │ │ < OK > │ @@ -539,6 +995,10 @@ Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut. | `list` / `verify` / `prune --keep N` | Backups verwalten | | `restore …` | Backup zurückspielen | | `import …` | Migrations-Bundle einspielen | +| `image status\|list\|pull\|download\|load\|use` | Checkmk-Image beschaffen und auswaehlen | +| `browser [--engine …]` | Terminal-Browser im Container – Proxy Manager lokal bedienen | +| `config list\|get\|set\|edit` | Einstellungen der `.env` anzeigen und ändern | +| `npm-port [PORT]` | Port der Proxy-Manager-Oberfläche setzen/anzeigen | | `cert …` | selbstsigniertes Zertifikat erzeugen | | `shell` | Root-Shell im Checkmk-Container | | `omd …` | beliebiges `omd`-Kommando im Container | @@ -546,9 +1006,66 @@ Eine Dateiauswahl mit Verzeichnisnavigation ist eingebaut. Globale Optionen: `--env-file DATEI`, `-y/--yes` (keine Rückfragen, z. B. für Cronjobs), `-v/--verbose`. +### 14.3 Einstellungen ändern – ohne Editor + +Sämtliche Werte der `.env` lassen sich über das Menü pflegen. In der +Oberfläche: **Einstellungen (.env) – menügeführt**. Die Werte sind nach +Bereichen gruppiert: + +``` + ┌──────────────────── Einstellungen ─────────────────────┐ + │ Alle Werte der Datei .env - direkt hier änderbar. │ + │ Datei: /opt/checkmk-stack/.env │ + │ │ + │ runtime Runtime und Zeitzone │ + │ image Checkmk-Image und Zugangsdaten │ + │ checkmk Checkmk-Site und Container │ + │ npm NGINX Proxy Manager │ + │ browser Terminal-Browser │ + │ paths Verzeichnisse │ + │ cert Selbstsignierte Zertifikate │ + │ show Alle Werte auflisten │ + │ editor Datei .env im Editor öffnen │ + │ back zurück │ + └────────────────────────────────────────────────────────┘ +``` + +Jeder Eintrag zeigt seinen aktuellen Wert und öffnet beim Bestätigen die +passende Eingabe: Freitext, Zahl, Auswahlliste oder Kennwortfeld (Kennwörter +erscheinen in der Übersicht als `********` und bleiben unverändert, wenn man +das Feld leer lässt). Der Editor bleibt als Menüpunkt erhalten. + +Dieselben Werte über die Kommandozeile: + +```bash +./scripts/cmk-manage.sh config list # alles mit aktuellen Werten +./scripts/cmk-manage.sh config list --category npm # nur ein Bereich +./scripts/cmk-manage.sh config get CMK_SITE_ID +./scripts/cmk-manage.sh config set CMK_SITE_ID prod +./scripts/cmk-manage.sh config set NPM_ADMIN_PORT 10443 +``` + +**Geprüft wird beim Setzen**, nicht erst beim nächsten Start: + +| Schlüssel | Prüfung | +|---|---| +| `NPM_ADMIN_PORT` | Zahl 1–65535, nicht 80/443/5000/8000/6557, Warnung wenn belegt | +| `CMK_SITE_ID` | nur Buchstaben, Ziffern, `_`; höchstens 16 Zeichen | +| `CMK_IMAGE`, `NPM_IMAGE`, … | muss vollqualifiziert sein (Podman-Fallstrick) | +| `CMK_RUNTIME` | muss auf diesem System installiert sein | +| `CERT_DAYS` u. a. | Zahlenfelder | +| URL-Felder | müssen mit `http://` oder `https://` beginnen | + +Werte mit Leerzeichen werden automatisch in Anführungszeichen gesetzt, damit +die `.env` weiterhin von compose, systemd **und** der Shell gelesen werden +kann. Ändert man `NPM_ADMIN_PORT`, zieht das Skript die nginx-Zusatzdatei +automatisch mit (siehe [Kapitel 12](#12-adminoberfläche-auf-einen-anderen-port-legen)). +Bei Werten, die erst nach dem Neuerstellen der Container greifen, weist das +Menü ausdrücklich darauf hin. + --- -## 12. Backup +## 15. Backup Backups werden mit `omd backup` erstellt und als **Bundle** verpackt: @@ -599,7 +1116,7 @@ sudo crontab -e --- -## 13. Restore +## 16. Restore ```bash # Einfachster Fall: Site existiert nicht mehr @@ -630,7 +1147,7 @@ der Site-Name wird dann aus dem Archiv gelesen. --- -## 14. Migration einer Direktinstallation (`migrate_creator.sh`) +## 17. Migration einer Direktinstallation (`migrate_creator.sh`) Ziel: eine bestehende Checkmk-Installation auf Blech/VM in den Container übernehmen – **ohne die Agents anzufassen**. @@ -714,21 +1231,32 @@ Checkmk-Version im Zielsystem installiert ist.** Im Container kommt die Version aus dem Image – also muss der Image-Tag passen: ```bash -grep CMK_VERSION <(tar -xzOf backups/cmkmigrate_prod_*.tar.gz cmkbundle/MANIFEST) -# CMK_VERSION=2.3.0p23.cre -> Image-Tag: 2.3.0p23 +tar -xzOf backups/cmkmigrate_prod_*.tar.gz cmkbundle/MANIFEST | grep CMK_VERSION +# CMK_VERSION=2.3.0p23.cre -> Version 2.3.0p23, Endung .cre = Raw Edition -sudo $EDITOR .env -# CMK_IMAGE_TAG=2.3.0p23 +# passendes Image holen und als CMK_IMAGE eintragen lassen +sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0p23 sudo ./scripts/cmk-manage.sh up ``` +Bei einer Enterprise-Quelle (`.cee`) entsprechend: + +```bash +sudo ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \ + --user --password +# oder, wenn die Registry nicht erreichbar ist: +sudo ./scripts/cmk-manage.sh image download --edition enterprise --version 2.3.0p23 \ + --user --password +``` + Das Import-Skript prüft das selbst und bricht mit einer entsprechenden Meldung ab, wenn die Version fehlt. -> **Edition beachten:** `.cre` = Raw Edition → `checkmk/check-mk-raw`. -> Bei `.cee` / `.cce` / `.cme` wird das entsprechende Enterprise-/Cloud-Image -> benötigt (`CMK_IMAGE_REPO=checkmk/check-mk-enterprise`, Zugang über die -> Checkmk-Subskription). +> **Edition beachten:** die Endung der Version verrät sie – +> `.cre` = Raw, `.cee` = Enterprise, `.cce` = Cloud, `.cme` = Managed. +> Das Import-Skript liest sie aus dem Manifest und nennt im Fehlerfall direkt +> das passende `image pull`-Kommando. Enterprise-Images gibt es **nicht** auf +> Docker Hub – siehe [Kapitel 8](#8-checkmk-image-beschaffen-raw-enterprise--co). ### 14.5 Schritt 4 – Bundle importieren @@ -792,7 +1320,7 @@ Danach in der Oberfläche prüfen: - [ ] `migrate_creator.sh` auf den Quellserver kopiert - [ ] Bundle erzeugt (möglichst mit `--stop`) - [ ] Bundle auf das Zielsystem kopiert (`backups/`) -- [ ] `CMK_IMAGE_TAG` auf die Quellversion gesetzt, Stack neu erstellt +- [ ] passendes Image geholt (`image pull`/`image download`), `CMK_IMAGE` gesetzt, Stack neu erstellt - [ ] `import --set-default-site` ausgeführt, Site läuft - [ ] Alte Site gestoppt / alter Server abgeschaltet - [ ] IP bzw. DNS auf das Zielsystem umgestellt @@ -803,7 +1331,7 @@ Danach in der Oberfläche prüfen: --- -## 15. Mehrere Sites in einem Container +## 18. Mehrere Sites in einem Container Der Checkmk-Entrypoint legt beim Start nur die Site aus `CMK_SITE_ID` an und startet auch nur diese. Weitere Sites (z. B. mehrere importierte) existieren im @@ -827,7 +1355,7 @@ vorhandenen Sites. --- -## 16. Checkmk aktualisieren +## 19. Checkmk aktualisieren Da `/omd/sites` ein Bind-Mount ist, überleben die Daten den Austausch des Images. Die Checkmk-Software selbst steckt im Image unter `/omd/versions`. @@ -836,11 +1364,10 @@ Images. Die Checkmk-Software selbst steckt im Image unter `/omd/versions`. # 1) IMMER zuerst sichern sudo ./scripts/cmk-manage.sh backup --all --label vor-update -# 2) neuen Tag eintragen -sudo $EDITOR .env # z.B. CMK_IMAGE_TAG=2.3.0p28 +# 2) neues Image holen (traegt CMK_IMAGE automatisch in die .env ein) +sudo ./scripts/cmk-manage.sh image pull --edition raw --version 2.3.0p28 -# 3) Image holen und Container neu erstellen -sudo ./scripts/cmk-manage.sh pull +# 3) Container neu erstellen sudo ./scripts/cmk-manage.sh up # 4) Site aktualisieren (interaktiv, Konflikte bestätigen) @@ -854,19 +1381,29 @@ Checkmk-Werksnotizen (Werks/Release Notes) lesen. --- -## 17. Fehlersuche +## 20. Fehlersuche | Symptom | Ursache / Lösung | |---|---| | `Port 80/443 already in use` | Auf dem Host läuft bereits ein Webserver: `ss -tlnp \| grep ':80'` → `systemctl disable --now apache2 nginx httpd` | | Nach Reboot laufen die Container nicht (Podman) | systemd-Unit fehlt: `./install.sh --with-systemd` bzw. `--quadlet`, danach `systemctl is-enabled checkmk-stack` | -| `omd restore`: *version is not installed* | `CMK_IMAGE_TAG` in der `.env` auf die Version aus dem `MANIFEST` setzen und `up` ausführen | -| Import bricht mit Editions-Warnung ab | Enterprise-Backup benötigt das Enterprise-Image (`CMK_IMAGE_REPO`) | +| `omd restore`: *version is not installed* | passendes Image holen: `cmk-manage.sh image pull --edition --version `, dann `up` | +| Import bricht mit Editions-Warnung ab | Enterprise-Backup benötigt ein Enterprise-Image, siehe [Kapitel 8](#8-checkmk-image-beschaffen-raw-enterprise--co) | +| `image not known` / Podman sucht bei `registry.access.redhat.com` | kurzer Image-Name. `CMK_IMAGE` vollqualifiziert setzen: `cmk-manage.sh image use docker.io/…` bzw. `registry.checkmk.com/enterprise/…` | +| `checkmk/check-mk-enterprise` nicht auf Docker Hub gefunden | richtig so – Enterprise liegt nur auf `registry.checkmk.com` oder als Tarball vor; ab 2.5 heißt die Edition `pro` und liegt frei auf Docker Hub | +| Tarball mit `podman import` eingespielt, Image „unbekannt“ | `import` erzeugt ein Image ohne Metadaten. Fehl-Image mit `podman rmi ` entfernen und `cmk-manage.sh image load --file …` verwenden (nutzt `load`) | +| Download des Image-Tarballs schlägt fehl (401/404) | Zugangsdaten des Kundenportals prüfen, exakte Version angeben (kein `-latest`), notfalls `image download --url ''` | | Proxy zeigt `502 Bad Gateway` | Checkmk-Container läuft nicht oder Weiterleitung nicht auf `127.0.0.1:5000` gesetzt: `./scripts/cmk-manage.sh status`, `curl -I http://127.0.0.1:5000/` | | Let's Encrypt schlägt fehl | Port 80 aus dem Internet nicht erreichbar oder DNS falsch; Alternative: DNS-Challenge oder selbstsigniertes Zertifikat | | Agents melden sich nach der Migration nicht | Site-Name geändert (`--as-site`), IP nicht übernommen oder Port 8000 blockiert; auf dem Agent prüfen: `cmk-agent-ctl status` | | Permission denied auf `data/` unter RHEL | SELinux: `restorecon -Rv /opt/checkmk-stack/data`, `:Z` an den Mounts prüfen | | `podman-compose` nicht gefunden | EPEL aktivieren oder auf Quadlet umstellen (`./install.sh --quadlet`) | +| Adminoberfläche aus dem LAN nicht erreichbar | Port 81 gesperrt. Auf einen freien Port legen: `cmk-manage.sh npm-port 10443` und in der Firewall freigeben | +| Nach `npm-port` antwortet der neue Port nicht | Proxy Manager wurde nicht neu gestartet: `cmk-manage.sh restart`; Datei prüfen: `data/npm/data/nginx/custom/http.conf` | +| `cmk-manage.sh` bricht mit „CMK_RUNTIME … ist nicht installiert" ab | wird nur noch gewarnt und selbst gesucht; sauber setzen mit `config set CMK_RUNTIME auto` | +| Proxy-Manager-Oberfläche im Browser leer / nur Textfragmente | Textbrowser ohne JavaScript verwendet. `cmk-manage.sh browser --engine browsh` (bzw. `carbonyl`) nehmen | +| Selbstsigniertes Zertifikat lässt sich im Terminal-Browser nicht hochladen | Datei-Dialoge gibt es dort nicht – Upload über die API, siehe [Kapitel 11.3](#11-proxy-manager-lokal-einrichten-terminal-browser) | +| `browser` meldet „braucht ein echtes Terminal" | Aufruf aus Pipe/Skript. Direkt auf der Konsole oder per SSH aufrufen; nur der Bau geht headless mit `--build-only` | | TUI startet nicht | `dialog` installieren: `apt-get install -y dialog` bzw. `dnf install -y dialog` | | Site startet nicht, `tmp`-Fehler | `./scripts/cmk-manage.sh omd config set TMPFS off`, danach Site starten | @@ -881,7 +1418,7 @@ docker exec -it checkmk omd su cmk # bzw. podman exec … --- -## 18. Sicherheitshinweise +## 21. Sicherheitshinweise * `CMK_PASSWORD` sofort nach der Installation in der Oberfläche ändern und aus der `.env` entfernen (wird nur bei der Neuanlage ausgewertet); @@ -900,7 +1437,7 @@ docker exec -it checkmk omd su cmk # bzw. podman exec … --- -## 19. Deinstallation +## 22. Deinstallation ```bash sudo ./scripts/cmk-manage.sh down @@ -913,10 +1450,13 @@ sudo rm -f /etc/containers/systemd/checkmk.container \ /etc/containers/systemd/nginx-proxy-manager.container sudo systemctl daemon-reload -# Images entfernen -docker image rm checkmk/check-mk-raw:2.3.0-latest jc21/nginx-proxy-manager:2 +# Images entfernen (Namen aus "cmk-manage.sh image list") +docker image rm docker.io/checkmk/check-mk-raw:2.3.0-latest docker.io/jc21/nginx-proxy-manager:2 # podman image rm … +# ggf. gespeicherte Registry-Anmeldung entfernen +podman logout registry.checkmk.com # bzw. docker logout + # Daten (ACHTUNG: löscht die komplette Überwachung!) sudo rm -rf /opt/checkmk-stack/data ``` diff --git a/containers/browser/Containerfile b/containers/browser/Containerfile new file mode 100644 index 0000000..44e6ffb --- /dev/null +++ b/containers/browser/Containerfile @@ -0,0 +1,37 @@ +# ===================================================================== +# Kleines Werkzeug-Image fuer die lokale Bedienung/Diagnose des Stacks. +# +# Enthaelt Textbrowser und Netzwerkwerkzeuge. ACHTUNG: Textbrowser +# koennen KEIN JavaScript - die Admin-Oberflaeche des NGINX Proxy +# Managers laesst sich damit NICHT bedienen. Dafuer sind die Engines +# "browsh" oder "carbonyl" vorgesehen (siehe cmk-manage.sh browser). +# +# Bauen: ./scripts/cmk-manage.sh browser --build +# Nutzen: ./scripts/cmk-manage.sh browser --engine links +# ./scripts/cmk-manage.sh browser --engine shell +# ===================================================================== +FROM docker.io/library/debian:stable-slim + +LABEL org.opencontainers.image.title="checkmk-stack browser tools" \ + org.opencontainers.image.description="Textbrowser und Netzwerkwerkzeuge fuer die lokale Bedienung" + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + links2 \ + w3m \ + lynx \ + curl \ + ca-certificates \ + openssl \ + jq \ + less \ + iproute2 \ + iputils-ping \ + procps \ + && rm -rf /var/lib/apt/lists/* + +ENV TERM=xterm-256color \ + LANG=C.UTF-8 + +WORKDIR /root +CMD ["/bin/bash"] diff --git a/docker-compose.yml b/docker-compose.yml index 0422741..29d9d94 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,11 @@ services: # Port 6557 = Livestatus (nur wenn CMK_LIVESTATUS_TCP=on) # ------------------------------------------------------------------- checkmk: - image: ${CMK_IMAGE_REPO:-checkmk/check-mk-raw}:${CMK_IMAGE_TAG:-2.3.0-latest} + # Vollqualifizierter Name! Wird aus der .env genommen und ggf. von + # "cmk-manage.sh image ..." dort eingetragen. Kurze Namen wuerde Podman + # ueber unqualified-search-registries aufloesen (auf RHEL zuerst + # registry.access.redhat.com) und das Image nicht finden. + image: ${CMK_IMAGE:-docker.io/checkmk/check-mk-raw:2.3.0-latest} container_name: ${CMK_CONTAINER_NAME:-checkmk} hostname: ${CMK_HOSTNAME:-checkmk} network_mode: host @@ -51,7 +55,7 @@ services: # Port 81 = Admin-Oberflaeche (unbedingt per Firewall einschraenken!) # ------------------------------------------------------------------- nginx-proxy-manager: - image: ${NPM_IMAGE:-jc21/nginx-proxy-manager:2} + image: ${NPM_IMAGE:-docker.io/jc21/nginx-proxy-manager:2} container_name: ${NPM_CONTAINER_NAME:-nginx-proxy-manager} network_mode: host restart: unless-stopped diff --git a/images/.gitkeep b/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/install.sh b/install.sh index 267ac54..7199c46 100755 --- a/install.sh +++ b/install.sh @@ -159,8 +159,10 @@ log "Bereite Projektverzeichnis vor ..." mkdir -p "$PROJECT_DIR/data/checkmk/sites" \ "$PROJECT_DIR/data/npm/data" \ "$PROJECT_DIR/data/npm/letsencrypt" \ + "$PROJECT_DIR/data/npm/data/nginx/custom" \ "$PROJECT_DIR/data/npm/custom-certs" \ - "$PROJECT_DIR/backups" + "$PROJECT_DIR/backups" \ + "$PROJECT_DIR/images" chmod +x "$PROJECT_DIR"/scripts/*.sh "$PROJECT_DIR/install.sh" 2>/dev/null || true if [ ! -f "$PROJECT_DIR/.env" ]; then @@ -238,8 +240,8 @@ install_quadlet_units() { local f for f in "$PROJECT_DIR"/systemd/quadlet/*.container; do sed -e "s|__PROJECT_DIR__|$PROJECT_DIR|g" \ - -e "s|__CMK_IMAGE__|${CMK_IMAGE_REPO:-checkmk/check-mk-raw}:${CMK_IMAGE_TAG:-2.3.0-latest}|g" \ - -e "s|__NPM_IMAGE__|${NPM_IMAGE:-jc21/nginx-proxy-manager:2}|g" \ + -e "s|__CMK_IMAGE__|${CMK_IMAGE:-docker.io/checkmk/check-mk-raw:2.3.0-latest}|g" \ + -e "s|__NPM_IMAGE__|${NPM_IMAGE:-docker.io/jc21/nginx-proxy-manager:2}|g" \ -e "s|__CMK_SITE_ID__|${CMK_SITE_ID:-cmk}|g" \ -e "s|__CMK_CONTAINER_NAME__|${CMK_CONTAINER_NAME:-checkmk}|g" \ -e "s|__NPM_CONTAINER_NAME__|${NPM_CONTAINER_NAME:-nginx-proxy-manager}|g" \ @@ -300,7 +302,12 @@ Naechste Schritte: $PROJECT_DIR/scripts/cmk-manage.sh up 3) NGINX Proxy Manager oeffnen: http://$(primary_ip):81 Erstlogin: admin@example.com / changeme - 4) Verwaltung / Backup / Migration - ncurses-Oberflaeche: + 4) Ist Port 81 im Netz gesperrt, laesst sich die Adminoberflaeche auf einen + anderen Port legen: + $PROJECT_DIR/scripts/cmk-manage.sh npm-port 10443 + Oder ganz ohne Netzzugriff per Terminal-Browser auf dieser Maschine: + $PROJECT_DIR/scripts/cmk-manage.sh browser + 5) Verwaltung / Backup / Migration - ncurses-Oberflaeche: $PROJECT_DIR/scripts/cmk-manage.sh gui Alles Weitere steht in der README.md. diff --git a/scripts/cmk-manage.sh b/scripts/cmk-manage.sh index e6b524e..89f62c3 100755 --- a/scripts/cmk-manage.sh +++ b/scripts/cmk-manage.sh @@ -89,6 +89,44 @@ KOMMANDOS - Backup / Restore / Migration prune --keep N nur die N neuesten Backups behalten +KOMMANDOS - Checkmk-Image beschaffen + image status konfiguriertes und lokal vorhandene Images anzeigen + image list lokal vorhandene Checkmk-Images + image pull [Opt.] Image aus einer Registry holen + --edition E raw|community|free|cloud|managed|pro|ultimate| + ultimatemt|enterprise (Vorgabe: CMK_EDITION) + --version V z.B. 2.3.0p23 (Vorgabe: CMK_VERSION) + --registry R abweichende Registry + --user U --password P Zugangsdaten (Enterprise: Kundenportal) + --image REF fertige Referenz statt Edition/Version + --no-set .env nicht veraendern + image download [Opt.] Image-Tarball vom Downloadportal holen und einspielen + --edition/--version/--user/--password wie oben + --url URL vollstaendige URL fest vorgeben + --dir VERZ Ablage (Vorgabe: $IMAGE_DIR) + --keep Tarball nach dem Einspielen behalten + image load --file F bereits heruntergeladenen Tarball einspielen + image use REF vorhandenes Image als CMK_IMAGE in die .env eintragen + +KOMMANDOS - Konfiguration + config list [--category KAT] alle Einstellungen mit aktuellen Werten + config get KEY einzelnen Wert ausgeben + config set KEY WERT Wert setzen (mit Pruefung) + config edit .env im Editor oeffnen + npm-port [PORT] Port der Proxy-Manager-Oberflaeche + (ohne PORT: aktuellen Stand anzeigen) + +KOMMANDOS - Lokale Bedienung ohne externen Zugriff + browser [Optionen] Terminal-Browser im Container starten, um den + NGINX Proxy Manager direkt auf der Maschine + einzurichten (Host-Netzwerk, erreicht 127.0.0.1:81) + -e, --engine E browsh (Vorgabe) | carbonyl | links | w3m | lynx | shell + browsh/carbonyl koennen JavaScript - die Textbrowser + NICHT, damit laesst sich der Proxy Manager nicht bedienen + -u, --url URL Startseite (Vorgabe: http://127.0.0.1:81) + --build Werkzeug-Image neu bauen + --pull Engine-Image neu laden + KOMMANDOS - Zertifikat cert [Optionen] selbstsigniertes Zertifikat fuer den Proxy erzeugen --domain FQDN Common Name / SAN @@ -99,6 +137,13 @@ BEISPIELE ./scripts/cmk-manage.sh up ./scripts/cmk-manage.sh backup --all --no-logs ./scripts/cmk-manage.sh import --file backups/cmkmigrate_prod_2.3.0p23_*.tar.gz --set-default-site + ./scripts/cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \ + --user --password + ./scripts/cmk-manage.sh image download --edition enterprise --version 2.3.0p23 + ./scripts/cmk-manage.sh image load --file images/check-mk-enterprise-2.3.0p23.docker.tar.gz + ./scripts/cmk-manage.sh npm-port 10443 # Adminoberflaeche auf Port 10443 + ./scripts/cmk-manage.sh config set CMK_SITE_ID prod + ./scripts/cmk-manage.sh browser # Proxy Manager lokal bedienen ./scripts/cmk-manage.sh gui EOF } @@ -218,6 +263,406 @@ bundle_extract_payload() { fi } +# ===================================================================== +# Checkmk-Image beschaffen +# +# Hintergrund: +# * Die Enterprise-Edition liegt NICHT auf Docker Hub. Dort gibt es nur +# raw / community / cloud / managed / pro / ultimate / ultimatemt. +# Enterprise kommt aus registry.checkmk.com (Login) oder als Tarball +# vom Checkmk-Downloadportal (HTTP-Basic-Auth). +# * Ein heruntergeladener Image-Tarball wird mit "load" eingespielt, +# NICHT mit "import". "import" erwartet ein Dateisystem-Archiv und +# erzeugt ein Image ohne Metadaten (ohne Entrypoint, ohne Tag) - +# danach "kennt" die Runtime das Image scheinbar nicht. +# * Nach dem Laden traegt dieses Skript den TATSAECHLICHEN, voll- +# qualifizierten Namen in CMK_IMAGE der .env ein. +# ===================================================================== + +edition_repo() { # Edition -> vollqualifiziertes Repository + case "$1" in + raw) echo "docker.io/checkmk/check-mk-raw" ;; + community) echo "docker.io/checkmk/check-mk-community" ;; + free) echo "docker.io/checkmk/check-mk-free" ;; + cloud) echo "docker.io/checkmk/check-mk-cloud" ;; + managed) echo "docker.io/checkmk/check-mk-managed" ;; + pro) echo "docker.io/checkmk/check-mk-pro" ;; + ultimate) echo "docker.io/checkmk/check-mk-ultimate" ;; + ultimatemt) echo "docker.io/checkmk/check-mk-ultimatemt" ;; + enterprise) echo "${CMK_REGISTRY:-registry.checkmk.com}/enterprise/check-mk-enterprise" ;; + *) return 1 ;; + esac +} + +edition_known() { edition_repo "$1" >/dev/null 2>&1; } + +# Braucht diese Edition eine Anmeldung an der Registry? +edition_needs_login() { [ "$1" = enterprise ]; } + +edition_pkgname() { echo "check-mk-$1"; } + +# Lokal vorhandene Checkmk-Images +image_local_list() { + $RUNTIME images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null \ + | grep -Ei 'check-?mk' | grep -v '' | sort -u || true +} + +image_exists_local() { + $RUNTIME image inspect "$1" >/dev/null 2>&1 +} + +image_is_short_name() { + # Kurzer Name = ohne Registry-Anteil. Podman muesste ihn dann ueber + # unqualified-search-registries erraten. + case "$1" in + */*) : ;; + *) return 0 ;; # gar kein "/" -> immer kurz + esac + case "${1%%/*}" in + *.*|*:*|localhost) return 1 ;; # Registry mit Punkt, Port oder localhost + *) return 0 ;; + esac +} + +image_set_env() { + local ref="$1" + env_set CMK_IMAGE "$ref" + ok "CMK_IMAGE=$ref in der .env eingetragen." + if image_is_short_name "$ref"; then + warn "'$ref' ist ein KURZER Name ohne Registry. Podman wuerde ihn ueber + unqualified-search-registries aufloesen (auf RHEL zuerst + registry.access.redhat.com). Besser vollqualifiziert angeben." + fi + log "Danach den Stack neu erstellen: $SELF up" +} + +# Vor/Nachher-Vergleich, um den Namen eines geladenen Images sicher zu finden +image_snapshot() { $RUNTIME images --format '{{.Repository}}:{{.Tag}}' 2>/dev/null | sort -u || true; } + +# Tarball einspielen -> gibt den geladenen Image-Namen auf stdout aus +image_load_file() { + local file="$1" + [ -f "$file" ] || die "Datei nicht gefunden: $file" + + # Ist das ueberhaupt ein Container-Image-Archiv (docker-archive/OCI)? + if ! tar -tzf "$file" 2>/dev/null | grep -qE '^(manifest\.json|oci-layout|index\.json)$'; then + if tar -tf "$file" 2>/dev/null | grep -qE '^(manifest\.json|oci-layout|index\.json)$'; then + : + else + err "'$file' enthaelt kein manifest.json / oci-layout." + cat >&2 <<'EOF' + Das ist damit KEIN Container-Image-Archiv, sondern vermutlich ein + normales tar-Archiv. Nur "docker save"/"podman save"-Archive bzw. die + Image-Tarballs von Checkmk lassen sich mit "load" einspielen. + + Haeufige Verwechslung: + podman import -> erwartet ein Dateisystem-Archiv (rootfs), + erzeugt ein Image OHNE Entrypoint und ohne Tag + podman load -> spielt ein echtes Image inkl. Metadaten ein <-- richtig +EOF + return 1 + fi + fi + + local before after loaded + before="$(image_snapshot)" + log "Spiele Image ein: $RUNTIME load -i $file (das dauert einen Moment) ..." >&2 + local out + out="$($RUNTIME load -i "$file" 2>&1)" || { printf '%s\n' "$out" >&2; return 1; } + printf '%s\n' "$out" >&2 + + # 1. Versuch: Ausgabe auswerten + # docker: "Loaded image: repo:tag" podman: "Loaded image(s): repo:tag" + loaded="$(printf '%s\n' "$out" | sed -nE 's/^Loaded image(\(s\))?:[[:space:]]*//p' | head -n1 | tr -d '\r')" + + # 2. Versuch: Differenz der Image-Liste (bevorzugt ein Checkmk-Image) + if [ -z "$loaded" ] || [ "${loaded#sha256:}" != "$loaded" ]; then + after="$(image_snapshot)" + local diff_new + diff_new="$(comm -13 <(printf '%s\n' "$before") <(printf '%s\n' "$after") | grep -v '')" + local cand + cand="$(printf '%s\n' "$diff_new" | grep -Ei 'check-?mk' | head -n1)" + [ -n "$cand" ] || cand="$(printf '%s\n' "$diff_new" | sed '/^$/d' | head -n1)" + [ -n "$cand" ] && loaded="$cand" + fi + + if [ -z "$loaded" ]; then + err "Der Name des geladenen Images konnte nicht ermittelt werden." + err "Bitte manuell nachsehen: $RUNTIME images" + return 1 + fi + if [ "${loaded#sha256:}" != "$loaded" ]; then + err "Das Archiv enthaelt keinen Image-Namen (nur die ID $loaded)." + err "Manuell benennen: $RUNTIME tag $loaded localhost/checkmk/check-mk-enterprise:" + return 1 + fi + printf '%s\n' "$loaded" +} + +# Datei mit HTTP-Basic-Auth holen (Zugangsdaten nicht in der Prozessliste) +image_fetch_url() { + local url="$1" out="$2" user="$3" pass="$4" + local host; host="$(printf '%s' "$url" | sed -E 's|^[a-z]+://([^/]+).*|\1|')" + + if command -v curl >/dev/null 2>&1; then + local netrc="" + local -a auth=() + if [ -n "$user" ]; then + netrc="$(mktemp)"; chmod 600 "$netrc" + printf 'machine %s login %s password %s\n' "$host" "$user" "$pass" >"$netrc" + auth=(--netrc-file "$netrc") + fi + log "Lade $url" + if curl -fL --progress-bar ${auth[@]+"${auth[@]}"} -o "$out" "$url"; then + [ -n "$netrc" ] && rm -f "$netrc" + return 0 + fi + [ -n "$netrc" ] && rm -f "$netrc" + return 1 + elif command -v wget >/dev/null 2>&1; then + warn "curl fehlt - verwende wget (die Zugangsdaten sind dabei kurzzeitig + in der Prozessliste sichtbar)." + local -a wa=() + [ -n "$user" ] && wa=(--user="$user" --password="$pass") + wget ${wa[@]+"${wa[@]}"} -O "$out" "$url" + return $? + else + die "Weder curl noch wget vorhanden." + fi +} + +# --------------------------------------------------------------------- +# image pull - aus einer Registry holen +# --------------------------------------------------------------------- +image_cmd_pull() { + local edition="${CMK_EDITION:-raw}" version="${CMK_VERSION:-}" registry="${CMK_REGISTRY:-}" + local user="${CMK_REGISTRY_USER:-}" pass="${CMK_REGISTRY_PASSWORD:-}" ref="" setenv=1 + while [ $# -gt 0 ]; do + case "$1" in + --edition) edition="$2"; shift 2 ;; + --version) version="$2"; shift 2 ;; + --registry) registry="$2"; shift 2 ;; + --user) user="$2"; shift 2 ;; + --password) pass="$2"; shift 2 ;; + --image) ref="$2"; shift 2 ;; + --no-set) setenv=""; shift ;; + *) die "Unbekannte Option fuer 'image pull': $1" ;; + esac + done + + if [ -z "$ref" ]; then + edition_known "$edition" || die "Unbekannte Edition '$edition'. + Moeglich: raw community free cloud managed pro ultimate ultimatemt enterprise" + [ -n "$version" ] || die "Keine Version angegeben (--version oder CMK_VERSION)." + CMK_REGISTRY="${registry:-${CMK_REGISTRY:-registry.checkmk.com}}" + ref="$(edition_repo "$edition"):$version" + fi + + local reg="${ref%%/*}" + if edition_needs_login "$edition" || [ -n "$user" ]; then + if [ -z "$user" ]; then + err "Fuer '$edition' ist eine Anmeldung an $reg noetig." + cat >&2 < --password +EOF + return 1 + fi + log "Melde an $reg an ..." + printf '%s' "$pass" | $RUNTIME login --username "$user" --password-stdin "$reg" \ + || die "Anmeldung an $reg fehlgeschlagen." + ok "Anmeldung erfolgreich." + fi + + log "Hole Image: $ref" + if ! $RUNTIME pull "$ref"; then + err "Das Image '$ref' konnte nicht geholt werden." + if [ "$edition" = enterprise ]; then + cat >&2 <<'EOF' + + Hinweis: die Enterprise-Edition gibt es NICHT auf Docker Hub. + Zwei Wege stehen zur Verfuegung: + a) private Registry: + cmk-manage.sh image pull --edition enterprise --version 2.3.0p23 \ + --user --password + b) Tarball vom Downloadportal: + cmk-manage.sh image download --edition enterprise --version 2.3.0p23 \ + --user --password + Ab Checkmk 2.5 heisst diese Edition "pro" und liegt frei auf Docker Hub: + cmk-manage.sh image pull --edition pro --version 2.5.0p11 +EOF + fi + return 1 + fi + ok "Image vorhanden: $ref" + [ -n "$setenv" ] && image_set_env "$ref" + return 0 +} + +# --------------------------------------------------------------------- +# image download - Tarball vom Downloadportal holen und einspielen +# --------------------------------------------------------------------- +image_cmd_download() { + local edition="${CMK_EDITION:-raw}" version="${CMK_VERSION:-}" + local user="${CMK_DOWNLOAD_USER:-}" pass="${CMK_DOWNLOAD_PASSWORD:-}" + local url="${CMK_DOWNLOAD_URL:-}" dir="" keep="" setenv=1 + while [ $# -gt 0 ]; do + case "$1" in + --edition) edition="$2"; shift 2 ;; + --version) version="$2"; shift 2 ;; + --url) url="$2"; shift 2 ;; + --user) user="$2"; shift 2 ;; + --password) pass="$2"; shift 2 ;; + --dir) dir="$2"; shift 2 ;; + --keep) keep=1; shift ;; + --no-set) setenv=""; shift ;; + *) die "Unbekannte Option fuer 'image download': $1" ;; + esac + done + + dir="${dir:-${IMAGE_DIR:-$PROJECT_DIR/images}}" + case "$dir" in /*) : ;; *) dir="$PROJECT_DIR/${dir#./}" ;; esac + mkdir -p "$dir" + + local -a urls=() + if [ -n "$url" ]; then + urls=("$url") + else + [ -n "$version" ] || die "Keine Version angegeben (--version oder CMK_VERSION)." + case "$version" in + *-latest|latest) die "Fuer den Tarball-Download wird eine exakte Version benoetigt, + z.B. 2.3.0p23 - '$version' funktioniert dort nicht." ;; + esac + edition_known "$edition" || die "Unbekannte Edition '$edition'." + local base="${CMK_DOWNLOAD_BASEURL:-https://download.checkmk.com/checkmk}" + local pkg; pkg="$(edition_pkgname "$edition")" + # Checkmk hat den Dateinamen ueber die Jahre geaendert - beide probieren + urls=("$base/$version/$pkg-$version.docker.tar.gz" + "$base/$version/$pkg-docker-$version.tar.gz") + fi + + local target="" u + for u in "${urls[@]}"; do + target="$dir/$(basename "$u")" + if image_fetch_url "$u" "$target" "$user" "$pass"; then + ok "Heruntergeladen: $target ($(human_size "$(file_size "$target")"))" + break + fi + rm -f "$target"; target="" + warn "Nicht gefunden/abgelehnt: $u" + done + + if [ -z "$target" ]; then + err "Der Image-Tarball konnte nicht geladen werden." + cat >&2 </' \\ + --user --password + * oder die Datei manuell im Kundenportal herunterladen und einspielen: + $SELF image load --file /pfad/zur/datei.tar.gz +EOF + return 1 + fi + + local loaded + loaded="$(image_load_file "$target")" || return 1 + ok "Image eingespielt: $loaded" + [ -z "$keep" ] && { rm -f "$target"; log "Tarball entfernt (mit --keep behalten)."; } + [ -n "$setenv" ] && image_set_env "$loaded" + return 0 +} + +# --------------------------------------------------------------------- +# image load - bereits heruntergeladenen Tarball einspielen +# --------------------------------------------------------------------- +image_cmd_load() { + local file="" setenv=1 + while [ $# -gt 0 ]; do + case "$1" in + --file) file="$2"; shift 2 ;; + --no-set) setenv=""; shift ;; + *) [ -z "$file" ] && { file="$1"; shift; } || die "Unbekannte Option: $1" ;; + esac + done + [ -n "$file" ] || die "--file fehlt." + local loaded + loaded="$(image_load_file "$file")" || return 1 + ok "Image eingespielt: $loaded" + [ -n "$setenv" ] && image_set_env "$loaded" +} + +# --------------------------------------------------------------------- +# image use / list / status +# --------------------------------------------------------------------- +image_cmd_use() { + [ $# -ge 1 ] || die "Image-Referenz fehlt, z.B.: + $SELF image use localhost/checkmk/check-mk-enterprise:2.3.0p23" + local ref="$1" + image_exists_local "$ref" || warn "'$ref' ist lokal (noch) nicht vorhanden." + image_set_env "$ref" +} + +image_cmd_list() { + printf '%sLokal vorhandene Checkmk-Images%s\n' "$C_BLD" "$C_RST" + local l n=0 + while IFS= read -r l; do + [ -n "$l" ] || continue + if [ "$l" = "${CMK_IMAGE:-}" ]; then + printf ' %s %s<- laut .env in Verwendung%s\n' "$l" "$C_GRN" "$C_RST" + else + printf ' %s\n' "$l" + fi + n=$((n+1)) + done < <(image_local_list) + [ "$n" -eq 0 ] && echo " (keines)" + return 0 +} + +image_cmd_status() { + printf '\n%sKonfiguriertes Image (.env: CMK_IMAGE)%s\n' "$C_BLD" "$C_RST" + printf ' %s\n' "${CMK_IMAGE:-}" + if [ -n "${CMK_IMAGE:-}" ]; then + if image_exists_local "$CMK_IMAGE"; then + printf ' Status : %slokal vorhanden%s\n' "$C_GRN" "$C_RST" + else + printf ' Status : %snicht lokal vorhanden%s (wird beim Start geholt)\n' "$C_YEL" "$C_RST" + fi + if image_is_short_name "$CMK_IMAGE"; then + printf ' %sACHTUNG%s: kurzer Name ohne Registry - unter Podman fehleranfaellig.\n' "$C_RED" "$C_RST" + fi + fi + printf '\n%sVorgaben fuer den Downloader%s\n' "$C_BLD" "$C_RST" + printf ' Edition : %s -> %s\n' "${CMK_EDITION:-raw}" "$(edition_repo "${CMK_EDITION:-raw}" 2>/dev/null || echo '?')" + printf ' Version : %s\n' "${CMK_VERSION:-}" + printf ' Registry : %s (Benutzer: %s)\n' "${CMK_REGISTRY:-registry.checkmk.com}" "${CMK_REGISTRY_USER:-}" + printf ' Download : %s (Benutzer: %s)\n' "${CMK_DOWNLOAD_BASEURL:-https://download.checkmk.com/checkmk}" "${CMK_DOWNLOAD_USER:-}" + echo + image_cmd_list + echo +} + +cmd_image() { + local sub="${1:-status}"; [ $# -gt 0 ] && shift || true + case "$sub" in + status) image_cmd_status ;; + list|ls) image_cmd_list ;; + pull) image_cmd_pull "$@" ;; + download) image_cmd_download "$@" ;; + load) image_cmd_load "$@" ;; + use|set) image_cmd_use "$@" ;; + *) die "Unbekanntes Unterkommando 'image $sub'. + Moeglich: status | list | pull | download | load | use" ;; + esac +} + # ===================================================================== # Stack-Kommandos # ===================================================================== @@ -237,6 +682,10 @@ cmd_shell() { require_cmk_running; $RUNTIME exec -it "$CMK_CONTAINER_NAME" bas cmd_omd() { require_cmk_running; $RUNTIME exec -it "$CMK_CONTAINER_NAME" omd "$@"; } cmd_status() { + printf '\n%sImage%s\n' "$C_BLD" "$C_RST" + printf ' %-24s %s\n' "${CMK_IMAGE:-}" \ + "$(image_exists_local "${CMK_IMAGE:-}" && echo "lokal vorhanden" || echo "${C_YEL}nicht lokal vorhanden${C_RST}")" + printf '\n%sContainer%s\n' "$C_BLD" "$C_RST" local c for c in "$CMK_CONTAINER_NAME" "$NPM_CONTAINER_NAME"; do @@ -264,7 +713,7 @@ cmd_status() { printf ' Checkmk (direkt) : http://%s:5000/%s/\n' "$ip" "$CMK_SITE_ID" printf ' Checkmk (ueber Proxy) : https:///%s/\n' "$CMK_SITE_ID" printf ' Agent-Receiver : %s:8000\n' "$ip" - printf ' NGINX Proxy Manager : http://%s:81/ (Erstlogin: admin@example.com / changeme)\n\n' "$ip" + printf ' NGINX Proxy Manager : http://%s:%s/ (Erstlogin: admin@example.com / changeme)\n\n' "$ip" "${NPM_ADMIN_PORT:-81}" } # ===================================================================== @@ -503,17 +952,27 @@ do_restore() { err "Die Checkmk-Version des Backups ist im Container nicht installiert." printf ' benoetigt : %s\n' "$B_CMK_VERSION" printf ' installiert : %s\n' "$(printf '%s' "$installed" | tr '\n' ' ')" + local want_ver want_ed + want_ver="${B_CMK_VERSION%.*}" + case "$B_CMK_VERSION" in + *.cre) want_ed=raw ;; + *.cee) want_ed=enterprise ;; + *.cce) want_ed=cloud ;; + *.cme) want_ed=managed ;; + *) want_ed="${CMK_EDITION:-raw}" ;; + esac cat < --password EOF die "Abbruch wegen Versionskonflikt." fi @@ -524,8 +983,8 @@ EOF case "$B_CMK_VERSION" in *.cee|*.cme|*.cce) warn "Das Backup stammt aus einer $(edition_from_version "$B_CMK_VERSION"). - Dafuer wird das passende Enterprise-/Cloud-Image benoetigt - (CMK_IMAGE_REPO=checkmk/check-mk-enterprise)." ;; + Dafuer wird das passende Image benoetigt - die Raw-Edition genuegt nicht. + Aktuell konfiguriert: ${CMK_IMAGE:-}" ;; esac # --- vorhandene Site -------------------------------------------- @@ -655,6 +1114,509 @@ cmd_import() { fi } +# ===================================================================== +# Admin-Port des NGINX Proxy Managers +# +# Die Adminoberflaeche des Proxy Managers lauscht im Image fest auf Port 81 +# ("listen 81 default;" in /etc/nginx/conf.d/production.conf). Eine +# Umgebungsvariable dafuer gibt es in den veroeffentlichten 2.x-Versionen +# noch nicht. Da beide Container im Host-Netzwerk laufen, laesst sich der +# Port auch nicht per Port-Mapping verschieben. +# +# Loesung: nginx bindet in der Datei +# /data/nginx/custom/http.conf (= ./data/npm/data/nginx/custom/http.conf) +# einen offiziellen Erweiterungspunkt innerhalb des http{}-Blocks ein. +# Dort legen wir einen zusaetzlichen Server an, der auf dem gewuenschten +# Port lauscht und an die Oberflaeche auf 127.0.0.1:81 weiterreicht. +# +# Port 81 bleibt dabei lokal bestehen - er wird per Firewall dichtgehalten. +# ===================================================================== + +NPM_CUSTOM_CONF_REL="nginx/custom/http.conf" +NPM_BLOCK_START="# >>> cmk-manage.sh: Admin-Port - nicht von Hand aendern >>>" +NPM_BLOCK_END="# <<< cmk-manage.sh: Admin-Port <<<" + +npm_custom_conf_path() { + local base="${NPM_DATA_DIR:-$PROJECT_DIR/data/npm/data}" + case "$base" in /*) : ;; *) base="$PROJECT_DIR/${base#./}" ;; esac + printf '%s/%s\n' "$base" "$NPM_CUSTOM_CONF_REL" +} + +# Vorhandenen verwalteten Block entfernen, Fremdinhalte bleiben erhalten +npm_conf_strip_block() { + local f="$1" + [ -f "$f" ] || return 0 + awk -v s="$NPM_BLOCK_START" -v e="$NPM_BLOCK_END" ' + $0 == s { skip=1; next } + $0 == e { skip=0; next } + !skip { print } + ' "$f" > "$f.tmp" && mv "$f.tmp" "$f" +} + +npm_conf_write_block() { + local f="$1" port="$2" + mkdir -p "$(dirname "$f")" + touch "$f" + npm_conf_strip_block "$f" + { + printf '%s\n' "$NPM_BLOCK_START" + cat <> "$f" + # Leerzeilen am Anfang aufraeumen + sed -i '/./,$!d' "$f" +} + +port_in_use() { + command -v ss >/dev/null 2>&1 || return 1 + ss -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]$1\$" +} + +valid_port() { + case "$1" in + ''|*[!0-9]*) return 1 ;; + esac + [ "$1" -ge 1 ] && [ "$1" -le 65535 ] +} + +cmd_npm_port() { + local port="" restart=1 + while [ $# -gt 0 ]; do + case "$1" in + --no-restart) restart=""; shift ;; + -h|--help) + cat <<'EOF' +cmk-manage.sh npm-port [PORT] [--no-restart] + + Legt fest, auf welchem Port die Adminoberflaeche des NGINX Proxy Managers + erreichbar ist. Ohne PORT wird der aktuelle Stand angezeigt. + + 81 = Vorgabe, kein Zusatzeintrag noetig + sonst = zusaetzlicher nginx-Server auf diesem Port (Port 81 bleibt lokal + bestehen und sollte per Firewall dichtgehalten werden) +EOF + return 0 ;; + *) port="$1"; shift ;; + esac + done + + local conf; conf="$(npm_custom_conf_path)" + + if [ -z "$port" ]; then + printf '\n%sAdminoberflaeche des NGINX Proxy Managers%s\n' "$C_BLD" "$C_RST" + printf ' Konfigurierter Port : %s\n' "${NPM_ADMIN_PORT:-81}" + printf ' Adresse : %s\n' "${NPM_ADMIN_URL:-http://127.0.0.1:81}" + printf ' Zusatzkonfiguration : %s\n' \ + "$(grep -qsF "$NPM_BLOCK_START" "$conf" && echo "$conf" || echo 'keine (Vorgabe 81)')" + if [ "${NPM_ADMIN_PORT:-81}" != 81 ]; then + printf ' Port 81 lokal : %s\n' "$(port_in_use 81 && echo 'lauscht (per Firewall sperren)' || echo 'lauscht nicht')" + fi + echo + return 0 + fi + + valid_port "$port" || die "'$port' ist keine gueltige Portnummer (1-65535)." + + case "$port" in + 80|443) die "Port $port wird vom Proxy Manager bereits fuer HTTP/HTTPS genutzt." ;; + 5000) die "Port 5000 gehoert der Checkmk-Oberflaeche." ;; + 8000) die "Port 8000 gehoert dem Checkmk-Agent-Receiver." ;; + 6557) die "Port 6557 gehoert Livestatus." ;; + esac + + if [ "$port" != 81 ] && port_in_use "$port"; then + warn "Auf Port $port lauscht bereits ein Dienst." + confirm "Trotzdem fortfahren?" || die "Abgebrochen." + fi + + if [ "$port" = 81 ]; then + npm_conf_strip_block "$conf" + [ -s "$conf" ] || rm -f "$conf" + ok "Zusatzkonfiguration entfernt - es gilt wieder die Vorgabe (Port 81)." + else + npm_conf_write_block "$conf" "$port" + ok "Zusatzkonfiguration geschrieben: $conf" + fi + + env_set NPM_ADMIN_PORT "$port" + env_set NPM_ADMIN_URL "http://127.0.0.1:$port" + NPM_ADMIN_PORT="$port"; NPM_ADMIN_URL="http://127.0.0.1:$port" + + if [ -n "$restart" ] && container_running "$NPM_CONTAINER_NAME"; then + log "Starte '$NPM_CONTAINER_NAME' neu, damit nginx die Konfiguration liest ..." + if $RUNTIME restart "$NPM_CONTAINER_NAME" >/dev/null; then + ok "Proxy Manager neu gestartet." + else + warn "Neustart fehlgeschlagen - bitte manuell: $SELF restart" + fi + else + log "Wirksam nach: $SELF up (bzw. Neustart des Proxy Managers)" + fi + + local ip; ip="$(primary_ip)" + cat < "kategorie|key|typ|label|auswahl|leer" + settings_defs | awk -F'|' -v k="$1" '$2==k {print; exit}' +} + +settings_value() { # KEY -> aktueller Wert + eval "printf '%s' \"\${$1-}\"" +} + +settings_display() { # KEY TYP -> Anzeigewert (Kennwoerter maskiert) + local v; v="$(settings_value "$1")" + if [ "$2" = password ] && [ -n "$v" ]; then + printf '********' + elif [ -z "$v" ]; then + printf '' + else + printf '%s' "$v" + fi +} + +settings_validate() { # TYP WERT LEER_ERLAUBT -> 0/1, Meldung auf stdout + local typ="$1" val="$2" opt="$3" + if [ -z "$val" ]; then + [ -n "$opt" ] && return 0 + echo "Der Wert darf nicht leer sein."; return 1 + fi + case "$typ" in + port) valid_port "$val" || { echo "Keine gueltige Portnummer (1-65535)."; return 1; } ;; + int) case "$val" in ''|*[!0-9]*) echo "Bitte eine Zahl angeben."; return 1 ;; esac ;; + url) case "$val" in http://*|https://*) : ;; *) echo "Bitte mit http:// oder https:// beginnen."; return 1 ;; esac ;; + esac + return 0 +} + +# Zusaetzliche, schluesselbezogene Pruefung (ueber den Typ hinaus) +settings_validate_key() { + local key="$1" val="$2" + case "$key" in + CMK_RUNTIME) + [ -z "$val" ] && return 0 + command -v "$val" >/dev/null 2>&1 \ + || { echo "'$val' ist auf diesem System nicht installiert."; return 1; } ;; + CMK_SITE_ID) + case "$val" in + *[!a-zA-Z0-9_]*) echo "Ein Site-Name darf nur Buchstaben, Ziffern und _ enthalten."; return 1 ;; + esac + [ "${#val}" -le 16 ] || { echo "Ein Site-Name darf hoechstens 16 Zeichen lang sein."; return 1; } ;; + CMK_IMAGE|NPM_IMAGE|BROWSH_IMAGE|CARBONYL_IMAGE) + if [ -n "$val" ] && image_is_short_name "$val"; then + echo "Bitte vollqualifiziert angeben (z.B. docker.io/...) - Podman +findet kurze Namen sonst nicht."; return 1 + fi ;; + esac + return 0 +} + +# Nacharbeit nach dem Setzen bestimmter Schluessel +settings_post_set() { + local key="$1" val="$2" + case "$key" in + NPM_ADMIN_PORT) + # Der nginx-Zusatzblock muss mitgezogen werden + cmd_npm_port "$val" ;; + CMK_IMAGE|CMK_SITE_ID|CMK_CONTAINER_NAME|NPM_IMAGE|NPM_CONTAINER_NAME|TZ|CMK_LIVESTATUS_TCP|NPM_DISABLE_IPV6|CMK_DATA_DIR|NPM_DATA_DIR|NPM_LE_DIR) + log "Wirksam nach: $SELF up (Container werden neu erstellt)" ;; + esac +} + +cmd_config() { + local sub="${1:-list}"; [ $# -gt 0 ] && shift || true + case "$sub" in + list|ls) + local cat_filter="" + [ "${1:-}" = "--category" ] && cat_filter="$2" + local line c k t l + while IFS='|' read -r c k t l _ _; do + [ -n "$k" ] || continue + [ -n "$cat_filter" ] && [ "$c" != "$cat_filter" ] && continue + printf '%-24s %-10s %s\n' "$k" "$c" "$(settings_display "$k" "$t")" + done < <(settings_defs) + ;; + get) + [ $# -ge 1 ] || die "Schluessel fehlt: $SELF config get KEY" + [ -n "$(settings_def_for "$1")" ] || die "Unbekannter Schluessel '$1'. Uebersicht: $SELF config list" + settings_value "$1"; echo + ;; + set) + [ $# -ge 2 ] || die "Aufruf: $SELF config set KEY WERT" + local key="$1" val="$2" def typ opt msg + def="$(settings_def_for "$key")" + [ -n "$def" ] || die "Unbekannter Schluessel '$key'. Uebersicht: $SELF config list" + typ="$(printf '%s' "$def" | cut -d'|' -f3)" + opt="$(printf '%s' "$def" | cut -d'|' -f6)" + [ "$val" = "auto" ] && [ "$key" = CMK_RUNTIME ] && val="" + if ! msg="$(settings_validate "$typ" "$val" "$opt")"; then + die "$msg" + fi + if ! msg="$(settings_validate_key "$key" "$val")"; then + die "$msg" + fi + if [ "$key" = NPM_ADMIN_PORT ]; then + cmd_npm_port "$val" + else + env_set "$key" "$val" "$opt" + ok "$key=$val" + settings_post_set "$key" "$val" + fi + ;; + edit) + local f="${ENV_FILE:-$PROJECT_DIR/.env}" + "${EDITOR:-nano}" "$f"; load_env "$f"; ok "Konfiguration neu eingelesen." ;; + *) die "Unbekanntes Unterkommando 'config $sub'. + Moeglich: list [--category KAT] | get KEY | set KEY WERT | edit" ;; + esac +} + +# ===================================================================== +# Terminal-Browser im Container +# +# Zweck: den NGINX Proxy Manager direkt auf der Maschine einrichten, +# wenn dessen Adminoberflaeche (Port 81) von aussen nicht erreichbar ist. +# +# WICHTIG: Die Adminoberflaeche des Proxy Managers ist eine JavaScript- +# Anwendung. Klassische Textbrowser (links2, w3m, lynx) koennen sie NICHT +# darstellen. Dafuer gibt es zwei Engines, die einen echten Browser im +# Terminal rendern: +# browsh - Firefox im Terminal (gepflegt) +# carbonyl - Chromium im Terminal (schoenere Darstellung, Stand 2023) +# Die Textbrowser bleiben fuer schnelle Pruefungen nuetzlich. +# +# Der Container laeuft im Host-Netzwerk und erreicht damit 127.0.0.1:81 +# genau wie der Proxy Manager selbst. +# ===================================================================== + +browser_tools_image() { + if [ -n "${BROWSER_TOOLS_IMAGE:-}" ]; then + printf '%s\n' "$BROWSER_TOOLS_IMAGE" + elif [ "$RUNTIME" = podman ]; then + # Podman legt selbst gebaute Images unter localhost/ ab + printf '%s\n' "localhost/checkmk-stack/browser-tools:1" + else + # Docker wuerde ein "localhost/"-Praefix als echte Registry deuten + printf '%s\n' "checkmk-stack/browser-tools:1" + fi +} + +browser_build_tools() { + local img; img="$(browser_tools_image)" + local ctx="$PROJECT_DIR/containers/browser" + [ -f "$ctx/Containerfile" ] || die "Containerfile fehlt: $ctx/Containerfile" + log "Baue Werkzeug-Image '$img' ..." + # -f explizit: Docker sucht sonst nach "Dockerfile", Podman nimmt beides + $RUNTIME build -f "$ctx/Containerfile" -t "$img" "$ctx" \ + || die "Bau des Werkzeug-Images fehlgeschlagen." + ok "Image gebaut: $img" +} + +browser_ensure_tools() { + local img; img="$(browser_tools_image)" + image_exists_local "$img" || browser_build_tools +} + +cmd_browser() { + local engine="${BROWSER_ENGINE:-browsh}" + local url="" build="" build_only="" pull="" mono="" + while [ $# -gt 0 ]; do + case "$1" in + -e|--engine) engine="$2"; shift 2 ;; + -u|--url) url="$2"; shift 2 ;; + --build) build=1; shift ;; + --build-only) build=1; build_only=1; shift ;; + --pull) pull=1; shift ;; + --monochrome) mono=1; shift ;; + -h|--help) + cat <<'EOF' +cmk-manage.sh browser - Terminal-Browser im Container + + -e, --engine ENGINE browsh Firefox im Terminal (Vorgabe, kann JavaScript) + carbonyl Chromium im Terminal (kann JavaScript) + links links2 (Textbrowser, KEIN JavaScript) + w3m w3m (Textbrowser, KEIN JavaScript) + lynx lynx (Textbrowser, KEIN JavaScript) + shell Bash mit curl/jq/openssl im Host-Netzwerk + -u, --url URL Startseite (Vorgabe: $NPM_ADMIN_URL, sonst + http://127.0.0.1:81 = Proxy-Manager-Oberflaeche) + --build Werkzeug-Image neu bauen und danach starten + --build-only Werkzeug-Image nur bauen (ohne Terminal, z.B. im Skript) + --pull Image der gewaehlten Engine neu laden + --monochrome nur bei browsh: einfarbige Darstellung + +Bedienung browsh: Strg+L Adresszeile, Strg+T neuer Tab, + Strg+W Tab schliessen, Strg+Q beenden +EOF + return 0 ;; + *) die "Unbekannte Option fuer browser: $1" ;; + esac + done + + url="${url:-${NPM_ADMIN_URL:-http://127.0.0.1:81}}" + + # Engine-Namen zuerst pruefen, damit ein Tippfehler auch ohne + # Terminal eine brauchbare Meldung ergibt + case "$engine" in + browsh|carbonyl|links|links2|w3m|lynx|shell) : ;; + *) die "Unbekannte Engine '$engine'. + Moeglich: browsh | carbonyl | links | w3m | lynx | shell" ;; + esac + + # Bauen braucht kein Terminal - deshalb vor der TTY-Pruefung + if [ -n "$build" ]; then + browser_build_tools + [ -n "$build_only" ] && return 0 + fi + + if [ ! -t 0 ] || [ ! -t 1 ]; then + die "Ein Terminal-Browser braucht ein echtes Terminal (TTY). + Bitte direkt auf der Konsole bzw. in einer SSH-Sitzung aufrufen, + nicht in einer Pipe oder aus einem Skript heraus." + fi + + local image + local -a args=() runopts=() + case "$engine" in + browsh) + image="${BROWSH_IMAGE:-docker.io/browsh/browsh:v1.8.3}" + args=(--startup-url "$url") + [ -n "$mono" ] && args+=(--monochrome) + ;; + carbonyl) + image="${CARBONYL_IMAGE:-docker.io/fathyb/carbonyl:latest}" + args=("$url") + ;; + links|links2) + browser_ensure_tools; image="$(browser_tools_image)"; args=(links2 "$url") ;; + w3m) + browser_ensure_tools; image="$(browser_tools_image)"; args=(w3m "$url") ;; + lynx) + browser_ensure_tools; image="$(browser_tools_image)"; args=(lynx "$url") ;; + shell) + browser_ensure_tools; image="$(browser_tools_image)"; args=(/bin/bash) ;; + esac + + if [ -n "$pull" ]; then + case "$engine" in + browsh|carbonyl) log "Lade $image ..."; $RUNTIME pull "$image" || die "Konnte '$image' nicht laden." ;; + *) browser_build_tools ;; + esac + fi + + case "$engine" in + links|w3m|lynx) + warn "Textbrowser koennen kein JavaScript - die Oberflaeche des + NGINX Proxy Managers laesst sich damit NICHT bedienen. + Dafuer: $SELF browser --engine browsh" ;; + esac + + log "Starte $engine im Host-Netzwerk -> $url" + [ "$engine" = browsh ] && log "Beenden mit Strg+Q, Adresszeile mit Strg+L." + + runopts=(--rm -it --network host + -e "TERM=${TERM:-xterm-256color}" + -e "COLORTERM=${COLORTERM:-truecolor}") + + $RUNTIME run "${runopts[@]}" "$image" "${args[@]}" +} + # ===================================================================== # Selbstsigniertes Zertifikat fuer den NGINX Proxy Manager # ===================================================================== @@ -912,6 +1874,226 @@ gui_sites_menu() { done } +gui_image_menu() { + while :; do + local sel + sel="$(ui_menu "Checkmk-Image" \ +"Aktuell (.env): ${CMK_IMAGE:-} +Edition/Version: ${CMK_EDITION:-raw} / ${CMK_VERSION:-?}" \ + status "Status und lokale Images anzeigen" \ + pull "Aus Registry holen (Docker Hub / registry.checkmk.com)" \ + download "Tarball vom Downloadportal holen (mit Zugangsdaten)" \ + load "Heruntergeladenen Tarball einspielen (load)" \ + use "Vorhandenes Image auswaehlen" \ + back "zurueck")" || return 0 + case "$sel" in + status) local f; f="$(mktemp)"; NO_COLOR=1 cmd_image status >"$f" 2>&1 || true + ui_text "Image-Status" "$f"; rm -f "$f" ;; + pull) gui_image_pull ;; + download) gui_image_download ;; + load) local lf; lf="$(ui_pick_file "${IMAGE_DIR:-$PROJECT_DIR/images}" '*.tar.gz')" || continue + [ -n "$lf" ] || continue + ui_run "Image einspielen" bash -c "cd '$PROJECT_DIR' && '$SELF' -y image load --file '$lf'" + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" ;; + use) gui_image_use ;; + back) return 0 ;; + esac + done +} + +gui_image_pick_edition() { + ui_menu "Edition" "Welche Checkmk-Edition?" \ + raw "Raw (frei, Docker Hub, bis 2.4)" \ + community "Community (frei, Docker Hub, ab 2.5)" \ + enterprise "Enterprise (NICHT auf Docker Hub - Login noetig)" \ + pro "Pro (ab 2.5, Nachfolger von Enterprise)" \ + cloud "Cloud (Docker Hub)" \ + managed "Managed (Docker Hub, bis 2.4)" \ + ultimate "Ultimate (ab 2.5)" \ + ultimatemt "Ultimate Multi-Tenancy (ab 2.5)" +} + +gui_image_pull() { + local ed ver user pass + ed="$(gui_image_pick_edition)" || return + ver="$(ui_input "Version" "Version bzw. Tag (z.B. 2.3.0p23 oder 2.3.0-latest):" "${CMK_VERSION:-}")" || return + [ -n "$ver" ] || return + local -a extra=() + if [ "$ed" = enterprise ] || [ -n "${CMK_REGISTRY_USER:-}" ]; then + user="$(ui_input "Registry-Anmeldung" "Benutzer (Checkmk-Kundenportal):" "${CMK_REGISTRY_USER:-}")" || return + pass="$(ui_password "Registry-Anmeldung" "Kennwort:")" || return + [ -n "$user" ] && extra+=(--user "$user" --password "$pass") + fi + ui_run "Image holen" bash -c "cd '$PROJECT_DIR' && '$SELF' -y image pull --edition '$ed' --version '$ver' ${extra[*]+${extra[*]}}" + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" +} + +gui_image_download() { + local ed ver user pass + ed="$(gui_image_pick_edition)" || return + ver="$(ui_input "Version" "EXAKTE Version (z.B. 2.3.0p23 - kein '-latest'):" "${CMK_VERSION:-}")" || return + [ -n "$ver" ] || return + user="$(ui_input "Downloadportal" "Benutzer:" "${CMK_DOWNLOAD_USER:-}")" || return + pass="$(ui_password "Downloadportal" "Kennwort:")" || return + ui_run "Image herunterladen" bash -c "cd '$PROJECT_DIR' && '$SELF' -y image download --edition '$ed' --version '$ver' --user '$user' --password '$pass'" + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" +} + +gui_image_use() { + local -a items=() l + while IFS= read -r l; do + [ -n "$l" ] || continue + items+=("$l" "$([ "$l" = "${CMK_IMAGE:-}" ] && echo '(aktuell)' || echo ' ')") + done < <(image_local_list) + [ ${#items[@]} -gt 0 ] || { ui_msg "Images" "Es ist kein Checkmk-Image lokal vorhanden.\n\nZuerst 'pull', 'download' oder 'load' verwenden."; return; } + local sel + sel="$(ui_menu "Image auswaehlen" "Lokal vorhandene Checkmk-Images:" "${items[@]}")" || return + ui_run "Image setzen" bash -c "cd '$PROJECT_DIR' && '$SELF' -y image use '$sel'" + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" +} + +# --------------------------------------------------------------------- +# Einstellungen im Menue +# --------------------------------------------------------------------- +settings_needs_restart() { + case "$1" in + CMK_IMAGE|CMK_SITE_ID|CMK_CONTAINER_NAME|CMK_HOSTNAME|CMK_PASSWORD|\ + CMK_LIVESTATUS_TCP|MAIL_RELAY_HOST|TZ|NPM_IMAGE|NPM_CONTAINER_NAME|\ + NPM_DISABLE_IPV6|CMK_DATA_DIR|NPM_DATA_DIR|NPM_LE_DIR) return 0 ;; + *) return 1 ;; + esac +} + +gui_settings_edit() { + local key="$1" def typ label choices opt cur new msg + def="$(settings_def_for "$key")" + [ -n "$def" ] || { ui_msg "Fehler" "Unbekannter Schluessel '$key'."; return; } + typ="$(printf '%s' "$def" | cut -d'|' -f3)" + label="$(printf '%s' "$def" | cut -d'|' -f4)" + choices="$(printf '%s' "$def"| cut -d'|' -f5)" + opt="$(printf '%s' "$def" | cut -d'|' -f6)" + cur="$(settings_value "$key")" + + while :; do + case "$typ" in + choice) + local -a ropts=() c + [ -z "$cur" ] && case ":$choices:" in *:auto:*) cur=auto ;; esac + local IFS_BAK="$IFS"; IFS=':' + for c in $choices; do + IFS="$IFS_BAK" + ropts+=("$c" " " "$([ "$c" = "$cur" ] && echo on || echo off)") + IFS=':' + done + IFS="$IFS_BAK" + new="$(ui_radiolist "$key" "$label\n\nAktuell: ${cur:-}" "${ropts[@]}")" || return + [ "$new" = auto ] && new="" + ;; + password) + new="$(ui_password "$key" "$label\n\n(leer lassen = unveraendert)")" || return + [ -z "$new" ] && return + ;; + *) + new="$(ui_input "$key" "$label\n\nTyp: $typ$([ -n "$opt" ] && echo ' (darf leer bleiben)')" "$cur")" || return + ;; + esac + + if msg="$(settings_validate "$typ" "$new" "$opt")" \ + && msg="$(settings_validate_key "$key" "$new")"; then + break + else + ui_msg "Ungueltige Eingabe" "$msg" + cur="$new" + fi + done + + if [ "$key" = NPM_ADMIN_PORT ]; then + ui_run "Admin-Port setzen" bash -c "cd '$PROJECT_DIR' && '$SELF' -y npm-port '$new'" + else + env_set "$key" "$new" "$opt" + local hint="" + settings_needs_restart "$key" && hint="\n\nWirksam nach 'Stack steuern -> Stack starten'\n(die Container werden dabei neu erstellt)." + ui_msg "Gespeichert" "$key = $([ "$typ" = password ] && echo '********' || echo "${new:-}")$hint" + fi + load_env "${ENV_FILE:-$PROJECT_DIR/.env}" +} + +gui_settings_category() { + local cat="$1" title="$2" + while :; do + local -a items=() c k t l ch o + while IFS='|' read -r c k t l ch o; do + [ "$c" = "$cat" ] || continue + items+=("$k" "$l = $(settings_display "$k" "$t")") + done < <(settings_defs) + items+=("back" "zurueck") + local sel + sel="$(ui_menu "$title" "Eintrag waehlen und mit ENTER aendern:" "${items[@]}")" || return 0 + [ "$sel" = back ] && return 0 + gui_settings_edit "$sel" + done +} + +gui_settings_menu() { + while :; do + local -a items=() c l + while IFS='|' read -r c l; do + [ -n "$c" ] && items+=("$c" "$l") + done < <(settings_categories) + items+=("show" "Alle Werte auflisten") + items+=("editor" "Datei .env im Editor oeffnen") + items+=("back" "zurueck") + local sel + sel="$(ui_menu "Einstellungen" \ +"Alle Werte der Datei .env - direkt hier aenderbar. +Datei: ${ENV_FILE:-$PROJECT_DIR/.env}" "${items[@]}")" || return 0 + case "$sel" in + back) return 0 ;; + show) local f; f="$(mktemp)" + { printf '%-24s %-10s %s\n' "SCHLUESSEL" "BEREICH" "WERT" + NO_COLOR=1 cmd_config list; } >"$f" 2>&1 + ui_text "Alle Einstellungen" "$f"; rm -f "$f" ;; + editor) local ef="${ENV_FILE:-$PROJECT_DIR/.env}" + clear; "${EDITOR:-nano}" "$ef" + load_env "$ef"; ui_msg "Konfiguration" "Die .env wurde neu eingelesen." ;; + *) local title + title="$(settings_categories | awk -F'|' -v c="$sel" '$1==c{print $2}')" + gui_settings_category "$sel" "${title:-$sel}" ;; + esac + done +} + +gui_browser_menu() { + while :; do + local sel + sel="$(ui_menu "Terminal-Browser" \ +"Bedienung des NGINX Proxy Managers direkt auf dieser Maschine. +Startseite: ${NPM_ADMIN_URL:-http://127.0.0.1:81} + +Nur browsh und carbonyl koennen JavaScript und damit die +Oberflaeche des Proxy Managers darstellen." \ + browsh "Firefox im Terminal (empfohlen)" \ + carbonyl "Chromium im Terminal" \ + links "links2 - Textbrowser, KEIN JavaScript" \ + w3m "w3m - Textbrowser, KEIN JavaScript" \ + lynx "lynx - Textbrowser, KEIN JavaScript" \ + shell "Shell mit curl/jq/openssl im Host-Netzwerk" \ + url "Andere Startseite eingeben" \ + build "Werkzeug-Image neu bauen" \ + back "zurueck")" || return 0 + case "$sel" in + url) local u + u="$(ui_input "Startseite" "URL:" "${NPM_ADMIN_URL:-http://127.0.0.1:81}")" || continue + [ -n "$u" ] && NPM_ADMIN_URL="$u" ;; + build) ui_run "Werkzeug-Image bauen" bash -c "cd '$PROJECT_DIR' && '$SELF' browser --build-only" || true ;; + back) return 0 ;; + *) clear + cmd_browser --engine "$sel" --url "${NPM_ADMIN_URL:-http://127.0.0.1:81}" || true + ;; + esac + done +} + gui_cert() { local domain alt days domain="$(ui_input "Zertifikat" "FQDN / Common Name:" "${CERT_DOMAIN:-checkmk.example.local}")" || return @@ -923,16 +2105,6 @@ gui_cert() { ui_run "Zertifikat erzeugen" bash -c "cd '$PROJECT_DIR' && '$SELF' cert --domain '$domain' --days '$days' ${a[*]+${a[*]}}" } -gui_env() { - local f="${ENV_FILE:-$PROJECT_DIR/.env}" - [ -f "$f" ] || { ui_msg ".env" "Keine .env vorhanden."; return; } - ui_text "Konfiguration ($f)" "$f" - if ui_yesno "Bearbeiten" "Die .env jetzt im Editor oeffnen?"; then - "${EDITOR:-nano}" "$f" - load_env "$f" - fi -} - gui_main() { ui_require while :; do @@ -948,8 +2120,10 @@ Backups : $BACKUP_DIR" \ import "Site von Direktinstallation importieren" \ manage "Backups verwalten (Liste/Details/Loeschen)" \ sites "Sites im Container verwalten" \ + image "Checkmk-Image beschaffen/auswaehlen" \ + browser "Terminal-Browser (Proxy Manager lokal bedienen)" \ cert "Selbstsigniertes Zertifikat erzeugen" \ - env "Konfiguration (.env) ansehen/bearbeiten" \ + config "Einstellungen (.env) - menuegefuehrt" \ shell "Root-Shell im Checkmk-Container" \ quit "Beenden")" || break case "$sel" in @@ -960,8 +2134,10 @@ Backups : $BACKUP_DIR" \ import) gui_import ;; manage) gui_backups_menu ;; sites) gui_sites_menu ;; + image) gui_image_menu ;; + browser) gui_browser_menu ;; cert) gui_cert ;; - env) gui_env ;; + config) gui_settings_menu ;; shell) clear; cmd_shell || true ;; quit) break ;; esac @@ -1011,6 +2187,10 @@ main() { restore) cmd_restore "$@" ;; import) cmd_import "$@" ;; cert) cmd_cert "$@" ;; + image) cmd_image "$@" ;; + browser) cmd_browser "$@" ;; + npm-port) cmd_npm_port "$@" ;; + config) cmd_config "$@" ;; help|-h|--help) usage ;; *) err "Unbekanntes Kommando: $cmd"; echo; usage; exit 1 ;; esac diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index 0c7b021..f7979e5 100644 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -36,21 +36,42 @@ load_env() { warn "Keine .env gefunden ($envfile) - es gelten die Standardwerte." ENV_FILE="" fi - # Defaults + # Rueckfallwerte, falls ein Schluessel in der .env fehlt. + # Die .env bleibt die massgebliche Konfiguration - hier steht nur, + # was gilt, wenn dort nichts eingetragen ist. CMK_CONTAINER_NAME="${CMK_CONTAINER_NAME:-checkmk}" NPM_CONTAINER_NAME="${NPM_CONTAINER_NAME:-nginx-proxy-manager}" CMK_SITE_ID="${CMK_SITE_ID:-cmk}" - BACKUP_DIR="${BACKUP_DIR:-$PROJECT_DIR/backups}" - case "$BACKUP_DIR" in - /*) : ;; - *) BACKUP_DIR="$PROJECT_DIR/${BACKUP_DIR#./}" ;; + CMK_IMAGE="${CMK_IMAGE:-docker.io/checkmk/check-mk-raw:2.3.0-latest}" + NPM_ADMIN_PORT="${NPM_ADMIN_PORT:-81}" + # Leer = automatisch aus dem Admin-Port ableiten + NPM_ADMIN_URL="${NPM_ADMIN_URL:-http://127.0.0.1:$NPM_ADMIN_PORT}" + BACKUP_DIR="$(abs_path "${BACKUP_DIR:-$PROJECT_DIR/backups}")" + IMAGE_DIR="$(abs_path "${IMAGE_DIR:-$PROJECT_DIR/images}")" +} + +# relativen Pfad (./foo) am Projektverzeichnis ausrichten +abs_path() { + case "$1" in + /*) printf '%s\n' "$1" ;; + *) printf '%s\n' "$PROJECT_DIR/${1#./}" ;; esac } # .env-Wert dauerhaft setzen +# env_set KEY WERT [allow_empty] env_set() { - local key="$1" val="$2" f="${ENV_FILE:-$PROJECT_DIR/.env}" + local key="$1" val="$2" allow_empty="${3:-}" f="${ENV_FILE:-$PROJECT_DIR/.env}" [ -f "$f" ] || die "Keine .env vorhanden - kann '$key' nicht setzen." + # mehrzeilige Werte wuerden die .env zerstoeren + case "$val" in + *$'\n'*) die "Ungueltiger Wert fuer '$key' (mehrzeilig)." ;; + esac + [ -n "$val" ] || [ -n "$allow_empty" ] || die "Leerer Wert fuer '$key' - abgebrochen." + # Werte mit Leerzeichen in Anfuehrungszeichen setzen + case "$val" in + *" "*) case "$val" in \"*\") : ;; *) val="\"$val\"" ;; esac ;; + esac if grep -qE "^[#[:space:]]*${key}=" "$f"; then sed -i -E "s|^[#[:space:]]*${key}=.*|${key}=${val}|" "$f" else @@ -63,10 +84,15 @@ env_set() { # Container-Runtime erkennen (docker / podman) # --------------------------------------------------------------------- detect_runtime() { - if [ -n "${CMK_RUNTIME:-}" ]; then - command -v "$CMK_RUNTIME" >/dev/null 2>&1 \ - || die "CMK_RUNTIME='$CMK_RUNTIME' ist nicht installiert." + if [ -n "${CMK_RUNTIME:-}" ] && command -v "$CMK_RUNTIME" >/dev/null 2>&1; then RUNTIME="$CMK_RUNTIME" + elif [ -n "${CMK_RUNTIME:-}" ]; then + # Falsch gesetzter Wert darf das Werkzeug nicht unbenutzbar machen + warn "CMK_RUNTIME='$CMK_RUNTIME' ist nicht installiert - suche selbst. + Korrigieren mit: cmk-manage.sh config set CMK_RUNTIME auto" + CMK_RUNTIME="" + detect_runtime + return elif command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then RUNTIME=docker elif command -v podman >/dev/null 2>&1; then @@ -187,11 +213,13 @@ primary_ip() { UI_BACKTITLE="Checkmk Stack Manager - Container-Runtime: ${RUNTIME:-?}" ui_init() { + # Geometrie IMMER setzen - sonst laeuft das Skript unter "set -u" auf + # eine unbound variable, wenn UI_BIN von aussen vorgegeben wurde. + UI_H="${UI_H:-22}"; UI_W="${UI_W:-78}"; UI_MH="${UI_MH:-13}" [ -n "${UI_BIN:-}" ] && return 0 if command -v dialog >/dev/null 2>&1; then UI_BIN=dialog elif command -v whiptail >/dev/null 2>&1; then UI_BIN=whiptail else UI_BIN=""; fi - UI_H="${UI_H:-22}"; UI_W="${UI_W:-78}"; UI_MH="${UI_MH:-13}" export DIALOGRC="${DIALOGRC:-}" } @@ -205,51 +233,61 @@ ui_require() { } ui_menu() { # title text tag item [tag item ...] -> gewaehlter tag auf stdout + ui_init local title="$1" text="$2"; shift 2 "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$title" \ --menu "$text" "$UI_H" "$UI_W" "$UI_MH" "$@" 3>&1 1>&2 2>&3 } ui_checklist() { # title text tag item status ... + ui_init local title="$1" text="$2"; shift 2 "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$title" \ --checklist "$text" "$UI_H" "$UI_W" "$UI_MH" "$@" 3>&1 1>&2 2>&3 } ui_radiolist() { + ui_init local title="$1" text="$2"; shift 2 "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$title" \ --radiolist "$text" "$UI_H" "$UI_W" "$UI_MH" "$@" 3>&1 1>&2 2>&3 } ui_input() { # title text default + ui_init "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" \ --inputbox "$2" 10 "$UI_W" "${3:-}" 3>&1 1>&2 2>&3 } ui_password() { + ui_init "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" \ --passwordbox "$2" 10 "$UI_W" 3>&1 1>&2 2>&3 } ui_msg() { # title text + ui_init "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --msgbox "$2" 16 "$UI_W" } ui_yesno() { # title text -> exit 0 = ja + ui_init "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --yesno "$2" 14 "$UI_W" } ui_text() { # title file + ui_init "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --textbox "$2" "$UI_H" "$UI_W" } ui_info() { # title text (ohne OK-Button) + ui_init "$UI_BIN" --backtitle "$UI_BACKTITLE" --title "$1" --infobox "$2" 8 "$UI_W" } # Kommando ausfuehren, Ausgabe live in Datei, danach in Textbox anzeigen ui_run() { # title cmd... + ui_init local title="$1"; shift local logf; logf="$(mktemp)" ui_info "$title" "Bitte warten ...\n\n$*" @@ -266,6 +304,7 @@ ui_run() { # title cmd... # Dateiauswahl im Midnight-Commander-Stil (funktioniert auch mit whiptail) # --------------------------------------------------------------------- ui_pick_file() { # startdir [glob] -> Dateipfad auf stdout + ui_init local dir="${1:-$PWD}" glob="${2:-*}" sel dir="$(cd "$dir" 2>/dev/null && pwd || echo "$PWD")" while :; do diff --git a/scripts/migrate_creator.sh b/scripts/migrate_creator.sh index 4e536a0..51302c4 100755 --- a/scripts/migrate_creator.sh +++ b/scripts/migrate_creator.sh @@ -206,9 +206,19 @@ SHA256 : $sum Import auf dem Zielsystem (Container-Installation): 1) Bundle in das Verzeichnis ./backups des Projekts kopieren - 2) In der .env die passende Checkmk-Version eintragen: - CMK_IMAGE_TAG=${version%.*} - und den Stack neu erstellen: ./scripts/cmk-manage.sh up + 2) Passendes Image beschaffen (Version MUSS uebereinstimmen): + ./scripts/cmk-manage.sh image pull --edition $( + case "$version" in + *.cre) echo raw ;; + *.cee) echo enterprise ;; + *.cce) echo cloud ;; + *.cme) echo managed ;; + *) echo raw ;; + esac) --version ${version%.*} + Die Enterprise-Edition liegt NICHT auf Docker Hub - dort zusaetzlich + --user/--password (Checkmk-Kundenportal) angeben oder + "image download" verwenden. + Danach: ./scripts/cmk-manage.sh up 3) Import ausfuehren: ./scripts/cmk-manage.sh import --file backups/$(basename "$outfile") --set-default-site diff --git a/systemd/quadlet/checkmk.container b/systemd/quadlet/checkmk.container index 4f21410..24221c6 100644 --- a/systemd/quadlet/checkmk.container +++ b/systemd/quadlet/checkmk.container @@ -12,7 +12,7 @@ After=network-online.target [Container] ContainerName=__CMK_CONTAINER_NAME__ -Image=docker.io/__CMK_IMAGE__ +Image=__CMK_IMAGE__ Network=host EnvironmentFile=__PROJECT_DIR__/.env Environment=CMK_SITE_ID=__CMK_SITE_ID__ diff --git a/systemd/quadlet/nginx-proxy-manager.container b/systemd/quadlet/nginx-proxy-manager.container index 439c5f1..10a725d 100644 --- a/systemd/quadlet/nginx-proxy-manager.container +++ b/systemd/quadlet/nginx-proxy-manager.container @@ -9,7 +9,7 @@ After=network-online.target checkmk.service [Container] ContainerName=__NPM_CONTAINER_NAME__ -Image=docker.io/__NPM_IMAGE__ +Image=__NPM_IMAGE__ Network=host EnvironmentFile=__PROJECT_DIR__/.env Environment=DISABLE_IPV6=true