行工具與巡檢實(shí)踐)
簡(jiǎn)介T(mén)entakel是一款面向系統(tǒng)管理員和運(yùn)維工程師的集群批量操作工具能夠?qū)Τ砂偕锨€(gè)分布式節(jié)點(diǎn)并發(fā)執(zhí)行命令、腳本和自動(dòng)化任務(wù)適用于服務(wù)器批量更新、軟件部署、系統(tǒng)升級(jí)、日志收集等場(chǎng)景顯著降低大規(guī)模集群運(yùn)維的時(shí)間成本與誤操作風(fēng)險(xiǎn)。資源包共110個(gè)文件體積僅547KB以70個(gè)Python腳本為核心目錄結(jié)構(gòu)清晰既包含可讀的源碼實(shí)現(xiàn)也提供配置示例、Markdown及文本說(shuō)明、Makefile與打包部署文件配合man幫助頁(yè)、變更記錄等完整參考資料便于閱讀、二次開(kāi)發(fā)或快速部署。目前已有713人學(xué)習(xí)下載。借助該包可深入了解Tentakel的并發(fā)調(diào)度、SSH密鑰認(rèn)證、任務(wù)監(jiān)控與錯(cuò)誤報(bào)告、彈性配置及跨平臺(tái)兼容等核心機(jī)制并通過(guò)附帶的配置模板、自動(dòng)化工作流示例結(jié)合自定義調(diào)度策略與權(quán)限控制快速搭建適合自身集群環(huán)境的運(yùn)維平臺(tái)從而提升批量操作效率、可審計(jì)性與系統(tǒng)穩(wěn)定性。1. tentakel 是什么一臺(tái)機(jī)器的命令幾十臺(tái)機(jī)器一起跑tentakel 這個(gè)名字直譯過(guò)來(lái)是“觸手”它要解決的問(wèn)題就是讓你一只手同時(shí)伸進(jìn)幾十臺(tái)機(jī)器。它是一個(gè)輕量的集群批量執(zhí)行工具不裝 agent、不寫(xiě) playbook本質(zhì)上是在本機(jī)把多個(gè) ssh 會(huì)話并行組織起來(lái)把同一條命令撒到一組機(jī)器上再統(tǒng)一收結(jié)果。第一次接手一批機(jī)器時(shí)可以用它快速摸底日常巡檢時(shí)可以用它并行采集狀態(tài)臨時(shí)要改配置、看日志也不用為一個(gè)動(dòng)作去引入一套配置管理平臺(tái)。它適合機(jī)器規(guī)模在幾十臺(tái)這個(gè)量級(jí)、操作以臨時(shí)性和探索性為主的團(tuán)隊(duì)也適合已經(jīng)在用 ansible 但嫌太重、想保留一套輕量通道的熟手。下面內(nèi)容從安裝和最小配置講起逐步拆到分組策略、執(zhí)行節(jié)奏、常見(jiàn)坑最后落成一套可以直接用的巡檢閉環(huán)。2. 把 tentakel 裝起來(lái)并跑通第一組命令從最小配置文件開(kāi)始2.1 安裝前先搞清楚依賴它只是 ssh 的調(diào)度器tentakel 最容易被誤解的一點(diǎn)是大家以為它和被管理機(jī)器之間有某種協(xié)議或服務(wù)。實(shí)際上它什么服務(wù)都不需要你只要保證本機(jī)能用 ssh 連上目標(biāo)機(jī)器tentakel 就能工作。它做的事就是把配置文件里的一組主機(jī)名、和你給的命令翻譯成一批并行發(fā)起的 ssh 調(diào)用然后把各自的輸出收回來(lái)。所以被管理機(jī)器上唯一的依賴是 sshd 和你的登錄賬號(hào)這也就是“無(wú) agent 集群工具”這個(gè)說(shuō)法的來(lái)源。安裝本身不復(fù)雜。先在自己的發(fā)行版包管理器里搜一下apt 系用apt-cache search tentakelrpm 系用yum search tentakel只要軟件源里有直接裝就是。如果源里沒(méi)有也不用著急tentakel 的依賴非常少源碼方式安裝也是常規(guī)三步# 把你拿到的源碼包解壓后進(jìn)入目錄按常規(guī)流程編譯安裝 make make test sudo make install邏輯說(shuō)明make負(fù)責(zé)生成可執(zhí)行文件和默認(rèn)配置模板make test會(huì)在本機(jī)跑一遍最小用例確認(rèn)沒(méi)有環(huán)境問(wèn)題后再make install。參數(shù)說(shuō)明如果你的環(huán)境沒(méi)有 sudo 權(quán)限可以只解壓后把可執(zhí)行文件放到個(gè)人目錄再把 PATH 指過(guò)去不影響使用。安裝后先確認(rèn)版本tentakel --version tentakel --help第一行確認(rèn)裝上了第二行看手頭版本支持哪些參數(shù)。tentakel 不同發(fā)行版的打包會(huì)有細(xì)微差異后面的命令如果和你本機(jī)對(duì)不上以--help的輸出為準(zhǔn)。2.2 第一個(gè)配置文件一個(gè)組、兩( 三)臺(tái)機(jī)器tentakel 的默認(rèn)配置文件是用戶家目錄下的~/.tentakelrc系統(tǒng)級(jí)配置通常在/etc/tentakelrc或/etc/tentakel/下具體路徑看安裝方式。對(duì)個(gè)人使用來(lái)說(shuō)寫(xiě)~/.tentakelrc就夠。格式非常簡(jiǎn)單方括號(hào)是組名下面每行是一個(gè)主機(jī)名cat ~/.tentakelrc EOF [test] web01.internal web02.internal EOF邏輯說(shuō)明[test]定義了一個(gè)叫 test 的組組里有兩臺(tái)主機(jī)web01.internal和web02.internal。tentakel 看到這個(gè)配置后會(huì)把后面你給的命令并行發(fā)到這兩臺(tái)機(jī)器上。參數(shù)說(shuō)明主機(jī)名可以是短主機(jī)名也可以是完整域名或 IP關(guān)鍵是你的 ssh 能直接解析并連接它行首#開(kāi)頭的是注釋會(huì)被忽略。這里有個(gè)很容易忽略的點(diǎn)tentakel 并不會(huì)幫你做 ssh 免密配置所以第一次跑之前先手動(dòng)確認(rèn)一下ssh web01.internal hostname如果這一步需要輸密碼說(shuō)明你后面跑 tentakel 也會(huì)被密碼卡住。先把本機(jī)到目標(biāo)機(jī)器的免密登錄配好再繼續(xù)往下走。2.3 跑第一組命令并看懂輸出配置文件寫(xiě)好、ssh 通路確認(rèn)后第一組命令就可以發(fā)了tentakel test uptimetentakel 會(huì)并行連接 test 組里的兩臺(tái)機(jī)器在各自終端執(zhí)行uptime然后把輸出收回來(lái)。輸出里一般會(huì)帶主機(jī)名標(biāo)識(shí)以便區(qū)分結(jié)果來(lái)自哪臺(tái)機(jī)器具體樣式取決于版本和是否開(kāi)啟了 verbose。如果你手頭版本支持-v參數(shù)可以打開(kāi) verbose 看更詳細(xì)的執(zhí)行狀態(tài)不支持的版本也不用擔(dān)心直接看輸出內(nèi)容即可。tentakel -v test uptime邏輯說(shuō)明test是配置里的組名后面跟的字符串是遠(yuǎn)程要執(zhí)行的命令。整條命令會(huì)被原樣交給遠(yuǎn)程 shell所以帶引號(hào)這個(gè)習(xí)慣要養(yǎng)成避免本機(jī) shell 先把命令拆了。參數(shù)說(shuō)明-v是 verbose 的簡(jiǎn)寫(xiě)它會(huì)把每臺(tái)機(jī)器的連接狀態(tài)、命令執(zhí)行狀態(tài)一并打出來(lái)排查問(wèn)題時(shí)很有用如果你的版本不支持-v運(yùn)行tentakel --help能看到這個(gè)參數(shù)到底叫什么。跑通這一條tentakel 的核心鏈路就通了。接下來(lái)要解決的是另一個(gè)問(wèn)題機(jī)器一多、組一雜配置文件該怎么組織。3. 分組配置再深入按用途拆組、按環(huán)境隔離、先查再跑3.1 三種常用的靜態(tài)分組方式tentakel 的分組模型很樸素一個(gè)組名對(duì)應(yīng)一組主機(jī)名命令行里給組名命令就會(huì)發(fā)到該組的所有機(jī)器上。實(shí)際使用中分組維度通常有三個(gè)按角色拆、按環(huán)境拆、按批次拆。按角色拆是最常見(jiàn)的比如把 Web 服務(wù)器放一個(gè)組、數(shù)據(jù)庫(kù)放一個(gè)組cat ~/.tentakelrc EOF [global] ssh_command ssh -o ConnectTimeout5 -o BatchModeyes [webservers] web01.internal web02.internal web03.internal [dbservers] db01.internal db02.internal [all] web01.internal web02.internal web03.internal db01.internal db02.internal EOF邏輯說(shuō)明[global]段是全局參數(shù)ssh_command指定 tentakel 調(diào)用 ssh 時(shí)用的命令模板。這里給 ssh 加了兩個(gè)參數(shù)ConnectTimeout5讓連接階段 5 秒超時(shí)BatchModeyes禁止交互式輸入密碼、失敗就立刻返回避免批量執(zhí)行時(shí)掛在密碼輸入上。參數(shù)說(shuō)明BatchModeyes不適用于你還沒(méi)配好免密的場(chǎng)景它只是讓故障快速暴露不是讓故障消失。按環(huán)境拆則是把生產(chǎn)、測(cè)試、演練機(jī)器分開(kāi)維護(hù)避免誤操作范圍擴(kuò)大。按批次拆適合你臨時(shí)要處理一批特定機(jī)器的情況比如升級(jí)只覆蓋部分機(jī)器時(shí)單獨(dú)建一個(gè)臨時(shí)組用完就刪。這三種拆法可以疊加角色組管職責(zé)環(huán)境組管邊界批次組管變化。3.2 用不同配置文件隔離生產(chǎn)與測(cè)試環(huán)境如果所有環(huán)境寫(xiě)在一個(gè)~/.tentakelrc里最大的風(fēng)險(xiǎn)就是手抖想對(duì) test 組執(zhí)行命令結(jié)果組名敲成了 prod。tentakel 支持通過(guò)-c參數(shù)指定配置文件所以更穩(wěn)妥的做法是為每個(gè)環(huán)境維護(hù)一套獨(dú)立配置。cat ~/.tentakelrc.prod EOF [app] app01.corp.internal app02.corp.internal EOFcat ~/.tentakelrc.staging EOF [app] stg01.corp.internal stg02.corp.internal EOF# 需要操作哪個(gè)環(huán)境就顯式指名配置文件避免默認(rèn)配置里混著多個(gè)環(huán)境 tentakel -c ~/.tentakelrc.prod app uptime tentakel -c ~/.tentakelrc.staging app uptime邏輯說(shuō)明-c接受一個(gè)配置文件路徑tentakel 啟動(dòng)時(shí)讀這個(gè)文件而不是默認(rèn)的~/.tentakelrc。這樣一來(lái)生產(chǎn)配置和測(cè)試配置物理隔離命令行里也能一眼看出當(dāng)前操作的是哪個(gè)環(huán)境。參數(shù)說(shuō)明-c的具體拼寫(xiě)如果在你本機(jī)版本里不是這個(gè)運(yùn)行tentakel --help確認(rèn)一下但絕大多數(shù)打包版本都支持這個(gè)參數(shù)。這個(gè)習(xí)慣很重要。我見(jiàn)過(guò)不止一次有人在測(cè)試環(huán)境執(zhí)行命令時(shí)因?yàn)槟J(rèn)配置里同時(shí)存在 prod 和 test 兩組組名寫(xiě)錯(cuò)一位就發(fā)到了生產(chǎn)機(jī)器上。用配置文件把環(huán)境隔開(kāi)是從源頭降低批量操作風(fēng)險(xiǎn)的手段。3.3 執(zhí)行前先檢查分組別讓同一臺(tái)機(jī)器跑兩遍配置文件用久了主機(jī)名會(huì)重復(fù)。比如 all 組里手動(dòng)維護(hù)了全量機(jī)器webservers 和 dbservers 里也有同樣的主機(jī)一旦你在命令行里同時(shí)指定多個(gè)組同一臺(tái)機(jī)器可能被執(zhí)行兩次這在執(zhí)行重啟、停服務(wù)這類操作時(shí)就是事故。所以我的習(xí)慣是改完配置先檢查再跑命令。# 列出配置里所有組名 awk -F[][] /^\[/{print $2} ~/.tentakelrc這個(gè)命令把配置里所有[...]形式的行截出來(lái)顯示當(dāng)前有哪些組。接著檢查主機(jī)有沒(méi)有重復(fù)# 統(tǒng)計(jì)所有主機(jī)名出現(xiàn)次數(shù)次數(shù)大于 1 就說(shuō)明有重復(fù) grep -v ^# ~/.tentakelrc | grep -v ^\[ | grep -v ^$ | sort | uniq -c | sort -rn邏輯說(shuō)明先把注釋、組名行和空行全部過(guò)濾掉剩下的都是主機(jī)名然后排序、去重統(tǒng)計(jì)最后按出現(xiàn)次數(shù)倒序排列。如果看到某個(gè)主機(jī)名前面的數(shù)字大于 1就說(shuō)明它在配置里出現(xiàn)了多次。參數(shù)說(shuō)明uniq -c是在排序基礎(chǔ)上統(tǒng)計(jì)連續(xù)重復(fù)行所以必須先sortsort -rn讓重復(fù)次數(shù)最多的排在最上面一眼就能看到問(wèn)題主機(jī)。在第 3 章的最后留一個(gè)建議如果 tentakel 的版本支持在組里引用其他組比如[all:include]這種寫(xiě)法優(yōu)先用引用而不是手動(dòng)把主機(jī)再抄一遍。手動(dòng)維護(hù)的重復(fù)列表遲早會(huì)在一次變更中漏掉某臺(tái)機(jī)器。手頭版本不支持也沒(méi)關(guān)系那就靠上面這個(gè)檢查命令兜底。4. 執(zhí)行節(jié)奏與輸出處理并行執(zhí)行怎么不翻車4.1 先懂 tentakel 的并行模型再?zèng)Q定要不要拆組tentakel 默認(rèn)是并行執(zhí)行意思是它不會(huì)等第一臺(tái)機(jī)器跑完才開(kāi)始第二臺(tái)而是把所有目標(biāo)機(jī)器的 ssh 會(huì)話同時(shí)拉起誰(shuí)先出結(jié)果誰(shuí)先顯示。這個(gè)設(shè)計(jì)在機(jī)器少的時(shí)候非常爽二十臺(tái)機(jī)器同時(shí)執(zhí)行幾秒內(nèi)全部返回。但機(jī)器一多、任務(wù)一重并行反而可能翻車所有機(jī)器同時(shí)執(zhí)行高負(fù)載命令監(jiān)控會(huì)告警同時(shí)重啟一個(gè)服務(wù)下游會(huì)出現(xiàn)大量連接錯(cuò)誤幾十臺(tái)機(jī)器同時(shí)涌回輸出終端直接花屏。所以真正的工程問(wèn)題不是“怎么讓它并行”而是“怎么按自己的節(jié)奏控制并行”。在不確定手頭版本是否提供并發(fā)數(shù)限制參數(shù)的情況下我一般用分組輪詢來(lái)控制做法是把一個(gè)大組按角色拆成幾個(gè)小組然后寫(xiě)循環(huán)逐組執(zhí)行# 按 webservers - appservers - dbservers 的順序逐批執(zhí)行每批內(nèi)部并行 for g in webservers appservers dbservers; do echo ${g} tentakel $g uptime done邏輯說(shuō)明循環(huán)體里每次只處理一個(gè)組組內(nèi)機(jī)器并行組與組之間串行。這樣既保留 tentakel 天然并行的優(yōu)點(diǎn)又不會(huì)讓全量機(jī)器在同一秒內(nèi)被命令擊中。參數(shù)說(shuō)明${g}是循環(huán)變量tentakel $g uptime等價(jià)于依次執(zhí)行tentakel webservers uptime、tentakel appservers uptime、tentakel dbservers uptime。如果手頭版本本身支持并發(fā)數(shù)參數(shù)也可以直接傳參但我這里給的拆組方案不依賴任何特殊參數(shù)在所有版本上都成立。4.2 把超時(shí)和密鑰行為統(tǒng)一交給 sshtentakel 本身不負(fù)責(zé)網(wǎng)絡(luò)超時(shí)它把連接這件事交給了 ssh。所以你會(huì)發(fā)現(xiàn)有時(shí)候命令發(fā)出去了終端一直沒(méi)反應(yīng)也不報(bào)錯(cuò)——大概率是某臺(tái)機(jī)器的 ssh 連接卡在了 TCP 層等待超時(shí)。解決思路不是在 tentakel 層面找開(kāi)關(guān)而是把超時(shí)和交互行為在 ssh 層面統(tǒng)一設(shè)置。# 在 ~/.tentakelrc 的 global 段統(tǒng)一給 ssh 傳參 [global] ssh_command ssh -o ConnectTimeout5 -o BatchModeyes這個(gè)配置的意思是tentakel 每次調(diào)用 ssh 時(shí)都會(huì)自動(dòng)帶上這兩個(gè)參數(shù)。ConnectTimeout5讓連接階段 5 秒超時(shí)適用于大多數(shù)內(nèi)網(wǎng)場(chǎng)景BatchModeyes讓 ssh 放棄交互式密碼輸入一旦密鑰失效直接失敗返回。二者合在一起的效果是批量執(zhí)行時(shí)不會(huì)再有一臺(tái)機(jī)器的連接問(wèn)題拖住整個(gè)批次最多 5 秒后報(bào)錯(cuò)你立刻知道哪臺(tái)有問(wèn)題。參數(shù)說(shuō)明ConnectTimeout的值根據(jù)網(wǎng)絡(luò)情況調(diào)整跨機(jī)房、跨地域會(huì)需要更大值同機(jī)房 3 到 5 秒足夠BatchModeyes對(duì)已經(jīng)配好免密的機(jī)器沒(méi)有副作用但如果你還在排查密鑰問(wèn)題先單獨(dú)手動(dòng) ssh 確認(rèn)不要開(kāi)著 BatchMode 去猜原因。4.3 給命令本身加超時(shí)防止遠(yuǎn)程命令永久掛住連接超時(shí)管的是“連不上”的情況但還有一種更隱蔽的場(chǎng)景連接沒(méi)問(wèn)題命令在遠(yuǎn)程機(jī)器上卡住了比如某個(gè)自動(dòng)化腳本在等一個(gè)永遠(yuǎn)等不到的鎖。這種情況下即使 ssh 連接正常命令也不會(huì)返回。處理辦法是在命令前包一層timeout# 每臺(tái)機(jī)器上的命令最多執(zhí)行 15 秒超時(shí)則返回非零狀態(tài) tentakel all timeout 15 sh -c hostname; uptime; df -h / | tail -1邏輯說(shuō)明timeout 15是 Linux 自帶的命令超時(shí)工具15 秒到了就強(qiáng)制終止后面的命令。sh -c ...把多條命令包成一個(gè)整體交給遠(yuǎn)程 shell 執(zhí)行避免分號(hào)在逐層傳參時(shí)被拆壞。參數(shù)說(shuō)明15 秒這個(gè)值要看你命令的預(yù)期耗時(shí)采集系統(tǒng)信息 15 秒足夠跑備份、部署這類長(zhǎng)任務(wù)就別用這么小的值否則會(huì)把正常命令誤殺。這一步和 4.2 的ConnectTimeout是兩層防護(hù)一個(gè)管連接建立一個(gè)管命令執(zhí)行。兩層都設(shè)好批量執(zhí)行才不容易被一兩臺(tái)異常機(jī)器拖住。5. 常見(jiàn)問(wèn)題與避坑五條批量執(zhí)行的血淚經(jīng)驗(yàn)5.1 host key 校驗(yàn)把整個(gè)批次卡死現(xiàn)象第一次在新機(jī)器上跑 tentakel命令發(fā)出去后長(zhǎng)時(shí)間無(wú)響應(yīng)既不報(bào)錯(cuò)也不返回??催M(jìn)程發(fā)現(xiàn) ssh 進(jìn)程都停在那里等輸入。原因目標(biāo)機(jī)器的 host key 不在本機(jī)known_hosts里ssh 默認(rèn)在交互模式下會(huì)詢問(wèn)是否信任BatchMode 沒(méi)開(kāi)的時(shí)候就直接掛住等待。tentakel 不會(huì)替你回答這個(gè)問(wèn)題于是整個(gè)批次卡死。解決批量操作前先把目標(biāo)機(jī)器公鑰收進(jìn)known_hosts或者在 ssh 參數(shù)里放開(kāi)對(duì)新主機(jī)校驗(yàn)的策略。# 把目標(biāo)主機(jī)公鑰一次性寫(xiě)入 known_hosts避免批量時(shí)卡在確認(rèn) ssh-keyscan -T 5 web01.internal web02.internal db01.internal ~/.ssh/known_hosts邏輯說(shuō)明ssh-keyscan主動(dòng)連接目標(biāo)機(jī)器并獲取 host key-T 5是單個(gè)主機(jī)的連接超時(shí)避免某臺(tái)機(jī)器連不上時(shí)卡很久。追加寫(xiě)入known_hosts后就相當(dāng)于提前回答了 ssh 的信任問(wèn)題。注意這里寫(xiě)入的是目標(biāo)機(jī)器的 host key不是你的登錄憑據(jù)不存在泄露密碼的風(fēng)險(xiǎn)。5.2 輸出混在一起事后找不到是哪臺(tái)機(jī)器現(xiàn)象幾十臺(tái)機(jī)器并行執(zhí)行終端刷出一大堆日志行沒(méi)有主機(jī)標(biāo)識(shí)事后想找某臺(tái)機(jī)器的輸出得靠猜。原因并行執(zhí)行時(shí)各臺(tái)機(jī)器的輸出是陸續(xù)返回的如果命令本身沒(méi)有打印主機(jī)名肉眼幾乎無(wú)法分辨哪行屬于哪臺(tái)。解決在命令開(kāi)頭顯式打印主機(jī)名標(biāo)記收尾時(shí)按標(biāo)記切分。推薦這樣寫(xiě)tentakel all echo HOST_START; hostname; echo HOST_END; uptime; df -h / | tail -1邏輯說(shuō)明echo HOST_START是一個(gè)機(jī)器可識(shí)別的分隔標(biāo)記hostname打印當(dāng)前主機(jī)名HOST_END結(jié)束標(biāo)記。之后無(wú)論是肉眼查看還是腳本切分都能準(zhǔn)確把輸出歸到具體機(jī)器。參數(shù)說(shuō)明標(biāo)記字符串不要用太通用的詞比如------這種日志里本身可能出現(xiàn)用HOST_START這種帶語(yǔ)義、不易撞車的標(biāo)記更穩(wěn)妥。5.3 配置文件里一個(gè)空格引發(fā)的“主機(jī)不存在”現(xiàn)象配置改完后運(yùn)行 tentakel報(bào)錯(cuò)說(shuō)某臺(tái)主機(jī)無(wú)法解析或者命令被莫名其妙地分發(fā)到了錯(cuò)誤的目標(biāo)。原因主機(jī)行末尾多了空格或制表符tentakel 解析時(shí)把空格后的內(nèi)容也當(dāng)成了主機(jī)名的一部分或者注釋符號(hào)沒(méi)放在行首在主機(jī)行后面跟了注釋文本。這兩種情況都不會(huì)在配置加載時(shí)立即報(bào)錯(cuò)但執(zhí)行時(shí)就會(huì)出問(wèn)題。解決統(tǒng)一配置文件格式主機(jī)行只寫(xiě)主機(jī)名注釋單獨(dú)一行改完配置后用檢查命令過(guò)濾出實(shí)際參與執(zhí)行的主機(jī)清單。# 把配置里真正會(huì)被當(dāng)成主機(jī)名的行全部打出來(lái)人工掃一遍 grep -v ^# ~/.tentakelrc | grep -v ^\[ | grep -v ^$邏輯說(shuō)明過(guò)濾掉注釋、組名和空行后剩下的每一行就是 tentakel 會(huì)當(dāng)作主機(jī)名的內(nèi)容。如果這里出現(xiàn)帶空格的行或者明顯不是主機(jī)名的字符串就是配置解析的根源。參數(shù)說(shuō)明這個(gè)命令只是檢查不修改配置發(fā)現(xiàn)問(wèn)題后直接用編輯器修掉行尾空格不要試圖在配置文件里用引號(hào)包主機(jī)名tentakel 的解析器不認(rèn)那套。5.4 免密登錄偶爾失效BatchMode 是最后的后悔藥現(xiàn)象某天批量執(zhí)行時(shí)幾臺(tái)機(jī)器突然開(kāi)始提示輸入密碼終端切換不了輸入框整個(gè)批次像被凍住一樣強(qiáng)殺后那幾臺(tái)機(jī)器也沒(méi)有返回任何輸出。原因ssh-agent 里密鑰沒(méi)有加載或者目標(biāo)機(jī)器的authorized_keys被動(dòng)過(guò)ssh 回退到了密碼認(rèn)證。tentakel 不會(huì)感知到這一點(diǎn)它會(huì)繼續(xù)等。解決平時(shí)就打開(kāi)BatchModeyes讓認(rèn)證失敗快速返回錯(cuò)誤而不是無(wú)聲等待同時(shí)養(yǎng)成批量操作前先驗(yàn)證密鑰加載的習(xí)慣。# 檢查當(dāng)前 ssh-agent 里已加載的密鑰數(shù)量 ssh-add -l如果輸出顯示The agent has no identities說(shuō)明本機(jī)沒(méi)加載密鑰tentakel 自然也拿不到免密通道。這不是玄學(xué)基本上每次批量免密失效都能追溯到 ssh-agent 或目標(biāo)機(jī)authorized_keys其中一環(huán)。BatchModeyes的作用是把這個(gè)故障從“掛起”變成“快速報(bào)錯(cuò)”你會(huì)在幾秒內(nèi)看到哪臺(tái)機(jī)器認(rèn)證失敗而不是等一根看不到頭的進(jìn)度條。5.5 sudo 和別名讓同一命令在不同機(jī)器上結(jié)果不同現(xiàn)象同一個(gè)命令在 A 機(jī)器上正常在 B 機(jī)器上報(bào)sudo: no tty present在 C 機(jī)器上跑出來(lái)的結(jié)果格式不一樣。原因遠(yuǎn)程機(jī)器默認(rèn)不分配偽終端sudo 在無(wú) tty 環(huán)境下默認(rèn)拒絕另外各機(jī)器的 shell 別名、默認(rèn) PATH 不同命令解釋結(jié)果自然不同。這三類問(wèn)題疊加在一起會(huì)出現(xiàn)“命令看著一樣、執(zhí)行結(jié)果各不相同”的詭異局面。解決需要 sudo 時(shí)給 ssh 加-tt強(qiáng)制分配偽終端命令內(nèi)部用sudo -n禁止交互式輸密碼避免在批量命令里依賴別名或相對(duì)路徑。# 配置里給 ssh 加 -tt命令里用 sudo -n ssh_command ssh -tt -o ConnectTimeout5 -o BatchModeyestentakel all sudo -n systemctl status nginx邏輯說(shuō)明-tt強(qiáng)制分配偽終端滿足 sudo 對(duì) tty 的依賴sudo -n表示非交互模式如果 sudo 需要密碼就立刻失敗不會(huì)卡住。參數(shù)說(shuō)明如果有些機(jī)器不需要 sudo 而有些需要建議拆成兩個(gè)組分別執(zhí)行而不是在同一組里混合 sudo 和非 sudo 命令這樣失敗的范圍更可控。6. 進(jìn)階讓 tentakel 成為日常巡檢的第一入口6.1 巡檢腳本模板帶主機(jī)標(biāo)記、可落盤(pán)、可核對(duì)tentakel 的價(jià)值體現(xiàn)在單點(diǎn)命令真正產(chǎn)生效率的是把它封裝進(jìn)日常巡檢流程。下面是我一直在用的一個(gè)模板它解決了三件事結(jié)果按主機(jī)切分、落到獨(dú)立文件便于排查、執(zhí)行后能核對(duì)主機(jī)數(shù)量。#!/usr/bin/env bash # 巡檢腳本tentakel 作為入口采集結(jié)果并按主機(jī)歸檔 set -uo pipefail GROUP${1:-all} TS$(date %Y%m%d_%H%M%S) DIR/tmp/ops_${TS} mkdir -p $DIR tentakel $GROUP \ echo HOST_START; hostname; echo HOST_END; uptime; df -h / | tail -1; free -m | head -2 \ $DIR/raw.log 21 awk /HOST_START/ {getline host; next} /HOST_END/ {print host; next} {print host | $0} $DIR/raw.log $DIR/parsed.log online$(grep -c HOST_START $DIR/raw.log) parsed$(grep -c ^HOSTNAME: $DIR/parsed.log) echo reachable hosts: ${online}, parsed: ${parsed}邏輯說(shuō)明腳本先把 tentakel 原始輸出落盤(pán)到帶時(shí)間戳的目錄然后用 awk 按HOST_START和HOST_END標(biāo)記切分把后續(xù)每行輸出都打上主機(jī)名前綴。最后統(tǒng)計(jì)在線主機(jī)數(shù)和解析出的主機(jī)數(shù)兩者不一致就說(shuō)明有機(jī)器沒(méi)跑完或有輸出被截?cái)?。參?shù)說(shuō)明set -uo pipefail防止未定義變量和管道錯(cuò)誤被靜默吞掉${1:-all}表示腳本第一個(gè)參數(shù)傳入組名不傳默認(rèn)用 all 組awk 里的getline host取到的是 hostname 命令的輸出行通常形如HOSTNAME: web01.internal所以后面用^HOSTNAME:匹配。6.2 用 SSH 證書(shū)機(jī)制免去逐臺(tái)部署公鑰機(jī)器數(shù)量少時(shí)ssh-copy-id逐臺(tái)部署公鑰可以接受但機(jī)器一多逐臺(tái)部署本身就是一件該被自動(dòng)化的事。最可靠的批量免密方案是用 SSH 證書(shū)機(jī)制本機(jī)持有一個(gè) CA 簽發(fā)的用戶證書(shū)目標(biāo)機(jī)器信任該 CA每次登錄自動(dòng)通過(guò)驗(yàn)證不需要在每臺(tái)機(jī)器上維護(hù)公鑰列表。tentakel 不需要感知證書(shū)的存在它只負(fù)責(zé)調(diào) ssh認(rèn)證邏輯完全由 ssh 層接管。這個(gè)方案的好處是換密鑰、加機(jī)器都不用在目標(biāo)機(jī)器上動(dòng)手適合跟 tentakel 配合做常態(tài)化巡檢。6.3 跑完怎么驗(yàn)證數(shù)量核對(duì)與失敗重跑巡檢腳本最后的數(shù)字核對(duì)就是驗(yàn)證手段。reachable hosts是 tentakel 實(shí)際連接到的主機(jī)數(shù)如果這個(gè)數(shù)少于配置里的主機(jī)總數(shù)說(shuō)明有機(jī)器 ssh 不通或認(rèn)證失敗去raw.log里搜錯(cuò)誤信息即可定位。失敗重跑時(shí)不需要重新跑全量把失敗的主機(jī)單獨(dú)建一個(gè)臨時(shí)組或直接用-c指定一個(gè)只含失敗主機(jī)的小配置文件補(bǔ)跑一次即可。我現(xiàn)在的習(xí)慣是tentakel 只負(fù)責(zé)把命令送到、把結(jié)果帶回來(lái)命令靠標(biāo)記切分故障靠數(shù)量核對(duì)免密靠證書(shū)機(jī)制不靠碰運(yùn)氣。把這三件事想清楚之后批量操作就不再是提心吊膽的“一把梭”而是一套隨時(shí)可以解釋、可以復(fù)盤(pán)、可以重跑的流程。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取