.
This commit is contained in:
104
README.md
104
README.md
@@ -16,7 +16,7 @@ Aktualisiert komplette Docker-Compose Stacks strukturiert und kontrolliert
|
|||||||
Zeigt an, was passieren würde, ohne Änderungen durchzuführen
|
Zeigt an, was passieren würde, ohne Änderungen durchzuführen
|
||||||
- 📲 ntfy Benachrichtigungen
|
- 📲 ntfy Benachrichtigungen
|
||||||
Push-Notifications über ntfy bei Updates, Fehlern oder Status
|
Push-Notifications über ntfy bei Updates, Fehlern oder Status
|
||||||
- ⏭️ Exclude-Liste
|
- ⚙️ Service-Modi (per Label steuerbar)
|
||||||
Einzelne Container oder komplette Stacks gezielt vom Update ausschließen
|
Einzelne Container oder komplette Stacks gezielt vom Update ausschließen
|
||||||
- 🗑️ Prune Funktion
|
- 🗑️ Prune Funktion
|
||||||
Entfernt nicht mehr benötigte Images/Container automatisch
|
Entfernt nicht mehr benötigte Images/Container automatisch
|
||||||
@@ -65,6 +65,91 @@ Entfernt nicht mehr benötigte Images/Container automatisch
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## ⚙️ Service-Modi (per Label steuerbar)
|
||||||
|
|
||||||
|
Du kannst das Verhalten einzelner Services oder ganzer Stacks über Labels steuern:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
labels:
|
||||||
|
- composeupdater.mode=update
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📊 Übersicht
|
||||||
|
|
||||||
|
| Mode | Pull | Compare | Update | ntfy |
|
||||||
|
| ----------- | ---- | ------- | ------ | ---- |
|
||||||
|
| update | ✅ | ✅ | ✅ | ✅ |
|
||||||
|
| notify-only | ✅ | ✅ | ❌ | ✅ |
|
||||||
|
| ignore | ❌ | ❌ | ❌ | ❌ |
|
||||||
|
|
||||||
|
|
||||||
|
### 🧠 Erklärung der Modi
|
||||||
|
|
||||||
|
🔄 `update` (**Standard**)
|
||||||
|
- Images werden gepullt
|
||||||
|
- Lokales Image wird mit dem Container verglichen
|
||||||
|
- Bei Änderungen wird der Service bzw. Stack aktualisiert
|
||||||
|
- ntfy-Benachrichtigung wird gesendet
|
||||||
|
|
||||||
|
|
||||||
|
🔔 `notify-only`
|
||||||
|
- Image wird gepullt (für Vergleich notwendig)
|
||||||
|
- Es wird geprüft, ob ein Update verfügbar ist
|
||||||
|
- Kein Container-Update / kein Restart
|
||||||
|
- ntfy informiert über verfügbare Updates
|
||||||
|
|
||||||
|
|
||||||
|
🚫 `ignore`
|
||||||
|
- Service wird komplett ignoriert
|
||||||
|
- Kein Pull
|
||||||
|
- Kein Vergleich
|
||||||
|
- Kein Update
|
||||||
|
- Keine Benachrichtigung
|
||||||
|
|
||||||
|
|
||||||
|
### 🧩 Beispiele
|
||||||
|
|
||||||
|
#### Service ausschließen (komplett ignorieren)
|
||||||
|
|
||||||
|
```yml
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:15
|
||||||
|
labels:
|
||||||
|
- composeupdater.mode=ignore
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Nur Benachrichtigung, kein automatisches Update
|
||||||
|
|
||||||
|
```yml
|
||||||
|
services:
|
||||||
|
app:
|
||||||
|
image: myapp:latest
|
||||||
|
labels:
|
||||||
|
- composeupdater.mode=notify-only
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Explizit Standardverhalten setzen
|
||||||
|
|
||||||
|
```yml
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
image: nginx:latest
|
||||||
|
labels:
|
||||||
|
- composeupdater.mode=update
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 📦 Stack-Level Label (optional)
|
||||||
|
|
||||||
|
Du kannst das Verhalten auch für den gesamten Stack setzen:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
labels:
|
||||||
|
- composeupdater.mode=ignore
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🗑️ Prune / Cleanup
|
## 🗑️ Prune / Cleanup
|
||||||
|
|
||||||
Nach Abschluss der Updates kann optional ein Docker Cleanup durchgeführt werden.
|
Nach Abschluss der Updates kann optional ein Docker Cleanup durchgeführt werden.
|
||||||
@@ -161,23 +246,6 @@ REDEPLOY_WAIT_HEALTHY=true
|
|||||||
REDEPLOY_WAIT_HEALTHY_TIMEOUT=60
|
REDEPLOY_WAIT_HEALTHY_TIMEOUT=60
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
# EXCLUDES
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
|
|
||||||
# Stacks vom Update ausschließen [ Array ]
|
|
||||||
EXCLUDE_STACKS=(
|
|
||||||
"example_stack_1"
|
|
||||||
"example_stack_2"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Services vom Update ausschließen [ Array ]
|
|
||||||
EXCLUDE_SERVICES=(
|
|
||||||
"example_container_1"
|
|
||||||
"example_container_2"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
# ----------------------------------------------------------
|
||||||
# NTFY SETTINGS
|
# NTFY SETTINGS
|
||||||
# ----------------------------------------------------------
|
# ----------------------------------------------------------
|
||||||
|
|||||||
17
config.conf
17
config.conf
@@ -53,23 +53,6 @@ REDEPLOY_WAIT_HEALTHY=true
|
|||||||
REDEPLOY_WAIT_HEALTHY_TIMEOUT=60
|
REDEPLOY_WAIT_HEALTHY_TIMEOUT=60
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
# EXCLUDES
|
|
||||||
# ----------------------------------------------------------
|
|
||||||
|
|
||||||
# Stacks vom Update ausschließen [ Array ]
|
|
||||||
EXCLUDE_STACKS=(
|
|
||||||
"example_stack_1"
|
|
||||||
"example_stack_2"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Services vom Update ausschließen [ Array ]
|
|
||||||
EXCLUDE_SERVICES=(
|
|
||||||
"example_container_1"
|
|
||||||
"example_container_2"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# ----------------------------------------------------------
|
# ----------------------------------------------------------
|
||||||
# NTFY SETTINGS
|
# NTFY SETTINGS
|
||||||
# ----------------------------------------------------------
|
# ----------------------------------------------------------
|
||||||
|
|||||||
@@ -42,6 +42,30 @@ fi
|
|||||||
# Helper
|
# Helper
|
||||||
# =============================
|
# =============================
|
||||||
|
|
||||||
|
|
||||||
|
get_service_mode() {
|
||||||
|
local svc="$1"
|
||||||
|
|
||||||
|
echo "$compose_json" \
|
||||||
|
| jq -r --arg svc "$svc" '
|
||||||
|
.services[$svc].labels // []
|
||||||
|
| map(select(startswith("composeupdater.mode=")))
|
||||||
|
| .[0] // "composeupdater.mode=update"
|
||||||
|
| split("=")[1]
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get_stack_mode() {
|
||||||
|
echo "$compose_json" \
|
||||||
|
| jq -r '
|
||||||
|
.labels // []
|
||||||
|
| map(select(startswith("composeupdater.mode=")))
|
||||||
|
| .[0] // "composeupdater.mode=update"
|
||||||
|
| split("=")[1]
|
||||||
|
'
|
||||||
|
}
|
||||||
|
|
||||||
is_excluded() {
|
is_excluded() {
|
||||||
local svc="$1"
|
local svc="$1"
|
||||||
for ex in "${EXCLUDE_SERVICES[@]}"; do
|
for ex in "${EXCLUDE_SERVICES[@]}"; do
|
||||||
@@ -58,6 +82,21 @@ is_stack_excluded() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_label_excluded() {
|
||||||
|
local svc="$1"
|
||||||
|
|
||||||
|
echo "$compose_json" \
|
||||||
|
| jq -r --arg svc "$svc" '
|
||||||
|
.services[$svc].labels // {}
|
||||||
|
| (if type=="array"
|
||||||
|
then map(split("=") | {(.[0]): .[1]}) | add
|
||||||
|
else .
|
||||||
|
end)
|
||||||
|
| .["composeupdater.enable"] // empty
|
||||||
|
' \
|
||||||
|
| grep -qi "^false$"
|
||||||
|
}
|
||||||
|
|
||||||
get_image() {
|
get_image() {
|
||||||
local svc="$1"
|
local svc="$1"
|
||||||
|
|
||||||
@@ -241,7 +280,6 @@ stack_tree=()
|
|||||||
|
|
||||||
cd "$PATH_COMPOSE_DIR"
|
cd "$PATH_COMPOSE_DIR"
|
||||||
|
|
||||||
|
|
||||||
while IFS= read -r -d '' file; do
|
while IFS= read -r -d '' file; do
|
||||||
|
|
||||||
declare -A pulled_images
|
declare -A pulled_images
|
||||||
@@ -249,11 +287,6 @@ while IFS= read -r -d '' file; do
|
|||||||
dir=$(dirname "$file")
|
dir=$(dirname "$file")
|
||||||
stack=$(basename "$dir")
|
stack=$(basename "$dir")
|
||||||
|
|
||||||
if is_stack_excluded "$stack"; then
|
|
||||||
log INFO "→ Stack $stack übersprungen (excluded)"
|
|
||||||
continue
|
|
||||||
fi
|
|
||||||
|
|
||||||
log INFO ""
|
log INFO ""
|
||||||
log INFO "→ Prüfe Stack: $stack"
|
log INFO "→ Prüfe Stack: $stack"
|
||||||
|
|
||||||
@@ -263,6 +296,14 @@ while IFS= read -r -d '' file; do
|
|||||||
|
|
||||||
compose_json=$(docker compose config --format json)
|
compose_json=$(docker compose config --format json)
|
||||||
|
|
||||||
|
stack_mode=$(get_stack_mode)
|
||||||
|
|
||||||
|
if [ "$stack_mode" = "ignore" ]; then
|
||||||
|
log INFO "→ Stack $stack übersprungen (label=ignore)"
|
||||||
|
cd "$PATH_COMPOSE_DIR"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
mapfile -t services < <(docker compose config --services)
|
mapfile -t services < <(docker compose config --services)
|
||||||
total_services=${#services[@]}
|
total_services=${#services[@]}
|
||||||
current_index=0
|
current_index=0
|
||||||
@@ -280,7 +321,6 @@ while IFS= read -r -d '' file; do
|
|||||||
for svc in "${services[@]}"; do
|
for svc in "${services[@]}"; do
|
||||||
|
|
||||||
update_needed=false
|
update_needed=false
|
||||||
|
|
||||||
current_index=$((current_index + 1))
|
current_index=$((current_index + 1))
|
||||||
|
|
||||||
if [ "$current_index" -eq "$total_services" ]; then
|
if [ "$current_index" -eq "$total_services" ]; then
|
||||||
@@ -296,13 +336,48 @@ while IFS= read -r -d '' file; do
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if is_excluded "$svc"; then
|
mode=$(get_service_mode "$svc")
|
||||||
pull_with_retry "$image" || true
|
|
||||||
notify_excluded_updates+=("$stack/$svc")
|
case "$mode" in
|
||||||
log INFO " $prefix $svc (excluded)"
|
|
||||||
|
ignore)
|
||||||
|
log INFO " $prefix $svc (ignore)"
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
|
||||||
|
notify-only)
|
||||||
|
log INFO " $prefix $svc (notify-only)"
|
||||||
|
|
||||||
|
before_id=$(get_container_image_id "$svc")
|
||||||
|
|
||||||
|
# 👉 ohne Container kein Vergleich sinnvoll
|
||||||
|
if [ -z "$before_id" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "${pulled_images[$image]:-}" ]; then
|
||||||
|
pull_with_retry "$image" || true
|
||||||
|
pulled_images[$image]=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
after_id=$(get_local_image_id "$image")
|
||||||
|
|
||||||
|
if [ "$before_id" != "$after_id" ]; then
|
||||||
|
notify_excluded_updates+=("$stack/$svc")
|
||||||
|
fi
|
||||||
|
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
|
||||||
|
update)
|
||||||
|
# normal weiterlaufen lassen
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
log WARN " $prefix $svc (unbekannter mode: $mode → fallback=update)"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
log INFO " $prefix $svc ($image)"
|
log INFO " $prefix $svc ($image)"
|
||||||
|
|
||||||
before_id=$(get_container_image_id "$svc")
|
before_id=$(get_container_image_id "$svc")
|
||||||
@@ -314,7 +389,7 @@ while IFS= read -r -d '' file; do
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# =============================
|
# =============================
|
||||||
# Pull + Vergleich (NEU)
|
# Pull + Vergleich
|
||||||
# =============================
|
# =============================
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user