554 lines
17 KiB
Bash
554 lines
17 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
# Script Name: dockernet-inspector.v1.sh
|
|
# Beschreibung: Dockernet Inspector - Verwaltet und inspiziert Docker-Netzwerke
|
|
# - Alle Netzwerke auflisten
|
|
# - Details zu einem spezifischen Docker-Netzwerk anzeigen
|
|
# - Belegte IPs je Netzwerk und netzwerkuebergreifend ausgeben
|
|
# - Ungenutzte Netzwerke (ohne Container) anzeigen
|
|
# - Netzwerke interaktiv auswaehlen und loeschen
|
|
# - Alle ungenutzten, loeschbaren Netzwerke auf einmal entfernen
|
|
# Verwendung: bash ./dockernet-inspector.v1.sh [BEFEHL] [OPTIONS]
|
|
# Befehle:
|
|
# networks - Alle Docker Netzwerke auflisten
|
|
# inspect - Details zu einem Netzwerk anzeigen (Standard)
|
|
# ips - Belegte IPs in einem Netzwerk
|
|
# ips-all - Belegte IPs in allen Netzwerken
|
|
# unused-networks - Netzwerke ohne verbundene Container
|
|
# delete-networks - Netzwerke interaktiv auswaehlen und loeschen
|
|
# delete-unused-networks - Alle ungenutzten, loeschbaren Netzwerke loeschen
|
|
# help, -h, --help - Diese Hilfe anzeigen
|
|
# Autor: Patrick Asmus
|
|
# Web: https://www.cleveradmin.de
|
|
# Git-Reposit.: https://git.techniverse.net/scriptos/dockernet-inspector.git
|
|
# Version: 1.7.0
|
|
# Datum: 08.05.2026
|
|
# Modifikation: Sammelloeschung fuer ungenutzte Docker-Netzwerke hinzugefuegt
|
|
#####################################################
|
|
|
|
set -uo pipefail
|
|
|
|
TABLE_LINE_WIDTH=80
|
|
INTERACTIVE_MODE=false
|
|
|
|
print_rule() {
|
|
local char="$1"
|
|
printf '%*s\n' "$TABLE_LINE_WIDTH" '' | tr ' ' "$char"
|
|
}
|
|
|
|
print_table_title() {
|
|
local title="$1"
|
|
echo "$title"
|
|
print_rule "="
|
|
}
|
|
|
|
is_protected_network() {
|
|
local net="$1"
|
|
[[ "$net" == "bridge" || "$net" == "host" || "$net" == "none" || "$net" == "ingress" || "$net" == "docker_gwbridge" ]]
|
|
}
|
|
|
|
# Hilfe-Funktion
|
|
show_help() {
|
|
cat <<HELP
|
|
Dockernet Inspector v1.7.0 - Docker Netzwerk Verwaltungstool
|
|
|
|
VERWENDUNG:
|
|
$0 - Interaktiver Modus (Menü)
|
|
$0 networks - Alle Docker Netzwerke auflisten
|
|
$0 inspect <netzwerk> - Details zu einem Netzwerk anzeigen
|
|
$0 ips <netzwerk> - Belegte IPs in einem Netzwerk anzeigen
|
|
$0 ips-all - Belegte IPs in allen Netzwerken anzeigen
|
|
$0 unused-networks - Ungenutzte Netzwerke (ohne Container) anzeigen
|
|
$0 delete-networks - Netzwerke interaktiv auswaehlen und loeschen
|
|
$0 delete-unused-networks - Alle ungenutzten, loeschbaren Netzwerke loeschen
|
|
$0 <netzwerk> - Alias fuer 'inspect <netzwerk>'
|
|
$0 help - Diese Hilfe anzeigen
|
|
|
|
BEFEHLE:
|
|
networks Listet alle verfuegbaren Docker Netzwerke auf
|
|
ips <netzwerk> Zeigt Containername und IPv4-Adresse im angegebenen Netzwerk
|
|
ips-all Zeigt alle belegten IPv4-Adressen in allen Netzwerken (aufsteigend)
|
|
unused-networks Zeigt alle Docker Netzwerke ohne verbundene Container
|
|
delete-networks Netzwerk per Nummer auswaehlen und loeschen;
|
|
Docker-Standard- und Systemnetzwerke sind geschuetzt
|
|
delete-unused-networks Loescht alle ungenutzten Docker Netzwerke nach Bestaetigung;
|
|
bridge, host, none, ingress und docker_gwbridge sind geschuetzt
|
|
inspect <netzwerk> Zeigt detaillierte Informationen zu einem Netzwerk:
|
|
- Netzwerktyp (Driver)
|
|
- Bridge-Interface
|
|
- Subnetz und Gateway
|
|
- Interface-Status
|
|
- Netzwerk-Statistiken (RX/TX bytes und packets)
|
|
help Zeigt diese Hilfe an
|
|
|
|
BEISPIELE:
|
|
$0 networks
|
|
$0 ips mynetwork
|
|
$0 ips-all
|
|
$0 unused-networks
|
|
$0 delete-networks
|
|
$0 delete-unused-networks
|
|
$0 inspect mynetwork
|
|
$0 mynetwork
|
|
$0 -h
|
|
|
|
HELP
|
|
}
|
|
|
|
# Funktion zum Auflisten aller Docker Netzwerke
|
|
list_networks() {
|
|
local table_output header
|
|
|
|
print_table_title "Verfuegbare Docker Netzwerke:"
|
|
table_output="$(docker network ls --format "table {{.ID}}\t{{.Name}}\t{{.Driver}}\t{{.Scope}}")" || {
|
|
echo "Fehler: Docker Netzwerke konnten nicht abgerufen werden."
|
|
exit 2
|
|
}
|
|
|
|
header="$(printf "%s\n" "$table_output" | head -n 1)"
|
|
printf "%s\n" "$header"
|
|
print_rule "-"
|
|
printf "%s\n" "$table_output" | tail -n +2
|
|
}
|
|
|
|
print_dynamic_table() {
|
|
local data="$1"
|
|
local formatted
|
|
local header
|
|
|
|
if command -v column >/dev/null 2>&1; then
|
|
formatted="$(printf "%b" "$data" | column -t -s $'\t')"
|
|
else
|
|
formatted="$(printf "%b" "$data")"
|
|
fi
|
|
|
|
header="$(printf "%s\n" "$formatted" | head -n 1)"
|
|
printf "%s\n" "$header"
|
|
print_rule "-"
|
|
printf "%s\n" "$formatted" | tail -n +2
|
|
}
|
|
|
|
list_ips_in_network() {
|
|
local net="$1"
|
|
local rows table_data
|
|
|
|
rows="$(docker network inspect "$net" --format '{{range $id, $c := .Containers}}{{println $c.Name $c.IPv4Address}}{{end}}' 2>/dev/null || true)"
|
|
[[ -z "$rows" ]] && {
|
|
echo "Keine Container mit IPv4-Adresse im Netzwerk '$net' gefunden."
|
|
exit 0
|
|
}
|
|
|
|
print_table_title "Belegte IP-Adressen im Netzwerk '$net':"
|
|
table_data=$'CONTAINER\tIP\n'
|
|
while read -r cname ipcidr; do
|
|
[[ -z "${cname:-}" || -z "${ipcidr:-}" ]] && continue
|
|
table_data+="${cname}"$'\t'"${ipcidr%%/*}"$'\n'
|
|
done < <(printf "%s\n" "$rows" | sort -k2,2V)
|
|
print_dynamic_table "$table_data"
|
|
}
|
|
|
|
list_ips_all_networks() {
|
|
local nets rows table_data
|
|
rows=""
|
|
|
|
nets="$(docker network ls --format '{{.Name}}' 2>/dev/null || true)"
|
|
[[ -z "$nets" ]] && {
|
|
echo "Fehler: Docker Netzwerke konnten nicht abgerufen werden."
|
|
exit 2
|
|
}
|
|
|
|
while read -r net; do
|
|
[[ -z "${net:-}" ]] && continue
|
|
while read -r cname ipcidr; do
|
|
[[ -z "${cname:-}" || -z "${ipcidr:-}" ]] && continue
|
|
rows+="${net}"$'\t'"${cname}"$'\t'"${ipcidr%%/*}"$'\n'
|
|
done < <(docker network inspect "$net" --format '{{range $id, $c := .Containers}}{{println $c.Name $c.IPv4Address}}{{end}}' 2>/dev/null || true)
|
|
done < <(printf "%s\n" "$nets")
|
|
|
|
[[ -z "$rows" ]] && {
|
|
echo "Keine belegten IPv4-Adressen in Docker Netzwerken gefunden."
|
|
exit 0
|
|
}
|
|
|
|
print_table_title "Belegte IP-Adressen in allen Netzwerken (aufsteigend):"
|
|
table_data=$'NETZWERK\tCONTAINER\tIP\n'
|
|
while IFS=$'\t' read -r net cname ip; do
|
|
[[ -z "${net:-}" || -z "${cname:-}" || -z "${ip:-}" ]] && continue
|
|
table_data+="${net}"$'\t'"${cname}"$'\t'"${ip}"$'\n'
|
|
done < <(printf "%s" "$rows" | sort -t $'\t' -k3,3V -k1,1 -k2,2)
|
|
print_dynamic_table "$table_data"
|
|
}
|
|
|
|
list_unused_networks() {
|
|
local nets net containers table_data has_unused
|
|
|
|
nets="$(docker network ls --format '{{.Name}}' 2>/dev/null || true)"
|
|
[[ -z "$nets" ]] && {
|
|
echo "Fehler: Docker Netzwerke konnten nicht abgerufen werden."
|
|
exit 2
|
|
}
|
|
|
|
table_data=$'NAME\tDRIVER\tSCOPE\n'
|
|
has_unused=false
|
|
|
|
while read -r net; do
|
|
[[ -z "${net:-}" ]] && continue
|
|
containers="$(docker network inspect "$net" --format '{{len .Containers}}' 2>/dev/null || true)"
|
|
if [[ "${containers:-0}" -eq 0 ]]; then
|
|
local driver scope
|
|
driver="$(docker network inspect "$net" --format '{{.Driver}}' 2>/dev/null || true)"
|
|
scope="$(docker network inspect "$net" --format '{{.Scope}}' 2>/dev/null || true)"
|
|
table_data+="${net}"$'\t'"${driver}"$'\t'"${scope}"$'\n'
|
|
has_unused=true
|
|
fi
|
|
done < <(printf "%s\n" "$nets")
|
|
|
|
if ! $has_unused; then
|
|
echo "Alle Docker Netzwerke haben mindestens einen verbundenen Container."
|
|
return 0
|
|
fi
|
|
|
|
print_table_title "Ungenutzte Docker Netzwerke (keine Container verbunden):"
|
|
print_dynamic_table "$table_data"
|
|
}
|
|
|
|
delete_networks() {
|
|
local nets
|
|
nets="$(docker network ls --format '{{.Name}}' 2>/dev/null || true)"
|
|
if [[ -z "$nets" ]]; then
|
|
echo "Fehler: Keine Docker Netzwerke gefunden."
|
|
return 1
|
|
fi
|
|
|
|
local -a net_array
|
|
mapfile -t net_array <<< "$nets"
|
|
|
|
echo ""
|
|
echo "Verfuegbare Docker Netzwerke:"
|
|
echo ""
|
|
local i
|
|
for ((i=0; i<${#net_array[@]}; i++)); do
|
|
local suffix=""
|
|
is_protected_network "${net_array[$i]}" && suffix=" (geschuetzt - nicht loeschbar)"
|
|
printf " %d. %s%s\n" "$((i+1))" "${net_array[$i]}" "$suffix"
|
|
done
|
|
echo ""
|
|
read -rp "Nummer des Netzwerks eingeben (0 = Abbrechen): " choice
|
|
|
|
if [[ "$choice" == "0" || -z "$choice" ]]; then
|
|
echo "Abgebrochen."
|
|
return 0
|
|
fi
|
|
|
|
if ! [[ "$choice" =~ ^[0-9]+$ ]] || ((choice < 1 || choice > ${#net_array[@]})); then
|
|
echo "Fehler: Ungueltige Nummer."
|
|
return 1
|
|
fi
|
|
|
|
local selected_net="${net_array[$((choice-1))]}"
|
|
if is_protected_network "$selected_net"; then
|
|
echo "FEHLER: '$selected_net' ist ein geschuetztes Docker-Netzwerk und kann nicht geloescht werden."
|
|
return 1
|
|
fi
|
|
echo ""
|
|
read -rp "Netzwerk '$selected_net' wirklich loeschen? [j/N]: " confirm
|
|
if [[ "$confirm" != "j" && "$confirm" != "J" ]]; then
|
|
echo "Abgebrochen."
|
|
return 0
|
|
fi
|
|
|
|
echo ""
|
|
if docker network rm "$selected_net" 2>/dev/null; then
|
|
echo "OK: Netzwerk '$selected_net' erfolgreich geloescht."
|
|
return 0
|
|
else
|
|
echo "FEHLER: Netzwerk '$selected_net' konnte nicht geloescht werden (wird moeglicherweise noch genutzt)."
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
delete_unused_networks() {
|
|
local nets net containers driver scope
|
|
local -a delete_candidates
|
|
local -a protected_unused
|
|
|
|
nets="$(docker network ls --format '{{.Name}}' 2>/dev/null || true)"
|
|
if [[ -z "$nets" ]]; then
|
|
echo "Fehler: Keine Docker Netzwerke gefunden."
|
|
return 1
|
|
fi
|
|
|
|
delete_candidates=()
|
|
protected_unused=()
|
|
|
|
while read -r net; do
|
|
[[ -z "${net:-}" ]] && continue
|
|
containers="$(docker network inspect "$net" --format '{{len .Containers}}' 2>/dev/null || true)"
|
|
if [[ "${containers:-0}" -eq 0 ]]; then
|
|
if is_protected_network "$net"; then
|
|
protected_unused+=("$net")
|
|
else
|
|
delete_candidates+=("$net")
|
|
fi
|
|
fi
|
|
done < <(printf "%s\n" "$nets")
|
|
|
|
if ((${#delete_candidates[@]} == 0)); then
|
|
echo "Keine ungenutzten, loeschbaren Docker Netzwerke gefunden."
|
|
if ((${#protected_unused[@]} > 0)); then
|
|
echo "Geschuetzte ungenutzte Netzwerke werden uebersprungen: ${protected_unused[*]}"
|
|
fi
|
|
return 0
|
|
fi
|
|
|
|
print_table_title "Ungenutzte Docker Netzwerke, die geloescht werden koennen:"
|
|
local table_data
|
|
table_data=$'NAME\tDRIVER\tSCOPE\n'
|
|
for net in "${delete_candidates[@]}"; do
|
|
driver="$(docker network inspect "$net" --format '{{.Driver}}' 2>/dev/null || true)"
|
|
scope="$(docker network inspect "$net" --format '{{.Scope}}' 2>/dev/null || true)"
|
|
table_data+="${net}"$'\t'"${driver}"$'\t'"${scope}"$'\n'
|
|
done
|
|
print_dynamic_table "$table_data"
|
|
|
|
if ((${#protected_unused[@]} > 0)); then
|
|
echo ""
|
|
echo "Geschuetzte ungenutzte Netzwerke werden nicht geloescht: ${protected_unused[*]}"
|
|
fi
|
|
|
|
echo ""
|
|
read -rp "Alle oben aufgefuehrten ungenutzten Netzwerke wirklich loeschen? [j/N]: " confirm
|
|
if [[ "$confirm" != "j" && "$confirm" != "J" ]]; then
|
|
echo "Abgebrochen."
|
|
return 0
|
|
fi
|
|
|
|
local success_count=0
|
|
local fail_count=0
|
|
echo ""
|
|
for net in "${delete_candidates[@]}"; do
|
|
if is_protected_network "$net"; then
|
|
echo "SKIP: Netzwerk '$net' ist geschuetzt."
|
|
continue
|
|
fi
|
|
|
|
if docker network rm "$net" >/dev/null 2>&1; then
|
|
echo "OK: Netzwerk '$net' erfolgreich geloescht."
|
|
((success_count++))
|
|
else
|
|
echo "FEHLER: Netzwerk '$net' konnte nicht geloescht werden (wird moeglicherweise wieder genutzt)."
|
|
((fail_count++))
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo "Ergebnis: $success_count geloescht, $fail_count fehlgeschlagen."
|
|
((fail_count == 0))
|
|
}
|
|
|
|
# Interaktive Menü-Funktion
|
|
interactive_menu() {
|
|
while true; do
|
|
echo ""
|
|
print_rule "="
|
|
echo "Dockernet Inspector - Interaktives Menü"
|
|
print_rule "="
|
|
echo ""
|
|
echo "1. Alle Netzwerke auflisten"
|
|
echo "2. Detaillierte Infos zu einem Netzwerk"
|
|
echo "3. IPs eines Netzwerks anzeigen"
|
|
echo "4. Alle belegten IPs anzeigen"
|
|
echo "5. Ungenutzte Netzwerke anzeigen"
|
|
echo "6. Netzwerke loeschen"
|
|
echo "7. Alle ungenutzten Netzwerke loeschen"
|
|
echo "0. Beenden"
|
|
echo ""
|
|
read -rp "Bitte waehlen Sie eine Option (0-7): " choice
|
|
echo ""
|
|
|
|
case "$choice" in
|
|
1)
|
|
list_networks
|
|
;;
|
|
2)
|
|
if select_and_inspect_network; then
|
|
:
|
|
fi
|
|
;;
|
|
3)
|
|
nets="$(docker network ls --format '{{.Name}}' 2>/dev/null || true)"
|
|
if [[ -z "$nets" ]]; then
|
|
echo "Fehler: Keine Docker Netzwerke gefunden."
|
|
continue
|
|
fi
|
|
|
|
echo "Verfuegbare Netzwerke:"
|
|
select net in $nets; do
|
|
if [[ -n "$net" ]]; then
|
|
list_ips_in_network "$net"
|
|
break
|
|
else
|
|
echo "Ungueltige Auswahl. Bitte versuchen Sie es erneut."
|
|
fi
|
|
done
|
|
;;
|
|
4)
|
|
list_ips_all_networks
|
|
;;
|
|
5)
|
|
list_unused_networks
|
|
;;
|
|
6)
|
|
delete_networks
|
|
;;
|
|
7)
|
|
delete_unused_networks
|
|
;;
|
|
0)
|
|
echo "Auf Wiedersehen!"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "FEHLER: Ungueltige Eingabe '$choice'. Bitte geben Sie eine Nummer zwischen 0 und 7 ein."
|
|
sleep 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Funktion zur Auswahl und Inspektion eines Netzwerks
|
|
select_and_inspect_network() {
|
|
local nets net
|
|
|
|
nets="$(docker network ls --format '{{.Name}}' 2>/dev/null || true)"
|
|
if [[ -z "$nets" ]]; then
|
|
echo "Fehler: Keine Docker Netzwerke gefunden."
|
|
return 1
|
|
fi
|
|
|
|
echo "Verfuegbare Netzwerke:"
|
|
select net in $nets; do
|
|
if [[ -n "$net" ]]; then
|
|
NET="$net"
|
|
inspect_network "$NET"
|
|
return 0
|
|
else
|
|
echo "Ungueltige Auswahl. Bitte versuchen Sie es erneut."
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Separate Funktion fuer Netzwerk-Inspektion
|
|
inspect_network() {
|
|
local NET="$1"
|
|
|
|
local DRIVER
|
|
DRIVER="$(docker network inspect "$NET" --format '{{.Driver}}' 2>/dev/null || true)"
|
|
[[ -z "$DRIVER" ]] && { echo "Fehler: Netzwerk '$NET' nicht gefunden."; return 2; }
|
|
|
|
echo ""
|
|
print_rule "="
|
|
echo "Detaillerte Informationen fuer Netzwerk: $NET"
|
|
print_rule "="
|
|
echo ""
|
|
|
|
# Sonderbehandlung fuer Docker-Standardnetzwerke
|
|
if [[ "$NET" == "none" || "$NET" == "host" || "$NET" == "bridge" ]]; then
|
|
cat <<OUT
|
|
Docker-Netzwerk : $NET
|
|
Driver : $DRIVER
|
|
Hinweis : Dies ist ein Docker-Standardnetzwerk und kann nicht geloescht werden.
|
|
OUT
|
|
echo ""
|
|
return 0
|
|
fi
|
|
|
|
# 1) Netzwerk-ID und Bridge-Name
|
|
local ID BR_RAW IF SUBNET GATEWAY state rxb txb rxp txp
|
|
ID="$(docker network inspect "$NET" --format '{{.Id}}' 2>/dev/null || true)"
|
|
|
|
BR_RAW="$(docker network inspect "$NET" --format '{{index .Options "com.docker.network.bridge.name"}}' 2>/dev/null || true)"
|
|
if [[ -z "$BR_RAW" || "$BR_RAW" == "<no value>" ]]; then
|
|
IF="br-${ID:0:12}"
|
|
else
|
|
IF="$BR_RAW"
|
|
fi
|
|
|
|
# 2) Subnet/Gateway
|
|
SUBNET="$(docker network inspect "$NET" --format '{{(index .IPAM.Config 0).Subnet}}' 2>/dev/null || true)"
|
|
GATEWAY="$(docker network inspect "$NET" --format '{{(index .IPAM.Config 0).Gateway}}' 2>/dev/null || true)"
|
|
|
|
# 3) Interface-Status & Stats
|
|
state="unknown"; rxb=0; txb=0; rxp=0; txp=0
|
|
if ip link show "$IF" &>/dev/null; then
|
|
state="$(cat /sys/class/net/"$IF"/operstate 2>/dev/null || echo unknown)"
|
|
rxb="$(cat /sys/class/net/"$IF"/statistics/rx_bytes 2>/dev/null || echo 0)"
|
|
txb="$(cat /sys/class/net/"$IF"/statistics/tx_bytes 2>/dev/null || echo 0)"
|
|
rxp="$(cat /sys/class/net/"$IF"/statistics/rx_packets 2>/dev/null || echo 0)"
|
|
txp="$(cat /sys/class/net/"$IF"/statistics/tx_packets 2>/dev/null || echo 0)"
|
|
fi
|
|
|
|
cat <<OUT
|
|
Docker-Netzwerk : $NET
|
|
Driver : $DRIVER
|
|
Bridge-Interface : $IF
|
|
Subnet/Gateway : ${SUBNET:--} / ${GATEWAY:--}
|
|
OperState : $state
|
|
RX bytes/packets : $rxb / $rxp
|
|
TX bytes/packets : $txb / $txp
|
|
OUT
|
|
echo ""
|
|
}
|
|
|
|
# Argument-Verarbeitung
|
|
COMMAND="${1:-}"
|
|
case "$COMMAND" in
|
|
networks)
|
|
list_networks
|
|
exit 0
|
|
;;
|
|
ips)
|
|
NET="${2:-}"
|
|
[[ -z "$NET" ]] && { echo "Fehler: Netzwerkname erforderlich. Verwendung: $0 ips <docker-network-name>"; exit 1; }
|
|
list_ips_in_network "$NET"
|
|
exit 0
|
|
;;
|
|
ips-all)
|
|
list_ips_all_networks
|
|
exit 0
|
|
;;
|
|
unused-networks)
|
|
list_unused_networks
|
|
exit 0
|
|
;;
|
|
delete-networks)
|
|
delete_networks
|
|
exit $?
|
|
;;
|
|
delete-unused-networks)
|
|
delete_unused_networks
|
|
exit $?
|
|
;;
|
|
help | -h | --help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
inspect)
|
|
NET="${2:-}"
|
|
[[ -z "$NET" ]] && { echo "Fehler: Netzwerkname erforderlich. Verwendung: $0 inspect <docker-network-name>"; exit 1; }
|
|
inspect_network "$NET"
|
|
exit 0
|
|
;;
|
|
"")
|
|
# Starte interaktiven Modus, wenn keine Argumente uebergeben wurden
|
|
interactive_menu
|
|
exit 0
|
|
;;
|
|
*)
|
|
# Kompatibilitaet: Wenn erstes Argument kein bekannter Befehl ist, behandle es als Netzwerkname
|
|
NET="$COMMAND"
|
|
inspect_network "$NET"
|
|
exit 0
|
|
;;
|
|
esac
|