最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SSH高效實(shí)現(xiàn)批量連接服務(wù)器的最佳實(shí)踐與避坑指南

 更新時(shí)間:2026年01月27日 09:07:51   作者:碼農(nóng)阿豪@新空間  
在運(yùn)維工作中,我們常常需要管理大量服務(wù)器,本文詳細(xì)記錄了運(yùn)維工作中批量測(cè)試SSH連接的完整解決方案,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下

引言:當(dāng)自動(dòng)化遇到現(xiàn)實(shí)挑戰(zhàn)

在運(yùn)維工作中,我們常常需要管理大量服務(wù)器。最近我遇到一個(gè)實(shí)際需求:需要快速測(cè)試一批服務(wù)器的SSH連接性,所有服務(wù)器都使用相同的root賬號(hào)和密碼。這聽(tīng)起來(lái)應(yīng)該很簡(jiǎn)單,但實(shí)施過(guò)程中卻遇到了各種意想不到的問(wèn)題。本文將詳細(xì)記錄這次實(shí)戰(zhàn)經(jīng)歷,分享完整的解決方案,并總結(jié)出可靠的最佳實(shí)踐。

需求分析:明確目標(biāo)與約束條件

原始需求

  • 測(cè)試一批IP地址的22端口SSH連接
  • 使用固定賬號(hào):root
  • 使用固定密碼:mn150@2099A
  • 需要超時(shí)控制(2-3秒)
  • 結(jié)果分類(lèi):成功與失敗的IP分別保存
  • 支持批量處理(IP數(shù)量可能達(dá)到數(shù)百個(gè))

技術(shù)約束

  • 運(yùn)行環(huán)境:CentOS 7
  • 網(wǎng)絡(luò)條件:可能存在網(wǎng)絡(luò)延遲和防火墻限制
  • 安全考慮:雖然使用密碼認(rèn)證,但這是測(cè)試環(huán)境

技術(shù)選型:多種方案的對(duì)比

方案一:sshpass + 循環(huán)(最直接)

sshpass -p '密碼' ssh -o ConnectTimeout=5 root@IP "命令"

優(yōu)點(diǎn):簡(jiǎn)單直接,無(wú)需額外依賴(lài)

缺點(diǎn):缺乏并行處理,速度慢

方案二:expect腳本(更健壯)

expect << EOF
spawn ssh root@IP
expect "password:" { send "密碼\r" }
expect eof
EOF

優(yōu)點(diǎn):處理交互更穩(wěn)定

缺點(diǎn):語(yǔ)法復(fù)雜,調(diào)試?yán)щy

方案三:Python + Paramiko(功能強(qiáng)大)

import paramiko
ssh = paramiko.SSHClient()
ssh.connect(hostname=ip, username='root', password='密碼', timeout=3)

優(yōu)點(diǎn):功能全面,錯(cuò)誤處理完善

缺點(diǎn):需要Python環(huán)境

方案四:并行處理(效率最高)

cat iplist.txt | parallel -j 20 "測(cè)試命令"

優(yōu)點(diǎn):大幅提升測(cè)試速度

缺點(diǎn):并發(fā)控制復(fù)雜,容易出錯(cuò)

實(shí)戰(zhàn)過(guò)程:從簡(jiǎn)單到復(fù)雜的演進(jìn)

第一階段:基礎(chǔ)腳本開(kāi)發(fā)

最初的腳本很簡(jiǎn)單:

#!/bin/bash
PASSWORD='mn150@2099A'

while read ip; do
    sshpass -p "$PASSWORD" ssh -o ConnectTimeout=3 root@$ip "echo ok"
    if [ $? -eq 0 ]; then
        echo "$ip" >> success.txt
    else
        echo "$ip" >> fail.txt
    fi
done < iplist.txt

這個(gè)腳本能工作,但存在幾個(gè)問(wèn)題:

  • 沒(méi)有進(jìn)度顯示
  • 錯(cuò)誤處理不完善
  • 串行執(zhí)行,速度慢

第二階段:添加功能增強(qiáng)

改進(jìn)版本增加了以下功能:

#!/bin/bash
# 配置參數(shù)
PASSWORD='mn150@2099A'
TIMEOUT=3
IP_FILE="iplist.txt"
SUCCESS_FILE="success_ips.txt"
FAILED_FILE="failed_ips.txt"

# 統(tǒng)計(jì)和進(jìn)度
TOTAL=$(wc -l < "$IP_FILE")
COUNT=0

echo "開(kāi)始測(cè)試 $TOTAL 個(gè)IP..."

while read ip; do
    COUNT=$((COUNT + 1))
    echo -n "[$COUNT/$TOTAL] 測(cè)試 $ip ... "
    
    timeout $TIMEOUT sshpass -p "$PASSWORD" ssh \
        -o ConnectTimeout=$TIMEOUT \
        -o StrictHostKeyChecking=no \
        root@"$ip" "exit" 2>/dev/null
    
    if [ $? -eq 0 ]; then
        echo "成功"
        echo "$ip" >> "$SUCCESS_FILE"
    else
        echo "失敗"
        echo "$ip" >> "$FAILED_FILE"
    fi
done < "$IP_FILE"

這個(gè)版本已經(jīng)有了基本框架,但仍然不夠理想。

第三階段:遇到的坑與解決方案

坑1:腳本編碼問(wèn)題

現(xiàn)象:腳本只運(yùn)行了4個(gè)IP就停止

錯(cuò)誤信息./ssh_batch_test.sh: line 1: i#!/bin/bash: No such file or directory

根本原因:腳本文件編碼問(wèn)題,可能是從Windows復(fù)制過(guò)來(lái),或者編輯器保存時(shí)加入了BOM頭。

解決方案

# 檢查文件編碼
file ssh_batch_test.sh

# 修復(fù)編碼問(wèn)題
sed -i '1s/^.*#!/#!/' ssh_batch_test.sh
# 或者重新創(chuàng)建腳本
cat > new_script.sh << 'EOF'
#!/bin/bash
# 正確內(nèi)容
EOF

坑2:IP文件格式問(wèn)題

現(xiàn)象:雖然IP文件有200多個(gè)IP,但腳本只處理了4個(gè)

可能原因

  • Windows換行符(CRLF)
  • 文件中有特殊字符
  • 讀取邏輯有缺陷

解決方案

# 檢查文件格式
cat -A iplist.txt | head -10

# 修復(fù)換行符
dos2unix iplist.txt
# 或者使用sed
sed -i 's/\r$//' iplist.txt

# 清理文件
grep -v '^[[:space:]]*$' iplist.txt | grep -v '^#' > iplist_clean.txt

坑3:SSH選項(xiàng)沖突

現(xiàn)象:手動(dòng)測(cè)試成功,但腳本測(cè)試失敗

關(guān)鍵發(fā)現(xiàn)-o BatchMode=yes選項(xiàng)會(huì)禁用密碼認(rèn)證!

錯(cuò)誤配置

# 這個(gè)會(huì)失敗
sshpass -p '密碼' ssh -o BatchMode=yes root@IP "命令"

# 正確的應(yīng)該是
sshpass -p '密碼' ssh -o BatchMode=no root@IP "命令"
# 或者干脆不要BatchMode選項(xiàng)

坑4:并發(fā)寫(xiě)入沖突

現(xiàn)象:并行腳本運(yùn)行異常,結(jié)果不完整

原因:多個(gè)進(jìn)程同時(shí)寫(xiě)入同一個(gè)文件

解決方案

# 每個(gè)進(jìn)程寫(xiě)入獨(dú)立文件,最后合并
TEMP_DIR=$(mktemp -d)
# 每個(gè)進(jìn)程寫(xiě)入 $TEMP_DIR/result_$PID
# 最后 cat $TEMP_DIR/* > final_result.txt

第四階段:最終穩(wěn)定版本

經(jīng)過(guò)多次調(diào)試,最終得到了穩(wěn)定可靠的版本:

#!/bin/bash
# SSH批量測(cè)試腳本 - 最終穩(wěn)定版

set -u  # 使用未定義變量時(shí)報(bào)錯(cuò)
set -e  # 遇到錯(cuò)誤時(shí)退出

# 配置參數(shù)
PASSWORD='mn150@2099A'
CONNECT_TIMEOUT=3
IP_FILE="${1:-iplist.txt}"

# 生成帶時(shí)間戳的結(jié)果文件
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
SUCCESS_FILE="success_ips_${TIMESTAMP}.txt"
FAILED_FILE="failed_ips_${TIMESTAMP}.txt"

# 驗(yàn)證環(huán)境
validate_environment() {
    # 檢查sshpass
    if ! command -v sshpass &> /dev/null; then
        echo "錯(cuò)誤: sshpass 未安裝"
        echo "請(qǐng)執(zhí)行: sudo yum install -y epel-release sshpass"
        exit 1
    fi
    
    # 檢查IP文件
    if [ ! -f "$IP_FILE" ]; then
        echo "錯(cuò)誤: IP文件 $IP_FILE 不存在"
        exit 1
    fi
    
    # 檢查文件是否可讀
    if [ ! -r "$IP_FILE" ]; then
        echo "錯(cuò)誤: 無(wú)法讀取IP文件 $IP_FILE"
        exit 1
    fi
}

# 清理和驗(yàn)證IP列表
prepare_ip_list() {
    local input_file="$1"
    local output_file="$2"
    
    # 清空輸出文件
    > "$output_file"
    
    # 處理IP文件:移除注釋、空行、換行符
    while IFS= read -r line || [ -n "$line" ]; do
        # 移除換行符和回車(chē)符
        line=$(echo "$line" | tr -d '\r')
        
        # 跳過(guò)空行和注釋
        if [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]]; then
            continue
        fi
        
        # 提取IP(移除可能的后綴和注釋?zhuān)?
        ip=$(echo "$line" | sed 's/[[:space:]].*$//' | sed 's/#.*$//')
        
        # 驗(yàn)證IP格式
        if [[ "$ip" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
            echo "$ip" >> "$output_file"
        else
            echo "警告: 跳過(guò)無(wú)效IP格式: $ip" >&2
        fi
    done < "$input_file"
}

# 測(cè)試單個(gè)IP
test_single_ip() {
    local ip="$1"
    
    # 使用timeout防止命令掛起
    timeout ${CONNECT_TIMEOUT} sshpass -p "$PASSWORD" ssh \
        -o ConnectTimeout=${CONNECT_TIMEOUT} \
        -o StrictHostKeyChecking=no \
        -o PasswordAuthentication=yes \
        -o BatchMode=no \
        -o LogLevel=ERROR \
        root@"$ip" "exit 0" 2>/dev/null
    
    return $?
}

# 主函數(shù)
main() {
    echo "========================================"
    echo "SSH批量連接測(cè)試工具"
    echo "========================================"
    echo "賬號(hào):        root"
    echo "超時(shí)時(shí)間:    ${CONNECT_TIMEOUT}秒"
    echo "IP文件:      $IP_FILE"
    echo "結(jié)果文件:"
    echo "  成功IP:    $SUCCESS_FILE"
    echo "  失敗IP:    $FAILED_FILE"
    echo "========================================"
    
    # 驗(yàn)證環(huán)境
    validate_environment
    
    # 準(zhǔn)備IP列表
    local clean_ip_file="/tmp/clean_ips_$$.txt"
    prepare_ip_list "$IP_FILE" "$clean_ip_file"
    
    local total_ips=$(wc -l < "$clean_ip_file" 2>/dev/null || echo 0)
    if [ $total_ips -eq 0 ]; then
        echo "錯(cuò)誤: 沒(méi)有有效的IP地址可以測(cè)試"
        exit 1
    fi
    
    echo "找到 $total_ips 個(gè)有效IP地址"
    echo ""
    
    # 清空結(jié)果文件
    > "$SUCCESS_FILE"
    > "$FAILED_FILE"
    
    # 開(kāi)始測(cè)試
    echo "開(kāi)始測(cè)試..."
    echo "----------------------------------------"
    
    local tested=0
    local success=0
    local failed=0
    
    while read ip; do
        tested=$((tested + 1))
        
        # 顯示進(jìn)度(每10個(gè)IP顯示一次)
        if [ $((tested % 10)) -eq 0 ] || [ $tested -eq $total_ips ]; then
            printf "\r進(jìn)度: %d/%d (%.1f%%)" $tested $total_ips $(echo "scale=1; $tested*100/$total_ips" | bc)
        fi
        
        # 測(cè)試連接
        if test_single_ip "$ip"; then
            echo "$ip" >> "$SUCCESS_FILE"
            success=$((success + 1))
        else
            echo "$ip" >> "$FAILED_FILE"
            failed=$((failed + 1))
        fi
    done < "$clean_ip_file"
    
    echo ""
    echo "----------------------------------------"
    echo ""
    
    # 生成報(bào)告
    echo "測(cè)試完成!"
    echo "========================================"
    echo "統(tǒng)計(jì)結(jié)果:"
    echo "  總IP數(shù):    $total_ips"
    echo "  成功數(shù):    $success"
    echo "  失敗數(shù):    $failed"
    
    if [ $total_ips -gt 0 ]; then
        local success_rate=$(echo "scale=2; $success * 100 / $total_ips" | bc)
        echo "  成功率:    ${success_rate}%"
    fi
    
    echo ""
    echo "結(jié)果文件已生成:"
    echo "  $SUCCESS_FILE"
    echo "  $FAILED_FILE"
    
    # 顯示示例結(jié)果
    if [ -s "$SUCCESS_FILE" ]; then
        echo ""
        echo "成功IP示例(前5個(gè)):"
        head -5 "$SUCCESS_FILE" | cat -n
    fi
    
    # 清理臨時(shí)文件
    rm -f "$clean_ip_file"
}

# 執(zhí)行主函數(shù)
main

關(guān)鍵技術(shù)與最佳實(shí)踐

1. 健壯的IP文件處理

# 正確處理各種格式的IP文件
while IFS= read -r line || [ -n "$line" ]; do
    # 處理?yè)Q行符
    line=$(echo "$line" | tr -d '\r')
    
    # 驗(yàn)證IP格式
    if [[ "$line" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        # 有效IP
    fi
done < ipfile.txt

2. 適當(dāng)?shù)腟SH選項(xiàng)配置

# 推薦的SSH選項(xiàng)組合
sshpass -p "$PASSWORD" ssh \
    -o ConnectTimeout=$TIMEOUT \      # 連接超時(shí)
    -o StrictHostKeyChecking=no \     # 不檢查主機(jī)密鑰(測(cè)試環(huán)境)
    -o PasswordAuthentication=yes \   # 允許密碼認(rèn)證
    -o BatchMode=no \                 # 不禁用密碼認(rèn)證!
    -o LogLevel=ERROR \               # 只顯示錯(cuò)誤日志
    root@"$IP" "命令"

3. 合理的錯(cuò)誤處理

# 使用timeout防止命令掛起
timeout $TIMEOUT 命令

# 檢查退出碼
if [ $? -eq 0 ]; then
    # 成功
elif [ $? -eq 124 ]; then
    # 超時(shí)
elif [ $? -eq 5 ]; then
    # 認(rèn)證失敗
else
    # 其他錯(cuò)誤
fi

4. 進(jìn)度反饋機(jī)制

# 顯示進(jìn)度百分比
printf "\r進(jìn)度: %d/%d (%.1f%%)" $current $total $(echo "scale=1; $current*100/$total" | bc)

# 或使用進(jìn)度條
draw_progress_bar() {
    local current=$1
    local total=$2
    local width=50
    local percent=$((current * 100 / total))
    local completed=$((current * width / total))
    
    printf "\r["
    printf "%${completed}s" | tr ' ' '='
    printf "%$((width - completed))s" | tr ' ' '.'
    printf "] %3d%%" $percent
}

性能優(yōu)化技巧

并行處理方案

對(duì)于大量IP的測(cè)試,順序執(zhí)行太慢。以下是安全的并行方案:

#!/bin/bash
# 安全的并行測(cè)試

PASSWORD='mn150@2099A'
TIMEOUT=3
MAX_JOBS=10

# 創(chuàng)建臨時(shí)目錄存放結(jié)果
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT

# 測(cè)試函數(shù)
test_ip() {
    local ip=$1
    local pid=$$
    
    timeout $TIMEOUT sshpass -p "$PASSWORD" ssh \
        -o ConnectTimeout=$TIMEOUT \
        -o StrictHostKeyChecking=no \
        root@"$ip" "exit" 2>/dev/null
    
    if [ $? -eq 0 ]; then
        echo "$ip" >> "$TEMP_DIR/success_$pid"
    else
        echo "$ip" >> "$TEMP_DIR/failed_$pid"
    fi
}

# 導(dǎo)出函數(shù)
export -f test_ip
export PASSWORD TIMEOUT TEMP_DIR

# 并行執(zhí)行
cat iplist.txt | xargs -P $MAX_JOBS -I {} bash -c 'test_ip "$@"' _ {}

# 合并結(jié)果
cat "$TEMP_DIR"/success_* 2>/dev/null | sort -u > success.txt
cat "$TEMP_DIR"/failed_* 2>/dev/null | sort -u > failed.txt

資源限制

# 避免過(guò)多的并發(fā)連接
ulimit -n 4096  # 增加文件描述符限制

# 限制每個(gè)進(jìn)程的資源使用
prlimit --nproc=100 --nofile=100 --cpu=10 sshpass ...

安全注意事項(xiàng)

盡管這是測(cè)試腳本,但仍需注意安全:

  • 密碼處理:不要在腳本中硬編碼密碼,考慮使用環(huán)境變量或配置文件
  • 結(jié)果保護(hù):測(cè)試結(jié)果可能包含敏感信息,妥善保管
  • 權(quán)限控制:腳本應(yīng)運(yùn)行在受控環(huán)境中
  • 日志清理:定期清理日志文件
# 更安全的方式:從環(huán)境變量讀取密碼
PASSWORD=${SSH_PASSWORD:-'default_password'}

# 或者從加密文件讀取
if [ -f ~/.ssh_test_pass ]; then
    PASSWORD=$(openssl enc -d -aes-256-cbc -in ~/.ssh_test_pass)
fi

擴(kuò)展功能

1. 添加重試機(jī)制

test_with_retry() {
    local ip=$1
    local max_retries=2
    
    for ((i=1; i<=max_retries; i++)); do
        if test_single_ip "$ip"; then
            return 0
        fi
        sleep 1
    done
    return 1
}

2. 收集系統(tǒng)信息

# 測(cè)試時(shí)順便收集信息
collect_info() {
    local ip=$1
    sshpass -p "$PASSWORD" ssh root@"$ip" "
        echo '=== 系統(tǒng)信息 ==='
        uname -a
        echo ''
        echo '=== 內(nèi)存信息 ==='
        free -h
        echo ''
        echo '=== 磁盤(pán)信息 ==='
        df -h
    " > "info_${ip}.txt" 2>/dev/null
}

3. 生成HTML報(bào)告

generate_html_report() {
    cat > report.html << EOF
<html>
<head>
    <title>SSH測(cè)試報(bào)告</title>
    <style>
        table { border-collapse: collapse; width: 100%; }
        th, td { border: 1px solid #ddd; padding: 8px; }
        th { background-color: #f2f2f2; }
        .success { background-color: #dff0d8; }
        .failed { background-color: #f2dede; }
    </style>
</head>
<body>
    <h1>SSH連接測(cè)試報(bào)告</h1>
    <p>生成時(shí)間: $(date)</p>
    <p>總計(jì): $total_ips 個(gè)IP</p>
    <p>成功: $success 個(gè)</p>
    <p>失敗: $failed 個(gè)</p>
    
    <h2>成功IP列表</h2>
    <table>
        <tr><th>序號(hào)</th><th>IP地址</th></tr>
        $(cat success.txt | awk '{print "<tr class=\"success\"><td>"NR"</td><td>"$1"</td></tr>"}')
    </table>
</body>
</html>
EOF
}

總結(jié)與建議

經(jīng)過(guò)這次實(shí)戰(zhàn),我總結(jié)了以下經(jīng)驗(yàn):

核心原則

  • 簡(jiǎn)單可靠勝過(guò)復(fù)雜先進(jìn):先確?;A(chǔ)功能穩(wěn)定
  • 逐步增強(qiáng):從簡(jiǎn)單版本開(kāi)始,逐步添加功能
  • 充分測(cè)試:小范圍測(cè)試驗(yàn)證后再批量運(yùn)行
  • 錯(cuò)誤處理:預(yù)見(jiàn)到可能的問(wèn)題并提前處理

技術(shù)建議

  • 使用set -euo pipefail讓腳本更健壯
  • 總是驗(yàn)證輸入數(shù)據(jù)的有效性
  • 為長(zhǎng)時(shí)間運(yùn)行的任務(wù)添加進(jìn)度反饋
  • 使用臨時(shí)文件處理并發(fā)寫(xiě)入問(wèn)題
  • 清理臨時(shí)文件和資源

運(yùn)維建議

  • 保持腳本的日志記錄能力
  • 考慮添加監(jiān)控和告警機(jī)制
  • 定期回顧和優(yōu)化腳本
  • 文檔化腳本的使用和維護(hù)方法

批量測(cè)試SSH連接雖然看起來(lái)簡(jiǎn)單,但實(shí)際實(shí)施時(shí)會(huì)遇到各種預(yù)料之外的問(wèn)題。通過(guò)系統(tǒng)的分析和逐步的改進(jìn),我們最終得到了一個(gè)穩(wěn)定、高效、功能完善的解決方案。這個(gè)過(guò)程不僅解決了眼前的問(wèn)題,也為類(lèi)似任務(wù)積累了寶貴經(jīng)驗(yàn)。

記住:好的自動(dòng)化腳本不是一蹴而就的,而是在不斷遇到問(wèn)題、解決問(wèn)題的過(guò)程中逐漸完善起來(lái)的。每個(gè)錯(cuò)誤和調(diào)試過(guò)程都是學(xué)習(xí)和提高的機(jī)會(huì)。

到此這篇關(guān)于SSH高效實(shí)現(xiàn)批量連接服務(wù)器的最佳實(shí)踐與避坑指南的文章就介紹到這了,更多相關(guān)SSH批量連接服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

蒲江县| 沅陵县| 济阳县| 衡南县| 绩溪县| 商南县| 镶黄旗| 绥芬河市| 科尔| 方山县| 逊克县| 连平县| 长宁县| 思南县| 北流市| 临朐县| 高要市| 博兴县| 卫辉市| 茌平县| 曲阳县| 毕节市| 溆浦县| 平陆县| 拉萨市| 义马市| 泾源县| 潍坊市| 宁夏| 瑞昌市| 通辽市| 安化县| 文化| 铜鼓县| 托里县| 西昌市| 彰化县| 桦甸市| 封丘县| 花垣县| 襄城县|