|
#!/bin/bash |
|
|
|
# Fallback defaults |
|
DEFAULT_RATE="35mbit" |
|
DEFAULT_BURST="16kb" |
|
DEFAULT_LATENCY="100ms" |
|
|
|
# Label Keys |
|
LABEL_ENABLE="dsl.txlimit" |
|
LABEL_RATE="dsl.txrate" |
|
LABEL_BURST="dsl.txburst" |
|
LABEL_LATENCY="dsl.txlatency" |
|
|
|
# Function to timestamp logs |
|
log() { |
|
echo "[DockerTrafficControl] $1" |
|
} |
|
|
|
apply_limit() { |
|
local cid=$1 |
|
|
|
# Inspect container to get PID and Labels |
|
# We use a custom format with pipe delimiter to parse easily |
|
local inspect_format="{{.State.Pid}}|{{index .Config.Labels \"$LABEL_ENABLE\"}}|{{index .Config.Labels \"$LABEL_RATE\"}}|{{index .Config.Labels \"$LABEL_BURST\"}}|{{index .Config.Labels \"$LABEL_LATENCY\"}}" |
|
|
|
local container_info |
|
container_info=$(docker inspect -f "$inspect_format" "$cid" 2>/dev/null) |
|
|
|
# If docker inspect failed (container might be gone), return |
|
if [ -z "$container_info" ]; then |
|
return |
|
fi |
|
|
|
# Read variables from the pipe-delimited string |
|
IFS='|' read -r pid limit_enable label_rate label_burst label_latency <<< "$container_info" |
|
|
|
# 1. Validation: PID check |
|
if [ -z "$pid" ] || [ "$pid" == "0" ]; then |
|
return |
|
fi |
|
|
|
# 2. Validation: Check if limiting is enabled (Strictly check for "1") |
|
if [ "$limit_enable" != "1" ]; then |
|
return |
|
fi |
|
|
|
# 3. Parameter Resolution: Use label value or fallback to default |
|
local rate=${label_rate:-$DEFAULT_RATE} |
|
local burst=${label_burst:-$DEFAULT_BURST} |
|
local latency=${label_latency:-$DEFAULT_LATENCY} |
|
|
|
log "Container $cid (PID: $pid) requesting limit. Rate=$rate, Burst=$burst, Latency=$latency." |
|
|
|
# 4. Execution: Apply TC rules via nsenter |
|
|
|
# Delete existing rules |
|
local del_output |
|
del_output=$(nsenter -t "$pid" -n tc qdisc del dev eth0 root 2>&1) |
|
|
|
# Add new rules |
|
local add_output |
|
add_output=$(nsenter -t "$pid" -n tc qdisc add dev eth0 root tbf rate "$rate" burst "$burst" latency "$latency" 2>&1) |
|
local status=$? |
|
|
|
if [ $status -eq 0 ]; then |
|
log "Limit applied successfully." |
|
else |
|
log "Failed to apply limit." |
|
log "tc del: $del_output" |
|
log "tc add: $add_output" |
|
fi |
|
} |
|
|
|
log "Docker Speed Limit Monitor Started" |
|
|
|
log "Processing running containers..." |
|
docker ps -q | while read -r container_id; do |
|
apply_limit "$container_id" |
|
done |
|
|
|
log "Listening for docker start events..." |
|
docker events --filter 'event=start' --format '{{ .Actor.ID }}' | while read -r container_id; do |
|
# Short sleep to ensure PID is ready in some edge cases |
|
sleep 1 |
|
apply_limit "${container_id::12}" |
|
done |