first commit

This commit is contained in:
root
2026-02-17 17:28:37 +08:00
commit 192078dc3b
52 changed files with 18158 additions and 0 deletions

179
docker-info/AGENTS.md Normal file
View File

@@ -0,0 +1,179 @@
# AGENTS.md - Agentic Coding Guidelines
## Project Overview
This is a Bash shell script project for collecting Docker and server information on Debian/Ubuntu systems.
**Primary Language**: Bash
**Main File**: `docker-info.sh`
---
## Build/Lint/Test Commands
Since this is a Bash script project without a formal build system, use these commands:
### Linting
```bash
# ShellCheck (static analysis for bash scripts)
shellcheck docker-info.sh
# Check for syntax errors
bash -n docker-info.sh
```
### Testing
```bash
# Run the script (requires Docker to be installed for full functionality)
bash docker-info.sh
# Or make executable and run directly
chmod +x docker-info.sh
./docker-info.sh
```
### Single Test Pattern
```bash
# Test specific functions by sourcing and calling them
source docker-info.sh && command_exists docker
source docker-info.sh && print_success "test message"
```
---
## Code Style Guidelines
### General Bash Style
- **Shebang**: Always use `#!/usr/bin/env bash`
- **Set options**: Use `set -euo pipefail` at the start of scripts
- `-e`: Exit on error
- `-u`: Exit on undefined variables
- `-o pipefail`: Pipeline fails if any command fails
### Formatting
- **Indentation**: 4 spaces (no tabs)
- **Line length**: Keep lines under 100 characters
- **Quotes**: Always quote variables: `"$variable"` not `$variable`
- **Functions**: Use `snake_case` for function names
- **Constants**: Use `UPPER_CASE` for constants and color codes
### Naming Conventions
```bash
# Functions - snake_case
print_header() { }
get_server_info() { }
check_root() { }
# Variables - descriptive names
local container_output
local cpu_count
local total_mem
# Constants - UPPER_CASE
readonly RED='\033[0;31m'
readonly HEADER_COLOR="${BRIGHT_CYAN}"
```
### Error Handling
```bash
# Always check command existence before use
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Use proper exit codes
if ! command_exists docker; then
print_error "Docker未安装"
return 1
fi
# Redirect errors appropriately
docker ps 2>/dev/null || print_warning "无法列出容器"
```
### Function Structure
```bash
# Document functions with comments
# 获取服务器信息
get_server_info() {
print_header "服务器信息"
# Use local for function-scoped variables
local cpu_count=$(grep -c '^processor' /proc/cpuinfo)
local cpu_model=$(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
# Call other functions for output
print_key_value "CPU核心数" "$cpu_count"
}
```
### Color/Styling Code
- Define color codes as constants at the top of the file
- Group related colors together (basic, bright, background, styles)
- Use descriptive names: `HEADER_COLOR`, `SUCCESS_COLOR`, `ERROR_COLOR`
- Always reset colors with `${NC}` after colored output
### Output Patterns
```bash
# Use helper functions for consistent output
print_header() # Boxed titles
print_section() # Section headers with arrows
print_key_value() # Key: Value pairs
print_success() # Green checkmark
print_warning() # Yellow warning
print_error() # Red X
```
### Comments
- Use Chinese comments to match existing codebase style
- Keep comments concise and meaningful
- Comment complex logic or non-obvious behavior
---
## Testing Checklist
Before submitting changes:
- [ ] Run `shellcheck docker-info.sh` with no warnings
- [ ] Run `bash -n docker-info.sh` for syntax check
- [ ] Test on a system with Docker installed
- [ ] Test on a system without Docker (should handle gracefully)
- [ ] Verify all color output displays correctly
- [ ] Check that tables align properly
---
## Dependencies
**Required**: None (uses standard POSIX utilities)
**Optional but recommended**:
- `jq` - For better JSON parsing of Docker info
- `shellcheck` - For linting
---
## File Structure
```
/shumengya/project/bash/docker-info/
└── docker-info.sh # Main script file
```
---
## Security Notes
- This script may require root access for some Docker operations
- Always validate user input if added in the future
- Use proper quoting to prevent word splitting and globbing
- Sanitize any data passed to eval or similar dangerous operations

253
docker-info/docker-info.sh Executable file
View File

@@ -0,0 +1,253 @@
#!/usr/bin/env bash
# =============================================================================
# Docker Info Collector - Single Column Edition
# =============================================================================
set -euo pipefail
# =============================================================================
# Colors
# =============================================================================
readonly NC='\033[0m'
readonly GRAY='\033[0;90m'
readonly CYAN='\033[0;36m'
readonly GREEN='\033[1;32m'
readonly YELLOW='\033[1;33m'
readonly WHITE='\033[1;37m'
readonly DIM='\033[2m'
readonly C_HEADER="${CYAN}"
readonly C_SECTION="${YELLOW}"
readonly C_KEY="${WHITE}"
readonly C_VALUE="${CYAN}"
readonly C_OK="${GREEN}"
readonly C_WARN="${YELLOW}"
readonly C_ERR="\033[1;31m"
readonly C_DIM="${GRAY}"
# Separator line (thick line style)
SEP_LINE="${C_DIM}══════════════════════════════════════════════════════════════════════════════${NC}"
# =============================================================================
# Utils
# =============================================================================
has_cmd() { command -v "$1" &>/dev/null; }
print_header() {
local title="$1"
local len=${#title}
local pad=$(( (76 - len) / 2 ))
echo -e "\n${C_HEADER}╔══════════════════════════════════════════════════════════════════════════════╗"
printf "${C_HEADER}║%${pad}s${WHITE} %s %${pad}s║${NC}\n" "" "$title" ""
echo -e "${C_HEADER}╚══════════════════════════════════════════════════════════════════════════════╝${NC}"
}
print_section() {
echo -e "\n${C_SECTION}$1${NC}"
echo -e "$SEP_LINE"
}
print_kv() {
printf " ${C_KEY}%-14s${NC} ${C_VALUE}%s${NC}\n" "$1:" "$2"
}
print_ok() { echo -e " ${C_OK}${NC} $1"; }
print_warn() { echo -e " ${C_WARN}${NC} $1"; }
print_err() { echo -e " ${C_ERR}${NC} $1"; }
# =============================================================================
# System Info
# =============================================================================
collect_server() {
print_header "服务器信息"
# OS Information
print_section "操作系统"
local os_name kernel arch
os_name="$(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME" || uname -s)"
kernel="$(uname -r)"
arch="$(uname -m)"
print_kv "系统" "$os_name"
print_kv "内核版本" "$kernel"
print_kv "系统架构" "$arch"
# Host Info
print_section "主机信息"
local hostname uptime_str
hostname="$(hostname)"
uptime_str="$(uptime -p 2>/dev/null | sed 's/up //' || uptime | sed 's/.*up //; s/,.*//')"
print_kv "主机名" "$hostname"
print_kv "运行时长" "$uptime_str"
print_kv "当前时间" "$(date '+%Y-%m-%d %H:%M:%S')"
# CPU
if [[ -f /proc/cpuinfo ]]; then
print_section "处理器"
local cpus cpu_model
cpus=$(grep -c '^processor' /proc/cpuinfo)
cpu_model=$(grep 'model name' /proc/cpuinfo | head -1 | cut -d: -f2 | xargs)
print_kv "核心数量" "${cpus}"
print_kv "型号" "$cpu_model"
fi
# Memory
if has_cmd free; then
print_section "内存"
local mem_total mem_used mem_free mem_pct
mem_total=$(free -h | awk '/^Mem:/ {print $2}')
mem_used=$(free -h | awk '/^Mem:/ {print $3}')
mem_free=$(free -h | awk '/^Mem:/ {print $7}')
mem_pct=$(free | awk '/^Mem:/ {printf "%.1f", $3/$2 * 100}')
print_kv "总容量" "$mem_total"
print_kv "已使用" "$mem_used (${mem_pct}%)"
print_kv "可用" "$mem_free"
fi
# Disk
if has_cmd df; then
print_section "磁盘使用"
df -h --output=source,fstype,size,used,pcent,target 2>/dev/null | tail -n +2 | while read -r fs type size used pct target; do
[[ "$fs" == "tmpfs" || "$fs" == "devtmpfs" || "$fs" == "overlay" ]] && continue
[[ -z "$fs" ]] && continue
# Escape % for printf
local pct_clean="${pct%%%}"
printf " ${C_DIM}[${NC}${C_VALUE}%-12s${NC}${C_DIM}]${NC} ${C_KEY}%-8s${NC} ${C_VALUE}%-7s${NC} ${C_DIM}used:${NC} ${C_VALUE}%-7s${NC} ${C_DIM}(%s%%)${NC}\n" \
"$target" "$type" "$size" "$used" "$pct_clean"
done
fi
# Network
if has_cmd ip; then
print_section "网络接口"
ip -o addr show 2>/dev/null | awk '{print $2, $4}' | while read -r iface addr; do
[[ "$iface" == "lo" ]] && continue
print_kv "$iface" "$addr"
done
fi
}
# =============================================================================
# Docker Info
# =============================================================================
collect_docker() {
print_header "Docker 信息"
if ! has_cmd docker; then
print_err "Docker 未安装"
return 1
fi
# Version
print_section "版本信息"
local client_ver server_ver
client_ver=$(docker version --format '{{.Client.Version}}' 2>/dev/null || echo "N/A")
server_ver=$(docker version --format '{{.Server.Version}}' 2>/dev/null || echo "N/A")
print_kv "客户端" "$client_ver"
print_kv "服务端" "$server_ver"
if has_cmd docker-compose; then
print_kv "Docker Compose" "$(docker-compose version --short 2>/dev/null)"
fi
# Status
if docker info &>/dev/null; then
print_ok "守护进程运行中"
else
print_warn "守护进程未运行"
return 1
fi
# Stats
print_section "资源统计"
local containers running images networks volumes
containers=$(docker ps -aq 2>/dev/null | wc -l)
running=$(docker ps -q 2>/dev/null | wc -l)
images=$(docker images -q 2>/dev/null | wc -l)
networks=$(docker network ls -q 2>/dev/null | wc -l)
volumes=$(docker volume ls -q 2>/dev/null | wc -l)
print_kv "容器" "${running} 运行 / ${containers} 总计"
print_kv "镜像" "$images"
print_kv "网络" "$networks"
print_kv "存储卷" "$volumes"
# Running containers
if [[ $running -gt 0 ]]; then
print_section "运行中的容器"
docker ps --format "{{.Names}}|{{.Image}}|{{.Status}}" 2>/dev/null | while IFS='|' read -r name image status; do
printf " ${C_OK}${NC} ${C_VALUE}%-20s${NC} ${C_DIM}%-30s${NC} %s\n" "$name" "${image:0:30}" "$status"
done
fi
# All containers
if [[ $containers -gt 0 ]]; then
print_section "所有容器"
docker ps -a --format "{{.Names}}|{{.Image}}|{{.Status}}" 2>/dev/null | head -20 | while IFS='|' read -r name image status; do
local icon="${C_DIM}${NC}"
local color="$C_VALUE"
[[ "$status" == Up* ]] && icon="${C_OK}${NC}" && color="$C_OK"
[[ "$status" == Exited* ]] && color="$C_DIM"
printf " ${icon} ${color}%-20s${NC} ${C_DIM}%-25s${NC} %s\n" "$name" "${image:0:25}" "$status"
done
[[ $containers -gt 20 ]] && echo -e " ${C_DIM}... 还有 $((containers - 20)) 个容器${NC}"
fi
# Images
if [[ $images -gt 0 ]]; then
print_section "镜像列表"
docker images --format "{{.Repository}}|{{.Tag}}|{{.Size}}|{{.CreatedAt}}" 2>/dev/null | grep -v "<none>" | head -25 | while IFS='|' read -r repo tag size created; do
printf " ${C_DIM}${NC} ${C_VALUE}%-35s${NC} ${C_DIM}%-10s %s${NC}\n" "${repo}:${tag}" "$size" "$created"
done
[[ $images -gt 25 ]] && echo -e " ${C_DIM}... 还有 $((images - 25)) 个镜像${NC}"
fi
# Networks
if [[ $networks -gt 0 ]]; then
print_section "网络"
docker network ls --format "{{.Name}}|{{.Driver}}|{{.Scope}}" 2>/dev/null | head -15 | while IFS='|' read -r name driver scope; do
printf " ${C_DIM}${NC} ${C_VALUE}%-20s${NC} ${C_DIM}[%s/%s]${NC}\n" "$name" "$driver" "$scope"
done
fi
# Volumes
if [[ $volumes -gt 0 ]]; then
print_section "存储卷"
docker volume ls --format "{{.Name}}|{{.Driver}}" 2>/dev/null | head -20 | while IFS='|' read -r name driver; do
printf " ${C_DIM}${NC} ${C_VALUE}%s${NC} ${C_DIM}(%s)${NC}\n" "$name" "$driver"
done
[[ $volumes -gt 20 ]] && echo -e " ${C_DIM}... 还有 $((volumes - 20)) 个存储卷${NC}"
fi
}
# =============================================================================
# Main
# =============================================================================
main() {
collect_server
collect_docker
echo -e "\n${C_HEADER}╔══════════════════════════════════════════════════════════════════════════════╗"
echo -e "${C_HEADER}${C_OK} ✓ 信息收集完成 ${C_HEADER}${NC}"
echo -e "${C_HEADER}╚══════════════════════════════════════════════════════════════════════════════╝${NC}\n"
}
main "$@"