
如果你正在搭Hadoop集群而且第一次執(zhí)行start-dfs.sh就一路綠燈跑完那運氣真的不錯。大部分人的第一次都會卡在同一個地方——腳本走到某個節(jié)點時突然停住終端上冒出一行密碼提示等你手動輸入SSH密碼。明明當(dāng)時已經(jīng)把公鑰拷到所有機器上了為什么還要輸密碼這個問題我在不少集群環(huán)境里見過有的甚至卡了整整一天。Hadoop的啟動腳本不會幫你輸密碼。無論是NameNode去連DataNode還是start-dfs.sh按slaves文件逐個訪問節(jié)點底層都是通過SSH遠(yuǎn)程執(zhí)行命令。只要有一臺機器沒有配好免密整個啟動流程就卡在那里看起來像死機了一樣。這篇內(nèi)容就是針對“Hadoop用戶配置SSH免密登錄”這件事把這套配置的原理、步驟、踩坑點一次性說清楚。1. 為什么Hadoop集群要把SSH免密放在最前面1.1 集群啟動腳本的真實連機邏輯很多人第一次接觸Hadoop時習(xí)慣先把JDK裝好、把Hadoop解壓好、把配置文件改好最后才想起SSH這回事。這個順序其實有點反了。Hadoop的啟動流程是典型的“被動依賴SSH”start-dfs.sh執(zhí)行后腳本會讀取slaves文件或較新版本中的workers文件拿到所有DataNode的地址然后通過SSH逐個遠(yuǎn)程執(zhí)行命令啟動DataNode進(jìn)程。NameNode所在機器也就是主節(jié)點必須能免密登錄到每一個DataNode。SecondaryNameNode如果單獨部署也需要考慮對應(yīng)的免密鏈路。腳本在處理這些連接時完全是非交互的它不會彈出一個窗口讓你輸入密碼而是直接在終端卡住等待標(biāo)準(zhǔn)輸入。在單機偽分布式模式下節(jié)點只有l(wèi)ocalhost一個只需要本機免密即可。但一旦到了三臺、五臺、甚至更多節(jié)點的分布式環(huán)境連接關(guān)系就變成了多對多。有些初次搭建的人只在主節(jié)點上配置了到DataNode的免密忽略了DataNode之間可能存在的互連需求結(jié)果啟動過程照樣卡住。穩(wěn)妥的做法是配置全互信每個節(jié)點都能免密登錄其他所有節(jié)點。這樣無論腳本從哪個節(jié)點發(fā)起連接都不會在密碼輸入這一步停下來。1.2 密鑰認(rèn)證是怎么做到“免密”的SSH免密的核心是非對稱加密也就是密鑰對。每個用戶在自己的家目錄下生成一對密鑰私鑰id_rsa和公鑰id_rsa.pub。私鑰留在本機絕對不對外傳輸公鑰則分發(fā)到所有需要被免密登錄的目標(biāo)機器的~/.ssh/authorized_keys文件里。整個認(rèn)證過程可以簡單理解為主機A要登錄主機B時A的SSH客戶端用私鑰對一段數(shù)據(jù)簽名B收到后用A的公鑰去驗證簽名。簽名驗證通過B就知道對面確實是持有私鑰的A于是直接放行不再索要密碼。這就像你把自己的“通行憑證”復(fù)印件預(yù)先留在門衛(wèi)處下次進(jìn)大門時報個名字、亮出對應(yīng)標(biāo)記門衛(wèi)核對無誤就開門不需要再出示身份證和密碼。這里要注意一個常見誤區(qū)authorized_keys文件里保存的是所有允許登錄這臺機器的用戶的公鑰。如果一臺機器有三個用戶都需要被免密登錄那么這三個用戶的公鑰都會被追加到這個文件里。不同用戶的公鑰是可以共存的互不影響。這也是為什么手動操作時強調(diào)“追加”而不是“覆蓋”一個不小心用重定向覆蓋掉原有內(nèi)容前面配好的免密就全失效了。2. 配置前必須先確認(rèn)的三類基礎(chǔ)項2.1 用戶身份和目錄權(quán)限邊界Hadoop集群運行通常不會直接用root而是創(chuàng)建一個普通用戶比如統(tǒng)一叫hadoop。這樣做的好處是權(quán)限隔離清晰也符合Hadoop社區(qū)的主流操作習(xí)慣。SSH免密是“用戶級”的配置每個用戶有自己的~/.ssh目錄A用戶配置的免密只對A用戶生效換一個用戶登錄根依然需要密碼。在開始之前先確認(rèn)所有節(jié)點上都是用同一個用戶名、同一個家目錄路徑。如果一臺機器上用戶名是hadoop另一臺是hduser哪怕你把公鑰拷過去了SSH依然會去對應(yīng)目標(biāo)用戶的家目錄里找authorized_keys找不到自然要密碼。我在實際環(huán)境中見過很多次這種“用戶名不統(tǒng)一”導(dǎo)致免密失敗的案例。排查時第一件事就是確認(rèn)所有節(jié)點都執(zhí)行了whoami echo $HOME另外還有個隱藏很深的坑目標(biāo)機器上.ssh目錄或authorized_keys文件的權(quán)限不對即使公鑰內(nèi)容完全正確SSH服務(wù)端也會拒絕讀取。權(quán)限要求非常嚴(yán)格chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod 600 ~/.ssh/id_rsa chmod 644 ~/.ssh/id_rsa.pub.ssh目錄權(quán)限如果太寬松比如755SSH服務(wù)端出于安全考慮會直接忽略這個目錄下的授權(quán)文件表現(xiàn)就是免密配置正確但始終要密碼。2.2 主機名與映射規(guī)劃集群環(huán)境下各節(jié)點通常通過主機名互相訪問而不是每次都敲IP。這就涉及兩層一是每臺機器的主機名要設(shè)置好二是/etc/hosts里的映射關(guān)系要正確。主機名設(shè)置建議在配置SSH之前就完成因為后面分發(fā)公鑰、驗證免密時都會用到主機名。如果中途改主機名已生成的known_hosts里會殘留舊主機名的指紋記錄新主機名連接時會出現(xiàn)“Host key verification failed”的報錯多一道處理工序。/etc/hosts里每一行對應(yīng)一條映射192.168.1.10 hadoop-master 192.168.1.11 hadoop-node1 192.168.1.12 hadoop-node2所有節(jié)點上的這個文件要保持一致。如果只改了一臺機器另一臺機器解析不到主機名SSH連接就會直接失敗報錯類似“Could not resolve hostname xxx”。2.3 ssh-keygen的幾個參數(shù)別弄錯生成密鑰對的命令看起來簡單但有幾個參數(shù)直接決定后續(xù)是否順利ssh-keygen -t rsa -P -f ~/.ssh/id_rsa-t rsa指定密鑰算法為RSAHadoop生態(tài)里最常見的用法是RSA兼容性最好。-P 表示passphrase為空也就是私鑰本身不設(shè)密碼短語。這一步很關(guān)鍵——如果給私鑰設(shè)了密碼短語那么每次SSH連接時依然會提示輸入這個短語等于沒有真正實現(xiàn)免密。-f指定生成文件的路徑默認(rèn)就是~/.ssh/id_rsa如果之前生成過執(zhí)行時會詢問是否覆蓋。生成后檢查一下家目錄下是否出現(xiàn)了這兩個文件ls -la ~/.ssh/正常情況下能看到id_rsa和id_rsa.pub。如果目錄不存在可能是用戶的home目錄沒有被正確創(chuàng)建或者ssh-keygen執(zhí)行時被別的方式干擾了。先mkdir -p ~/.ssh再執(zhí)行一次即可。3. 標(biāo)準(zhǔn)環(huán)境下的完整配置流程3.1 生成密鑰對并完成本機免密我會以一個三節(jié)點集群為例來說明一臺主節(jié)點hadoop-master和兩臺DataNodehadoop-node1、hadoop-node2三個節(jié)點都用hadoop用戶。第一步在每臺機器上都登錄hadoop用戶生成自己的密鑰對ssh-keygen -t rsa -P -f ~/.ssh/id_rsa如果機器數(shù)量多可以考慮在控制機上統(tǒng)一生成一對密鑰然后把公鑰分發(fā)到每臺機器私鑰只保留在控制機。這樣所有節(jié)點的免密都由控制機發(fā)起管理上更集中但要注意私鑰的安全保護(hù)。第二步在每臺機器上配置本機免密。本機免密雖然看起來簡單但有實際用處Hadoop腳本有時會連localhost或本機主機名啟動某些輔助進(jìn)程沒有本機免密同樣會卡cat ~/.ssh/id_rsa.pub ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys執(zhí)行后驗證一下ssh localhost ssh hadoop-master如果不報錯、不要求輸密碼說明本機免密完成。3.2 從中心節(jié)點向DataNode分發(fā)公鑰接下來在主節(jié)點上把hadoop-master的公鑰分發(fā)到兩臺DataNode。這里有兩種方式。第一種最省事用ssh-copy-id工具ssh-copy-id -i ~/.ssh/id_rsa.pub hadoophadoop-node1 ssh-copy-id -i ~/.ssh/id_rsa.pub hadoophadoop-node2命令執(zhí)行過程中會要求輸入一次目標(biāo)機器的密碼這是正?,F(xiàn)象。ssh-copy-id會自動把公鑰追加到目標(biāo)機器的~/.ssh/authorized_keys還會順帶處理目錄權(quán)限。整個過程只用一次密碼之后就再也不用了。但有些最小化安裝的系統(tǒng)沒有ssh-copy-id這個命令那就用傳統(tǒng)手動方式cat ~/.ssh/id_rsa.pub | ssh hadoophadoop-node1 mkdir -p ~/.ssh cat ~/.ssh/authorized_keys chmod 600 ~/.ssh/authorized_keys手動方式要注意管道命令里的地址寫的是hadoop-userhadoop-node1這里用戶名換成實際的即可。目標(biāo)機器上如果~/.ssh目錄不存在管道里的mkdir -p會先創(chuàng)建它。這種寫法好處是不需要臨時存儲公鑰文件一條命令把拷貝、追加、改權(quán)限全做了。執(zhí)行完成后在DataNode上單獨看一眼公鑰是否真的追加成功tail -n 1 ~/.ssh/authorized_keys對比主節(jié)點上的id_rsa.pub內(nèi)容應(yīng)該一模一樣。3.3 驗證全鏈路免密是否真的通了配置完成后不要急著啟動Hadoop先在主節(jié)點上把所有目標(biāo)都測一遍ssh hadoop-node1 hostname ssh hadoop-node2 hostname ssh hadoop-node1 ls -la /opt/hadoop每一條命令如果都能直接返回結(jié)果而沒有密碼提示說明這條鏈路是通的。如果返回的是目標(biāo)機器上一個普通命令的執(zhí)行結(jié)果說明SSH已經(jīng)成功連上了目標(biāo)主機并執(zhí)行了遠(yuǎn)程命令。這里提醒一個細(xì)節(jié)ssh hadoop-node1這種寫法默認(rèn)使用當(dāng)前用戶名連接目標(biāo)機器。如果當(dāng)前是hadoop用戶連接過去的目標(biāo)用戶也是hadoop。如果當(dāng)前是其他用戶比如root要記得顯式指定目標(biāo)用戶名ssh hadoophadoop-node1。Hadoop啟動腳本是以運行start-dfs.sh的用戶去連接各節(jié)點的所以最終所有節(jié)點上都必須有和主節(jié)點啟動用戶同名的用戶且公鑰要放在那個同名用戶的authorized_keys里。全互信驗證可以這樣處理在每個節(jié)點上分別執(zhí)行同樣的SSH連接測試確保任意兩個節(jié)點之間都能互相免密。這樣做的好處是后續(xù)執(zhí)行stop-dfs.sh、stop-yarn.sh或者在新版本腳本中涉及節(jié)點間跳轉(zhuǎn)時不會卡住。4. 啟動集群時的常見故障與排查實錄4.1 啟動卡在節(jié)點名處并提示輸入密碼這是最典型的故障。執(zhí)行start-dfs.sh后屏幕上出現(xiàn)了類似這樣的輸出Starting namenodes on [hadoop-master] hadoop-master:然后光標(biāo)停在那里等輸入密碼。出現(xiàn)這種情況先按CtrlC中斷然后按順序排查第一步確認(rèn)公鑰在目標(biāo)機器上的存放位置。用主節(jié)點的hadoop用戶執(zhí)行ssh -v hadoop-node1-v是verbose模式輸出里會顯示嘗試了哪些認(rèn)證方法。如果看到Server accept key之后再沒有下文說明服務(wù)端沒有接受公鑰基本就是authorized_keys的問題。如果看到公鑰路徑被嘗試了但被拒絕優(yōu)先檢查權(quán)限。第二步在目標(biāo)機器上看.ssh目錄和文件的權(quán)限ls -la ~/.ssh/ stat -c %a %n ~/.ssh ~/.ssh/authorized_keys校驗規(guī)則就是之前提到的.ssh必須是700authorized_keys必須是600私鑰是600公鑰可以是644。第三步如果權(quán)限沒問題看SSH服務(wù)端日志。系統(tǒng)日志位置因發(fā)行版而異tail -n 100 /var/log/secure tail -n 100 /var/log/auth.log日志里如果出現(xiàn)Authentication refused或Permission denied會直接告訴你被拒絕的原因。大部分情況都指向授權(quán)文件路徑或權(quán)限。4.2 報錯Host key verification failed這個報錯常見于以下幾種場景系統(tǒng)重裝后主機名沒變但SSH主機密鑰變了之前連接過某IP但后來該IP分配給另一臺機器或者known_hosts里的舊記錄與當(dāng)前主機指紋不匹配。報錯信息一般長這樣WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! Host key verification failed.解決辦法很簡單在發(fā)起連接的本機上把對應(yīng)主機的舊指紋記錄刪掉ssh-keygen -R hadoop-node1這條命令會從~/.ssh/known_hosts里移除指定主機的條目。刪掉后重新連接會再次提示確認(rèn)主機指紋輸入yes即可重新記錄。如果有多臺機器都報這個錯逐個執(zhí)行ssh-keygen -R或者簡單粗暴地處理整個文件rm -f ~/.ssh/known_hosts刪掉后重連所有指紋都會重新建立。第一次連接時的yes確實必不可少Hadoop腳本不會幫你回答這個提示所以建議在正式啟動前手動把所有目標(biāo)都連一遍避免在腳本執(zhí)行時遇到這個交互。4.3 權(quán)限報錯和SELinux干擾有些Linux發(fā)行版默認(rèn)開啟了SELinux如果配置不當(dāng)SSH免密會遇到額外阻礙。典型表現(xiàn)是公鑰文件內(nèi)容完全正確、權(quán)限也對但就是免密不成功。查看審計日志時可以看到SELinux的攔截記錄。我不是建議一遇到問題就去關(guān)閉SELinux但如果在測試環(huán)境里為了快速推進(jìn)搭建進(jìn)度臨時關(guān)閉確實能省很多排查時間setenforce 0不過這個命令只對當(dāng)前會話有效重啟后又會恢復(fù)。要想長期關(guān)閉需要修改配置文件/etc/selinux/config把SELINUXenforcing改成SELINUXdisabled。生產(chǎn)環(huán)境建議保留SELinux但要在安全策略里放行SSH免密相關(guān)操作或者驗證一下問題確實由SELinux引起再做處理。還有一種權(quán)限相關(guān)問題容易被忽略目標(biāo)機器上hadoop用戶的home目錄本身權(quán)限不對。如果home目錄對其他用戶沒有執(zhí)行權(quán)限SSH服務(wù)端在訪問~/.ssh/authorized_keys時也會失敗。常規(guī)情況下home目錄權(quán)限是755或700問題不大但如果有歷史原因改過檢查一下也不會浪費多少時間。4.4 多節(jié)點互信不完整導(dǎo)致的后遺癥在集群運行一段時間后有時會出現(xiàn)一種奇怪的現(xiàn)象單獨執(zhí)行ssh hadoop-node2完全正常但Hadoop腳本跑到某一步就卡住。排查了半天發(fā)現(xiàn)是腳本內(nèi)部會從節(jié)點A跳到節(jié)點B而A到B的免密沒有配置。這類問題最隱蔽因為表面上看“每個節(jié)點都能訪問其他節(jié)點”似乎都配了但實際上可能是單向的或者某些節(jié)點之間的互信漏掉了。給一個簡單的檢查方法在每一個節(jié)點上寫一個循環(huán)測試把集群內(nèi)所有主機名都ping一遍SSH連接for host in hadoop-master hadoop-node1 hadoop-node2; do echo $host: $(ssh $host hostname 21) done如果某個節(jié)點返回的不是主機名而是密碼提示或錯誤說明該節(jié)點到目標(biāo)的鏈路有問題。逐節(jié)點跑一遍很快就能把缺漏的地方找出來。這個循環(huán)在后期擴(kuò)容節(jié)點時特別有用新加一臺DataNode后保證新節(jié)點和所有舊節(jié)點之間都做好互信是整個集群穩(wěn)定啟動的基礎(chǔ)保障。5. 幾個讓集群維護(hù)更順手的個人習(xí)慣5.1 先規(guī)劃主機名再配置免密我實際踩過幾次坑之后現(xiàn)在固定的順序是先規(guī)劃好所有節(jié)點的主機名更新全部/etc/hosts重啟或重新登錄讓主機名生效然后創(chuàng)建統(tǒng)一的Hadoop運行用戶最后才去生成密鑰、分發(fā)公鑰。這個順序一旦固定下來后續(xù)每次擴(kuò)容都按照同樣流程走一遍很少再出現(xiàn)“重啟后免密失效”或“主機名變更后known_hosts報錯”這類問題。5.2 用腳本批量完成公鑰分發(fā)節(jié)點數(shù)量超過五臺時手動一條條執(zhí)行ssh-copy-id太容易出錯。可以寫一個簡單的Shell腳本在控制節(jié)點上批量執(zhí)行for node in hadoop-node1 hadoop-node2 hadoop-node3; do ssh-copy-id -i ~/.ssh/id_rsa.pub hadoop$node done腳本本身沒什么技術(shù)含量但勝在可以重復(fù)執(zhí)行、不會遺漏節(jié)點。如果某些機器遷移了IP重新跑一遍腳本就把公鑰刷過去了。5.3 新節(jié)點加入集群時的兩件套每次給Hadoop集群新增DataNode時只靠復(fù)制舊機器的authorized_keys是不夠的。新節(jié)點自己也需要生成一套密鑰對然后把新節(jié)點的公鑰加入舊節(jié)點的authorized_keys把舊節(jié)點的公鑰加入新節(jié)點的authorized_keys。我通常會在新節(jié)點上先完成本地密鑰生成再把新節(jié)點的公鑰復(fù)制到控制機在控制機上批量分發(fā)到所有舊節(jié)點同時從任何一個舊節(jié)點把它的公鑰復(fù)制到新節(jié)點追加到新節(jié)點的authorized_keys里。最后在新節(jié)點上執(zhí)行一次全節(jié)點免密驗證循環(huán)。整個過程大概多花五分鐘但換來的是后續(xù)啟動集群時零卡頓很值得。5.4 把免密測試寫入集群交接清單如果你負(fù)責(zé)維護(hù)一個別人搭建好的集群接手時不要只看配置文件先把免密鏈路全盤驗證一遍。這個動作花費的時間很少卻是最快發(fā)現(xiàn)遺留隱患的方式。我在接手某些環(huán)境時遇到過這樣的情況表面上看集群運行正常但某臺機器重啟后因為SSH服務(wù)啟動順序的問題免密暫時失效導(dǎo)致后續(xù)操作各種詭異報錯。提前驗一遍心里就有底了。SSH免密本身是個入門級配置但它卻是整個Hadoop集群最容易出問題的前置環(huán)節(jié)之一。很多集群啟動異常、腳本掛起、進(jìn)程起不了根因追到最后都是免密鏈路有缺口。把這件事做得扎實一點后面跑任務(wù)、調(diào)參數(shù)、擴(kuò)節(jié)點才會順。