1. docker 镜像分发推送
很多时候我们的服务器即使能联网也无法下载docker镜像,只能依靠VPN服务器来进行下载分发,机器一多还是挺麻烦的。可以优化一下来个脚本,在里面预先配置主机与密码,通过该方式导出镜像再对目标机器推送加载,可以实现不错的效果,后续可以继续优化推送到私有harbor。
#!/bin/bash
set -e
# ============ 可选变量:自定义镜像仓库 ============
# 示例:harbor.tanqidi.com/k8s
CUSTOM_REGISTRY_PREFIX="harbor.tanqidi.com/k8s"
# 是否拉取 arm64 平台镜像
IS_ARM64=false # 设置为 true 表示拉取 arm64 镜像,false 表示拉取默认平台镜像
# 是否远程执行 docker push(默认 false)
PUSH_REMOTE=false # 设置为 true 将在远程节点执行 docker push
# 是否清理远程镜像(默认 false)
CLEAN_REMOTE_IMAGE=false # 设置为 true 将在远程 push 后清理远程镜像
# 是否清理本地镜像(默认 false)
CLEAN_LOCAL_IMAGE=false # 设置为 true 将在远程 push 后清理本地镜像
# ============ 依赖检查 ============
if ! command -v sshpass &> /dev/null; then
echo "❌ 错误:未找到命令 sshpass"
echo "请先安装 sshpass,例如:"
echo " Debian/Ubuntu: sudo apt update && sudo apt install -y sshpass"
echo " CentOS/RHEL: sudo yum install -y epel-release && sudo yum install -y sshpass"
echo " Alpine: apk add sshpass"
exit 1
fi
if ! command -v docker &> /dev/null; then
echo "❌ 错误:未找到命令 docker,请确保当前机器安装了 Docker"
exit 1
fi
# ============ 参数检查 ============
if [ $# -ne 1 ]; then
echo "用法: $0 <镜像名:版本>(例如 nginx:1.25)"
exit 1
fi
ORIGINAL_IMAGE="$1"
IMAGE_BASE=$(echo "$ORIGINAL_IMAGE" | cut -d: -f1)
IMAGE_TAG=$(echo "$ORIGINAL_IMAGE" | cut -d: -f2)
# 根据是否配置 CUSTOM_REGISTRY_PREFIX 判断最终使用的镜像名
if [ -n "$CUSTOM_REGISTRY_PREFIX" ]; then
# 去掉 registry 前缀(如 registry.k8s.io/),只保留路径部分
IMAGE_PATH=$(echo "$IMAGE_BASE" | sed -E 's|^[^/]+/||')
FINAL_IMAGE="$CUSTOM_REGISTRY_PREFIX/$IMAGE_PATH:$IMAGE_TAG"
else
FINAL_IMAGE="$ORIGINAL_IMAGE"
fi
# 镜像保存为文件名(去掉斜杠和冒号,格式安全)
IMAGE_FILE="${FINAL_IMAGE//\//_}"
IMAGE_FILE="${IMAGE_FILE//:/-}"
# ============ 节点配置 ============
# 格式:用户名 密码 IP(密码可以包含特殊字符)
NODES=(
"root 123456 172.31.0.111"
)
# ============ 拉取原始镜像 ============
echo "===> 拉取原始镜像 $ORIGINAL_IMAGE ..."
if [ "$IS_ARM64" == true ]; then
docker pull --platform linux/arm64 "$ORIGINAL_IMAGE"
else
docker pull "$ORIGINAL_IMAGE"
fi
# ============ 如果需要,重新打标签 ============
if [ "$ORIGINAL_IMAGE" != "$FINAL_IMAGE" ]; then
echo "===> 给镜像重新打标签: $ORIGINAL_IMAGE -> $FINAL_IMAGE"
docker tag "$ORIGINAL_IMAGE" "$FINAL_IMAGE"
fi
# ============ 保存镜像 ============
echo "===> 保存镜像为本地文件 $IMAGE_FILE ..."
docker save "$FINAL_IMAGE" > "$IMAGE_FILE"
# ============ 分发并加载 ============
for NODE in "${NODES[@]}"; do
USER=$(echo "$NODE" | awk '{print $1}')
PASS=$(echo "$NODE" | awk '{print $2}')
IP=$(echo "$NODE" | awk '{print $3}')
echo "===> 正在传输镜像到节点 $IP:/tmp/$IMAGE_FILE ..."
sshpass -p "$PASS" scp -o StrictHostKeyChecking=no "$IMAGE_FILE" "$USER@$IP:/tmp/"
echo "===> 在节点 $IP 加载镜像并清理镜像包 ..."
sshpass -p "$PASS" ssh -o StrictHostKeyChecking=no "$USER@$IP" "
docker load < /tmp/$IMAGE_FILE && rm -f /tmp/$IMAGE_FILE
"
# 如果需要远程执行 docker push
if [ "$PUSH_REMOTE" == true ]; then
echo "===> 在节点 $IP 执行 docker push $FINAL_IMAGE ..."
sshpass -p "$PASS" ssh -o StrictHostKeyChecking=no "$USER@$IP" "
docker push $FINAL_IMAGE
"
fi
# 如果需要远程清理镜像
if [ "$CLEAN_REMOTE_IMAGE" == true ]; then
echo "===> 在节点 $IP 执行 docker rmi $FINAL_IMAGE ..."
sshpass -p "$PASS" ssh -o StrictHostKeyChecking=no "$USER@$IP" "
docker rmi -f $FINAL_IMAGE
"
fi
done
# ============ 本地清理 ============
if [ "$CLEAN_LOCAL_IMAGE" == true ]; then
echo "===> 清理本地镜像 $FINAL_IMAGE ..."
docker rmi -f "$FINAL_IMAGE"
fi
echo "✅ 镜像 [$FINAL_IMAGE] 已成功分发并加载到所有节点。"
2. 打印服务器信息
在某些内网环境中,由于无法访问外部仓库或下载成熟的工具,很多操作系统信息的获取需要通过命令行工具手动完成。这个脚本将自动化这类繁琐的任务,快速输出系统的关键运行信息,无需额外依赖任何外部工具。
echo -e "系统版本: $(grep PRETTY_NAME /etc/os-release | cut -d= -f2 | tr -d '"' || echo "N/A")\n内核版本: $(uname -r || echo "N/A")\n系统架构: $(uname -m || echo "N/A")\n主机名: $(hostname || echo "N/A")\nFQDN: $(hostname -f 2>/dev/null || echo "N/A")\nCPU型号: $(grep -m1 'model name\|Processor' /proc/cpuinfo | cut -d: -f2 | sed 's/^ *//' || echo "N/A")\nCPU核心数: 物理: $(grep '^cpu cores' /proc/cpuinfo | uniq | cut -d: -f2 | sed 's/ //g' || echo "N/A"), 逻辑: $(grep -c '^processor' /proc/cpuinfo || echo "N/A")\n总内存: $(free -h | awk '/Mem:/ {print $2}' || echo "N/A"), 已用: $(free | awk '/Mem:/ {if ($2 > 0) printf "%.2f%%", $3/$2*100; else print "N/A"}' || echo "N/A")\n总Swap: $(free -h | awk '/Swap:/ {print $2}' || echo "N/A"), 已用: $(free | awk '/Swap:/ {if ($2 > 0) printf "%.2f%%", $3/$2*100; else print "N/A"}' || echo "N/A")\n\n根分区使用: $(df -h / | awk 'NR==2 {print $5}' || echo "N/A")\n\n磁盘总量:\n$(df -h | grep -E '^/dev/' | awk 'NR==1 {printf "%-35s %-15s %-15s %-15s %-10s %-10s\n", $1, $2, $3, $4, $5, $6} NR>1 {printf "%-35s %-15s %-15s %-15s %-10s %-10s\n", $1, $2, $3, $4, $5, $6}' || echo "N/A")\n\nIPv4地址: $(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2 " (" $NF ")"}' | head -n 1 || echo "N/A")\nIPv6地址: $(ip addr show | grep 'inet6 ' | grep -v '::1' | awk '{print $2 " (" $NF ")"}' | head -n 1 || echo "N/A")\n默认网关: $(ip route show default | awk '/default/ {print $3}' || echo "N/A")\n网卡名称: $(ip link show | awk -F': ' '/^[0-9]+:/{print $2}' | grep -v 'lo' | head -n 1 || echo "N/A")\nDNS配置: $(cat /etc/resolv.conf | grep '^nameserver' | awk '{print $2}' | paste -sd ', ' - || echo "N/A")\n当前登录用户: $(who | awk '{print $1}' | paste -sd ', ' - || echo "N/A")\nSELinux 状态: $(getenforce || echo "N/A")\n系统时间: $(date || echo "N/A")\n时区: $(timedatectl show --property=Timezone --value 2>/dev/null || echo "N/A" | sed -r 's/\(.*\)//g')\n启动时间: $(who -b | awk '{print $3 " " $4}' || echo "N/A")\n运行时间: $(uptime | awk '{print $3 " " $4}' | cut -d, -f1 || echo "N/A")\n负载平均值: $(uptime | awk -F'load average: ' '{print $2}' || echo "N/A")\n登录用户数: $(who | wc -l || echo "N/A")\n进程总数: $(ps aux | wc -l || echo "N/A")\n公网IP: $(timeout 2 curl -s ifconfig.me || echo "N/A")"
系统版本: Ubuntu 22.04 LTS
内核版本: 5.15.0-106-generic
系统架构: x86_64
主机名: VM-8-14-ubuntu
FQDN: localhost.localdomain
CPU型号: AMD EPYC 7K62 48-Core Processor
CPU核心数: 物理: 2, 逻辑: 2
总内存: 3.3Gi, 已用: 54.95%
总Swap: 4.0Gi, 已用: 77.56%
根分区使用: 44%
磁盘总量:
/dev/vda2 69G 29G 38G 44% /
IPv4地址: 10.1.8.14/22 (eth0)
IPv6地址: fe80::5054:ff:fe75:4940/64 (link)
默认网关: 10.1.8.1
网卡名称: eth0
DNS配置: 127.0.0.53
当前登录用户: ubuntu,ubuntu
防火墙状态: Status: inactive
SELinux 状态: N/A
系统时间: Fri Jul 18 09:44:03 AM CST 2025
时区: Asia/Shanghai
启动时间: 2025-05-10 07:57
运行时间: 69 days
负载平均值: 0.03, 0.10, 0.04
登录用户数: 2
进程总数: 205
公网IP: N/A