feat(docker): Implemented a robust Bash utility for managing Docker bridge networks.

Key improvements and features:
- Automated IPAM: Scans for available /24 subnets within a defined BASE_NET range.
- Native OS Integration: Forces static bridge names using 'com.docker.network.bridge.name' for easier netfilter/iptables rules.
- Infrastructure Persistence: Tracks managed networks via a flat-file database (NET_FILE).
- Safety Mechanisms:
    - Enforced 15-char limit for Linux interface compatibility.
    - ShellCheck-validated code with 'set -euo pipefail' (Strict Mode).
    - Interactive confirmation for bulk decommissioning.
- Comprehensive Dashboard: Provides 'info' command for real-time network status and IP range overview.
This commit is contained in:
2026-04-16 17:35:32 +03:00
parent e3cba45215
commit 7ac0ad8922
7 changed files with 329 additions and 4 deletions
+14 -4
View File
@@ -4,13 +4,14 @@ A collection of battle-tested scripts and utilities for system administrators, D
---
### 📂 Navigation Table
## 📂 Navigation Table
This toolbox contains a `mix` of `built-in scripts` and `links to my standalone specialized projects` for easier navigation.
| OS | Stack | Utility Name | Description | Status |
| :--- | :--- | :--- | :--- | :--- |
| ![Windows](https://img.shields.io/badge/Windows-0078D6?style=flat-square&logo=windows&logoColor=white) | ![Batch](https://img.shields.io/badge/-Batch-4D4D4D?style=flat-square) | [AnyDesk Reset](./tools/windows/apps-reset/anydesk-id-reseter.bat) | Terminate [AnyDesk](https://anydesk.com/en) & clear config files (`ID reset`) | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [Juniper Network Toggle](./tools/linux/juniper-ctrl/juniper-net-toggle/juniper-net-toggle.sh) | Remote toggle for [Juniper](https://www.juniper.net/) interfaces & static routes | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [Directory Comparator](./tools/linux/compare-dirs/compare-dirs.sh) | Recursive file comparison between two directories with detailed diff logging | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Windows](https://img.shields.io/badge/Windows-0078D6?style=flat-square&logo=windows&logoColor=white) | ![Batch](https://img.shields.io/badge/-Batch-4D4D4D?style=flat-square) | [AnyDesk Reset](./tools/windows/apps-reset) | Terminate [AnyDesk](https://anydesk.com/en) & clear config files (`ID reset`) | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [Docker Network Manager](./tools/linux/docker-ce/network-manager) | Auto-IPAM & static bridge naming for `Docker` bridge networks | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [Juniper Network Toggle](./tools/linux/juniper-ctrl/juniper-net-toggle) | Remote toggle for [Juniper](https://www.juniper.net/) interfaces & static routes | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [Directory Comparator](./tools/linux/compare-dirs) | Recursive file comparison between two directories with detailed diff logging | ✅ Stable <br> 🧰&nbsp;Built-in&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [PSQL NFS Backup](https://github.com/andsyrovatko/s4k-psql-db-backuper) | Automation for [PostgreSQL](https://www.postgresql.org/) dumps with [NFS](https://en.wikipedia.org/wiki/Network_File_System) & [Telegram](https://telegram.org/) | ✅ Stable <br> 📦&nbsp;Standalone&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [PVE Rsync Backup Pro](https://github.com/andsyrovatko/s4k-pve-rsync-backup) | Surgical [Proxmox VE](https://www.proxmox.com/) VM backups with log-parsed paths & auto-cleanup | ✅ Stable <br> 📦&nbsp;Standalone&nbsp; |
| ![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black) | ![Bash](https://img.shields.io/badge/-Bash-4EAA25?style=flat-square) | [Whois Infrastructure Automator (for ISPs)](https://github.com/andsyrovatko/s4k-billing-whois-automator) | Automation for Whois DB update by billing system | ✅ Stable <br> 📦&nbsp;Standalone&nbsp; |
@@ -21,6 +22,15 @@ This toolbox contains a `mix` of `built-in scripts` and `links to my standalone
---
## ⭐ Featured Tools
### 🐳 Docker Network Manager
A surgical tool for managing Docker infrastructure. It eliminates the "random bridge names" problem by forcing static names at the OS level, making it perfect for custom firewall rules and network monitoring.
- **Auto-IPAM**: Scans and assigns free subnets.
- **Native Naming**: Direct mapping between Docker names and Linux interfaces.
---
### ⚠️ Disclaimer
> **Use at your own risk!** These scripts are designed for administrative tasks and may perform destructive actions (like killing processes or deleting config files). The author is not responsible for any data loss or system instability. Always test in a sandbox environment first.
@@ -0,0 +1,91 @@
# 🐳 Docker Network Manager
A lightweight, production-ready Bash utility to manage external Docker bridge networks with automatic IPAM (IP Address Management). It ensures your network configurations are persistent, documented, and free from subnet overlaps.
---
## 🚀 Key Features
* **Smart Subnet Allocation:** Automatically finds the next available /24 block within your specified range (e.g., `172.30.x.x`).
* **Infrastructure as Code (Lite):** Keep your network names in a simple text file; the script handles the rest.
* **Safe Operations:**
* Interactive confirmation for bulk deletions.
* ShellCheck-validated code (Strict Mode: `set -euo pipefail`).
* Non-interactive mode support (via `FORCE=true`).
* **Status Dashboard:** Instant overview of which tracked networks are `ONLINE` or `OFFLINE`.
## 🛠 Installation & Setup
1. **Clone the repo** (or add the code to your admin toolbox).
2. Create the config file:
```bash
cp docker-network-manager.conf.example docker-network-manager.conf
#OR
cat <<EOF > docker-network-manager.conf
NET_FILE="./dnm-networks.txt"
LOG_FILE="./dnm-networks.log"
BASE_NET="172.30"
START_OCTET=0
END_OCTET=255
EOF
```
3. **Make script executable:**
```bash
chmod +x docker-network-manager.sh
```
## 📖 Usage Examples
1. **Check current status**
```bash
./docker-network-manager.sh info
```
Example:\
![Dashboard Preview](assets/info-screen.png)
2. **Provision networks**
* **From file:** Add network names to dnm-networks.txt and run:
```bash
./docker-network-manager.sh create
```
* **Single network:**
```bash
./docker-network-manager.sh create br-project-alpha
```
3. **Decommission networks**
* **Remove and cleanup:**
```bash
./docker-network-manager.sh delete br-project-alpha
```
* **Purge all (from file):***
```bash
./docker-network-manager.sh delete
```
### ⚠️ IMPORTANT
> **Interface Name Limit**: Linux has a **15-character** limit for network interface names. Ensure your Docker network names stay within this limit to maintain consistent bridge naming.
## 🧩 Native OS Integration
Unlike standard Docker networks that create cryptic interface names (e.g., br-837d9f...), this manager assigns the actual network name to the Linux bridge interface.
This allows you to:
* Monitor traffic per-network using standard tools (tcpdump -i br-test1).
* Create persistent firewall rules (IPTables/NFTables) targeting specific bridges.
* Easily identify networks in ip addr or ifconfig output.\
Example:\
![Dashboard Preview](assets/ip-a-test.png)
## 📊 Summary Table of Commands
| Command | Short | Argument | Description |
| :--- | :--- | :--- | :--- |
| `create` | `c` | [name] | Provisions network(s) and updates config file. |
| `delete` | `d` | [name] | Removes network(s) from Docker and config file. |
| `info` | `i` | - | Displays dashboard with IP ranges and statuses. |
## ⚙️ Configuration Variables
| Variable | Default | Description |
| :--- | :--- | :--- |
| `BASE_NET` | `172.30` | The first two octets of your managed pool. |
| `START_OCTET` | `0` | Starting range for the 3rd octet. |
| `END_OCTET` | `255` | Ending range for the 3rd octet. |
| `NET_FILE` | `./dnm-networks.txt` | File where network names are stored. |
---
### ⚖️ License
MIT [LICENSE](https://github.com/andsyrovatko/s4k-admin-toolbox/blob/main/LICENSE). Free to use and modify.
Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

@@ -0,0 +1,5 @@
# br-test1
#br-test2
br-test3
br-longname_not_allowed-test4
br-test5
@@ -0,0 +1,6 @@
# MAIN VARIABLES
NET_FILE="./dnm-networks.txt"
LOG_FILE="./dnm-networks.log"
BASE_NET="172.30"
START_OCTET=0
END_OCTET=255
@@ -0,0 +1,213 @@
#!/usr/bin/env bash
# =============================================================================
# Script Name : docker-network-manager.sh
# Description : Manage Docker external networks with automatic subnet allocation and tracking.
# Usage: : ./docker-network-manager.sh <COMMAND> [ARGUMENTS]
# Commands:
# create [NAME] - Create a specific network by name or all networks from file if NO NAME provided.
# delete [NAME] - Delete a specific network by name or all networks from file if NO NAME provided.
# info - Show current status and configuration.
# For details - see README.md
# Author : syr4ok (Andrii Syrovatko)
# Version : 1.1.0
# =============================================================================
# --- STRICT MODE ---
set -euo pipefail
# Configuration Loader
CONFIG_FILE="$(dirname "$0")/docker-network-manager.conf"
if [[ -f "$CONFIG_FILE" ]]; then
# shellcheck source=/dev/null
source "$CONFIG_FILE"
else
echo "[Error]: Configuration file not found. Create ip_manager.conf from example."
exit 1
fi
touch "$NET_FILE"
log() {
local level="$1"; shift
printf '%s [%s] %s\n' "$(date -Is)" "$level" "$*" | tee -a "$LOG_FILE"
}
confirm_action() {
[[ "${FORCE:-false}" == "true" ]] && return 0
read -rp "Are you sure you want to delete ALL networks from $NET_FILE? (y/N): " response
case "$response" in
[yY][eE][sS]|[yY]) return 0 ;;
*) log INFO "Operation cancelled by user"; exit 0 ;;
esac
}
# Network check
network_exists() {
docker network ls --format '{{.Name}}' | grep -Fxq "$1"
}
used_subnets() {
local escaped_base="${BASE_NET//./\\.}"
# Get all subnets from existing Docker networks and filter those that match our base pattern
docker network ls -q | xargs -r docker network inspect 2>/dev/null \
| grep -oP '"Subnet":\s*"\K'"${escaped_base}"'\.[0-9]+\.0/24' || echo ""
}
next_free_subnet() {
local used="$1"
for i in $(seq "$START_OCTET" "$END_OCTET"); do
local subnet="${BASE_NET}.${i}.0/24"
if ! grep -q "$subnet" <<<"$used"; then
echo "$subnet"
return
fi
done
log ERROR "no free /24 subnet found in ${BASE_NET}.x.x"
exit 1
}
name_length_check() {
local name="$1"
if [[ ${#name} -gt 15 ]]; then
log WARN "Network name '$name' is too long for a Linux bridge (max 15 chars). It might be truncated."
return 1
fi
return 0
}
provision_single() {
local name="$1"
if ! name_length_check "$name"; then
return 1
fi
if network_exists "$name"; then
log INFO "network already exists name=$name"
return
fi
local used
local subnet
used="$(used_subnets)"
subnet="$(next_free_subnet "$used")"
local gw="${subnet%0/24}1"
log INFO "creating network name=$name subnet=$subnet gateway=$gw"
docker network create --driver bridge --subnet "$subnet" --gateway "$gw" \
--opt com.docker.network.bridge.name="$name" "$name" >/dev/null
if ! grep -Fxq "$name" "$NET_FILE"; then
echo "$name" >> "$NET_FILE"
log INFO "network name=$name added to $NET_FILE"
sed -i '/^$/d' "$NET_FILE"
fi
}
provision_from_file() {
[[ ! -s "$NET_FILE" ]] && { log WARN "NET_FILE is empty"; return; }
log INFO "starting mass provisioning from $NET_FILE"
while read -u 3 -r line; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
provision_single "$line" || true
done 3< "$NET_FILE"
}
delete_network() {
local name="$1"
if network_exists "$name"; then
log INFO "deleting network name=$name"
docker network rm "$name" >/dev/null
log INFO "network name=$name deleted from docker"
else
log WARN "network not found in docker name=$name — cleanup config anyway"
fi
# Remove from NET_FILE if exists
if grep -Fxq "$name" "$NET_FILE"; then
sed -i "/^$name$/d" "$NET_FILE"
log INFO "network name=$name removed from $NET_FILE"
else
log INFO "network name=$name not found in $NET_FILE, no cleanup needed"
fi
}
delete_all_from_file() {
log INFO "deleting all networks listed in $NET_FILE"
while read -u 3 -r line; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
delete_network "$line"
done 3< "$NET_FILE"
}
show_info() {
local tracked_count
tracked_count=$(grep -cE '^\s*[^#]' "$NET_FILE" || true)
echo "--- Docker Network Manager v1.1.0 ---"
echo "Configured Base : ${BASE_NET}.0.0/16 (Range: .${START_OCTET}.x to .${END_OCTET}.x)"
echo "Config File : $(basename "$NET_FILE")"
echo "Log File : $(basename "$LOG_FILE")"
echo "Tracked Networks: $tracked_count"
echo -e "\n[Current Status]"
if [[ "$tracked_count" -gt 0 ]]; then
printf "%-20s %-15s %-10s\n" "NETWORK NAME" "IP RANGE" "STATUS"
echo "--------------------------------------------------------"
while read -u 3 -r line; do
[[ -z "$line" || "$line" =~ ^# ]] && continue
local status="OFFLINE"
local subnet="N/A"
if network_exists "$line"; then
status="ONLINE"
subnet=$(docker network inspect "$line" --format '{{(index .IPAM.Config 0).Subnet}}' 2>/dev/null || echo "error")
fi
printf "%-20s %-15s %-10s\n" "$line" "$subnet" "$status"
done 3< "$NET_FILE"
else
echo "No networks tracked in $NET_FILE"
fi
echo -e "\n[Usage]"
echo " $0 create (c) [name] - Create single network and add to file"
echo " $0 create (c) - Create all networks from file"
echo " $0 delete (d) [name] - Remove network and clean file"
echo " $0 delete (d) - Remove all networks from file"
}
case "${1:-info}" in
[Cc][Rr][Ee][Aa][Tt][Ee]|[Cc])
if [[ ${2:-} ]]; then
provision_single "$2"
else
provision_from_file
fi
;;
[Dd][Ee][Ll][Ee][Tt][Ee]|[Dd])
if [[ ${2:-} ]]; then
delete_network "$2"
else
count=$( (grep -vE '^\s*(#|$)' "$NET_FILE" || true) | wc -l | xargs)
if (( count == 0 )); then
log INFO "Nothing to delete. $NET_FILE is empty or contains only comments."
exit 0
fi
confirm_action
delete_all_from_file
fi
;;
[Ii][Nn][Ff][Oo]|[Ii])
show_info
;;
*)
log ERROR "Unknown command: $1"
show_info
exit 1
;;
esac
exit 0