first commit
This commit is contained in:
179
docker-info/AGENTS.md
Normal file
179
docker-info/AGENTS.md
Normal 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
253
docker-info/docker-info.sh
Executable 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 "$@"
|
||||
Reference in New Issue
Block a user