通过跳板机批量管理GPU服务器 - peter-xbs/CommonCodes GitHub Wiki
1. 通过跳板机监测GPU服务器使用情况
背景:200台GPU服务器,多人共用,但哪台GPU服务器空闲不太确定,如何快速找出闲置GPU服务器
#!/bin/bash
# 文件名包含目标服务器的IP地址
SERVER_LIST="gpu_servers.txt"
# 输出符合要求的服务器的IP地址文件
OUTPUT_FILE="idle_gpu_servers.txt"
# 日志文件
LOG_FILE="gpu_check.log"
# 检查服务器列表文件是否存在
if [ ! -f "$SERVER_LIST" ]; then
echo "服务器列表文件 '$SERVER_LIST' 不存在,请确认文件路径。"
exit 1
fi
# 清空输出文件和日志文件
> "$OUTPUT_FILE"
> "$LOG_FILE"
# 显存占用率阈值
MEMORY_USAGE_THRESHOLD=5
# 检查服务器GPU显存使用情况
check_server_gpu_usage() {
local server_ip=$1
echo "检查服务器 $server_ip 的 GPU 使用情况..." | tee -a "$LOG_FILE"
# 通过 SSH 获取 GPU 使用情况,使用 `timeout` 限制执行时间为10秒
gpu_info=$(ssh -o BatchMode=yes -o ConnectTimeout=5 "$server_ip" "timeout 10s nvidia-smi --query-gpu=memory.used,memory.total --format=csv,noheader,nounits; exit" 2>/dev/null)
# 检查 SSH 或者 nvidia-smi 命令是否成功执行
if [ $? -ne 0 ]; then
echo "无法连接到服务器 $server_ip 或者无法获取 GPU 状态信息。" | tee -a "$LOG_FILE"
return
fi
# 检查每个 GPU 的显存占用率,只要有一个GPU符合条件,就记录服务器IP
is_idle=true
IFS=$'\n'
for line in $gpu_info; do
memory_used=$(echo "$line" | awk -F, '{print $1}')
memory_total=$(echo "$line" | awk -F, '{print $2}')
memory_usage=$((100 * memory_used / memory_total))
if [ "$memory_usage" -gt "$MEMORY_USAGE_THRESHOLD" ](/peter-xbs/CommonCodes/wiki/-"$memory_usage"--gt-"$MEMORY_USAGE_THRESHOLD"-); then
is_idle=false
break
fi
done
unset IFS
if [ "$is_idle" = true ]; then
echo "推荐:服务器 $server_ip 的所有 GPU 显存占用率均低于 $MEMORY_USAGE_THRESHOLD%." | tee -a "$LOG_FILE"
echo "$server_ip" >> "$OUTPUT_FILE"
else
echo "服务器 $server_ip 不满足推荐条件." | tee -a "$LOG_FILE"
fi
}
# 并发执行每台服务器的检查
export -f check_server_gpu_usage
export MEMORY_USAGE_THRESHOLD
export OUTPUT_FILE
export LOG_FILE
# 使用 xargs 并发执行,最多同时处理 30 台服务器
xargs -a "$SERVER_LIST" -I {} -P 30 bash -c 'check_server_gpu_usage "$@"' _ {}
echo "符合条件的服务器 IP 已写入文件:$OUTPUT_FILE"
exit 0
2. 通过跳板机批量向GPU服务器复制环境
背景:跳板机准备了一个新的nemo2.tar的环境包,批量复制到每台GPU服务器解压使用
#!/bin/bash
# servers.txt 文件包含了所有服务器的 IP 地址或主机名
SERVERS_FILE="gpu_servers.txt"
# 要复制和解压的文件名
TAR_FILE="nemo2_slim.tar.gz"
# 目标路径
DEST_PATH="/opt/conda/envs"
# 读取服务器列表并使用 xargs 并行处理
cat $SERVERS_FILE | xargs -P 10 -I {} bash -c "{
echo 'Processing {}...'
rsync -azq --progress $TAR_FILE {}:${DEST_PATH}/ > /dev/null 2>&1 && \
ssh -q {} 'cd $DEST_PATH && tar -zxvf $TAR_FILE && rm -f $TAR_FILE' >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo '{}: Deployment successful.'
else
echo '{}: Error occurred during deployment.'
fi
}"
3. 批量复制docker镜像并load到GPU服务器内存中
#!/bin/bash
# 服务器地址列表文件路径
SERVERS_FILE="/apps/sharedstorage/oceanstor-a800/sunxinbao/monitor/gpu_servers.txt"
# 镜像文件路径
IMAGE_PATH="/apps/sharedstorage/oceanstor-a800/sunxinbao/TRANSFER/vllm-0.4.2.tar"
# 读取服务器列表并存入数组
mapfile -t SERVERS < "$SERVERS_FILE"
# 定义一个函数来加载镜像
load_image() {
local server=$1
echo "Starting image load on server: $server"
# 使用 SSH 执行 docker load 命令
ssh "$server" "docker load < $IMAGE_PATH" && echo "Image loaded successfully on $server" || echo "Failed to load image on $server"
}
# 循环遍历每个服务器并在后台并行执行 load_image 函数
for server in "${SERVERS[@]}"; do
load_image "$server" &
done
# 等待所有后台任务完成
wait
echo "All operations completed."