Drei Verbesserungen an den Update-Skripten

1. Gewartet wird jetzt auf ALLE vier Container, nicht nur auf espocrm.
   "health: starting" im Bericht war keine Aussage. Scheitert es, nennt die
   Fehlermeldung, welcher Container in welchem Zustand haengt. Gilt fuer
   ESPO-03, ESPO-10 und ESPO-12.

2. ESPO-10 raeumt alte Images weg: Es bleiben genau zwei je Anwendung, das
   laufende und das vorherige - fuer EspoCRM wie fuer MariaDB. Das vorherige
   muss bleiben, sonst zeigt die von ESPO-12 zurueckgerollte Compose auf einen
   Tag, der lokal nicht mehr liegt. Alles aeltere fuellte bisher nur das
   docker-lv; Docker raeumt von sich aus nichts weg.

3. ESPO-10 zeigt einen eigenen Abschnitt "Datenbank" mit Image, Version und
   Digest, analog zum Abschnitt "Instanz", sowie die Images auf der VM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
gordon.zimm 2026-09-24 17:21:54 +02:00
parent e63d1b432b
commit 5c15ac3f0b
3 changed files with 90 additions and 10 deletions

View File

@ -14,6 +14,25 @@ WARTE_MAX=900
FQDN="${1:-}"
RING="${2:-}"
# Wartet, bis alle vier Container "healthy" melden - "starting" ist keine Aussage.
alle_gesund() {
local c
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] || return 1
done
return 0
}
# Nennt die Container, die noch nicht gesund sind - fuer die Fehlermeldung.
nicht_gesund() {
local c z=""
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] \
|| z="$z $c=$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null || echo fehlt)"
done
printf '%s' "${z# }"
}
fehler() { echo "FEHLER: $*"; echo "ESPO03_ERGEBNIS: FEHLER"; exit 1; }
# 1. Vorbedingungen - lieber hier abbrechen als auf halbem Weg.
@ -65,11 +84,10 @@ START_AUSGABE="$(docker compose -f /srv/espo/docker-compose.yml up -d --quiet-pu
# 7. Auf die Anwendung warten. Der erste Lauf installiert und baut das Schema auf, das dauert.
ENDE=$(( SECONDS + WARTE_MAX ))
while [ "$SECONDS" -lt "$ENDE" ]; do
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] && break
alle_gesund && break
sleep 10
done
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] \
|| fehler "espocrm nach ${WARTE_MAX}s nicht gesund - 'docker logs espocrm' ansehen"
alle_gesund || fehler "nach ${WARTE_MAX}s nicht alle Container gesund: $(nicht_gesund) - 'docker logs <name>' ansehen"
# 8. Ergebnis zeigen. Die Datenbankabfragen laufen im Container und lesen das Passwort dort aus der Secret-Datei,
# damit es weder im Skript noch in der Prozessliste der VM auftaucht.

View File

@ -18,6 +18,25 @@ WARTE_MAX=900
FQDN="${1:-}"
RING="${2:-}"
# Wartet, bis alle vier Container "healthy" melden - "starting" ist keine Aussage.
alle_gesund() {
local c
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] || return 1
done
return 0
}
# Nennt die Container, die noch nicht gesund sind - fuer die Fehlermeldung.
nicht_gesund() {
local c z=""
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] \
|| z="$z $c=$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null || echo fehlt)"
done
printf '%s' "${z# }"
}
fehler() { echo "FEHLER: $*"; echo "ESPO10_ERGEBNIS: FEHLER"; exit 1; }
# 1. Vorbedingungen - lieber hier abbrechen als auf halbem Weg.
@ -37,6 +56,9 @@ fi
# 3. Ausgangsstand festhalten, damit der Bericht ein Vorher und ein Nachher hat.
VORHER_IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm 2>/dev/null)"
VORHER_VERSION="$(docker exec espocrm php -r '$v=""; foreach (["/var/www/html/application/Espo/Resources/defaults/config.php","/var/www/html/data/config.php","/var/www/html/data/config-internal.php"] as $f) { $a=@include $f; if (is_array($a) && !empty($a["version"])) { $v=$a["version"]; } } echo $v;' 2>/dev/null)"
VORHER_ESPO_ID="$(docker inspect -f '{{.Image}}' espocrm 2>/dev/null)"
VORHER_DB_ID="$(docker inspect -f '{{.Image}}' espocrm-db 2>/dev/null)"
VORHER_DB_IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm-db 2>/dev/null)"
echo "Vorher: Image ${VORHER_IMAGE:-unbekannt}, Version ${VORHER_VERSION:-unbekannt}"
# 4. Erst der Rueckweg, dann das Update. Ohne Snapshot wird nichts angefasst.
@ -70,23 +92,45 @@ START_AUSGABE="$(docker compose -f /srv/espo/docker-compose.yml up -d --quiet-pu
# 7. Auf die Anwendung warten. Waehrend der Migration meldet app-check absichtlich nicht gesund.
ENDE=$(( SECONDS + WARTE_MAX ))
while [ "$SECONDS" -lt "$ENDE" ]; do
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] && break
alle_gesund && break
sleep 10
done
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] \
|| fehler "espocrm nach ${WARTE_MAX}s nicht gesund - 'docker logs espocrm' ansehen, Snapshot '$SNAPSHOT' steht bereit"
alle_gesund || fehler "nach ${WARTE_MAX}s nicht alle Container gesund: $(nicht_gesund) - 'docker logs <name>' ansehen"
# 8. Ergebnis zeigen.
echo "--- Container"
docker compose -f /srv/espo/docker-compose.yml ps --format 'table {{.Name}}\t{{.Status}}'
echo "--- Instanz"
NACHHER_IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm 2>/dev/null)"
NACHHER_ESPO_ID="$(docker inspect -f '{{.Image}}' espocrm 2>/dev/null)"
NACHHER_VERSION="$(docker exec espocrm php -r '$v=""; foreach (["/var/www/html/application/Espo/Resources/defaults/config.php","/var/www/html/data/config.php","/var/www/html/data/config-internal.php"] as $f) { $a=@include $f; if (is_array($a) && !empty($a["version"])) { $v=$a["version"]; } } echo $v;' 2>/dev/null)"
echo "Image: ${VORHER_IMAGE:-unbekannt} -> ${NACHHER_IMAGE:-unbekannt}"
echo "Version: ${VORHER_VERSION:-unbekannt} -> ${NACHHER_VERSION:-unbekannt}"
echo "Digest: $(docker image inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{else}}{{.Id}}{{end}}' "$NACHHER_IMAGE" 2>/dev/null)"
echo "--- Datenbank"
NACHHER_DB_IMAGE="$(docker inspect -f '{{.Config.Image}}' espocrm-db 2>/dev/null)"
NACHHER_DB_ID="$(docker inspect -f '{{.Image}}' espocrm-db 2>/dev/null)"
echo "Image: ${VORHER_DB_IMAGE:-unbekannt} -> ${NACHHER_DB_IMAGE:-unbekannt}"
echo "Version: $(docker exec espocrm-db sh -c 'mariadb -u root -p"$(cat /run/secrets/db_root_password)" -N -B -e "select version()"' 2>/dev/null | tr -d '\r')"
echo "Digest: $(docker image inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{else}}{{.Id}}{{end}}' "$NACHHER_DB_IMAGE" 2>/dev/null)"
# Alte Images wegraeumen: Es bleiben genau zwei je Anwendung - das laufende und das vorherige.
# Das vorherige muss bleiben, sonst zeigt die zurueckgerollte Compose nach ESPO-12 auf einen Tag,
# der lokal nicht mehr liegt. Alles aeltere ist nur Platzverbrauch auf dem docker-lv.
aufraeumen() { # aufraeumen <repository> <behalten-id-1> <behalten-id-2>
local repo="$1" a="$2" b="$3" id
docker image ls --no-trunc --format '{{.ID}} {{.Repository}}' 2>/dev/null \
| awk -v r="$repo" '$2 == r {print $1}' | sort -u | while read -r id; do
[ "$id" = "$a" ] || [ "$id" = "$b" ] || docker rmi "$id" >/dev/null 2>&1 || true
done
}
aufraeumen espocrm "$NACHHER_ESPO_ID" "$VORHER_ESPO_ID"
aufraeumen mariadb "$NACHHER_DB_ID" "$VORHER_DB_ID"
echo "--- Images auf der VM (behalten: laufendes und vorheriges)"
docker image ls --format 'table {{.Repository}}\t{{.Tag}}\t{{.Size}}' 2>/dev/null \
| grep -E 'REPOSITORY|^espocrm|^mariadb' | sed 's/^/ /'
echo "--- Rueckweg"
lvs --noheadings -o lv_name,lv_attr,origin,data_percent "$VG/$SNAPSHOT" 2>/dev/null | sed 's/^ */ /'
lvs --noheadings -o lv_name,lv_attr,origin,lv_size,data_percent "$VG/$SNAPSHOT" 2>/dev/null | sed 's/^ */ /'
echo "--- Naechster Schritt von Hand"
echo "Instanz pruefen (Anmeldung, ein Datensatz, E-Mail, WebSocket). Erst danach ESPO-11 ausfuehren,"
echo "das den Snapshot verwirft. Solange er besteht, kostet jeder Schreibvorgang zusaetzliche Zeit,"

View File

@ -14,6 +14,25 @@ SNAPSHOT=srv-vor-update
COMPOSE=/srv/espo/docker-compose.yml
WARTE_MAX=900
# Wartet, bis alle vier Container "healthy" melden - "starting" ist keine Aussage.
alle_gesund() {
local c
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] || return 1
done
return 0
}
# Nennt die Container, die noch nicht gesund sind - fuer die Fehlermeldung.
nicht_gesund() {
local c z=""
for c in espocrm-db espocrm espocrm-daemon espocrm-websocket; do
[ "$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null)" = "healthy" ] \
|| z="$z $c=$(docker inspect -f '{{.State.Health.Status}}' "$c" 2>/dev/null || echo fehlt)"
done
printf '%s' "${z# }"
}
fehler() { echo "FEHLER: $*"; echo "ESPO12_ERGEBNIS: FEHLER"; exit 1; }
# Bringt den Dienst wieder hoch, wenn der Rueckweg abgebrochen wird - eine stehende Instanz
@ -79,11 +98,10 @@ START_AUSGABE="$(docker compose -f "$COMPOSE" up -d --quiet-pull 2>&1)" || {
# 7. Auf die Anwendung warten.
ENDE=$(( SECONDS + WARTE_MAX ))
while [ "$SECONDS" -lt "$ENDE" ]; do
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] && break
alle_gesund && break
sleep 10
done
[ "$(docker inspect -f '{{.State.Health.Status}}' espocrm 2>/dev/null)" = "healthy" ] \
|| fehler "espocrm nach ${WARTE_MAX}s nicht gesund - 'docker logs espocrm' ansehen"
alle_gesund || fehler "nach ${WARTE_MAX}s nicht alle Container gesund: $(nicht_gesund) - 'docker logs <name>' ansehen"
# 8. Ergebnis zeigen.
echo "--- Container"