記一次在Windows10桌面環境搭建Jekins的吐血經歷

nuccch發表於2021-08-14

目錄

寫在前面

首先宣告,除非萬不得已,千萬不要在Windows環境做這個事情,否則就等著各種坑吧。
本人一貫的立場都是堅持用正確的方法做事,顯然在Windows搭建Jenkins這個事情本身並不那麼正確。
之所以有這篇隨筆,也是因為經歷了各種吐血踩坑之後希望留個備忘。當然,如果此文能給閱讀者帶來幫助,那不勝榮幸。

故事背景

最近在做一個簡單的資料採集專案,一開始只有一臺遠端主機,所以每次更新都是本地打包之後直接scp過去,然後再到目標主機上執行指令碼。因為機器只有一臺,做這些動作到也沒覺得不妥,因為就是簡單的幾步操作也犯不著還需要持續整合工具什麼的。但是最近的資料量有所增加,所以必須增加新的遠端主機,所以現在有了2臺機器,每次都是執行檔案上傳,然後再依次登入到每臺主機上執行指令碼。總是頻繁打包更新時花費在這些重複性步驟上的時間累加起來也挺可觀的,於是乎就想搭建一個Jenkins系統做一鍵釋出。
之所以在Windows10環境折騰,是因為公司電腦就只有Windows10,其實在Linux環境操作的話也不會遇到如下這些問題了。

踩坑詳情

第一步:安裝Jekins。

這一步沒有問題,直接到官網下載安裝包:jenkins.msi。
然後一步一步點選安裝完成,由於安裝的是Windows服務包,可以在Windows服務管理視窗中找到Jenkin後執行啟動/停止操作。當然,也可以通過Jenkins自帶的可執行程式來操作。
在Windows控制檯進入到Jenkins安裝目錄,執行如下命令:

jenkins.exe stop | start | restart

第二步:配置專案釋出流程

主要的踩坑都是在這裡遇到的。

踩坑1 shell環境

為了能在Windows環境使用一些Unix/Linux命令,所以需要安裝Cygwin,並新增到Windows環境變數Path中:Path=%Path%:C:\cygwin64\bin\
然後執行如下命令打包程式:tar czvf xxx.tar.gz xxx,該命令在Cygwin命令列介面執行是沒有任何問題的,但是到Jenkin中執行時就會報錯:

Caused: java.io.IOException: Cannot run program "sh"

顯然,Windows下的shell環境是cmd.exe,而上述打包命令並不能直接執行。

解決辦法:
在Jenkins中明確指定shell環境,設定路徑:【Manage Jenkins】->【Configure System】-> 【Shell】,明確指定“Shell executable”,如下圖所示:
Jekins Shell

注意: 雖然安裝Cygwin後也帶了“sh.exe”,但是在Jenkins中設定為“C:\cygwin64\bin\sh.exe”時依然不能執行命令,所以設定為Git客戶端自帶的sh.exe。

踩坑2: 檔案上傳

程式打包完畢之後,需要上傳到遠端主機。
在Linux主機之間傳輸檔案通常通過scp命令實現,於是我也想在Windows上使用scp來做這個事情。
但遺憾的是通過Cygwin並不能安裝scp命令,而微軟PowerShell團隊提供的Win32-OpenSSH專案正好帶了scp命令。
到這裡還算順利,在安裝了Win32-OpenSSH之後可以通過scp命令將檔案傳輸到遠端主機。
但是在執行scp命令時必須輸入密碼,顯然在Jenkins中要實現一鍵部署時是無法執行輸入密碼這個動作的,因此就需要實現本地Windows主機與遠端Linux主機之間的免密傳輸。

我們知道,在Linux主機之間要實現免密傳輸檔案,比如主機L1向主機L2傳輸檔案,只需要將L1主機的公鑰資訊寫在L2的~/.ssh/authorized_keys檔案中即可,具體操作步驟如下:
首先,在主機L1上執行:ssh-keygen -t rsa,然後將L1主機的~/.ssh/id_rsa.pub檔案上傳到L2主機上,並命名為id_rsa_L1.pub
其次,在主機L2上執行:cat id_rsa_L1.pub >> ~/.ssh/authorized_keys
完成上述設定之後,在主機L1上通過scp命令向主機L2傳輸檔案時就可以不用每次都輸入密碼了,這大大簡化了主機之間檔案傳輸的流程,也是在Jenkins中可以實現一鍵部署的關鍵。

但非常遺憾的是,在我的實踐中,這一步並沒有成功!我嘗試了很多次將本地Windows主機的ssh公鑰寫到遠端Linux主機的~/.ssh/authorized_keys檔案中,每次執行scp命令時依然需要手動輸入密碼。
另外,使用Cygwin提供的sshpass命令明確指定密碼也同樣不能成功!
顯然,如果無法避開手動輸入密碼這個步驟,是無法在Jenkins中實現一鍵部署的。
極度崩潰

經過一番搜尋後知道:在Windows環境要實現類似於scp命令的功能,還可以通過一個叫做pscp的命令實現,並且pscp命令有一個-pw選項引數可以指定遠端主機的登入密碼,這樣就可以實現不用手動輸入密碼的效果了。
pscp命令有以下2種方式獲取:
(1)Putty安裝包預設已經帶了pscp.exe程式,所以只需要安裝Putty即可,注意一定要選擇“Windows Installer”安裝包預設才帶pscp.exe。
(2)Gow工具包也預設帶有pscp.exe程式:前面我們說過,在Windows環境要執行一些Unix/Linux命令可以通過安裝Cygwin來實現,但遺憾的是Cygwin中卻不帶pscp.exe,而Gow是另一個包含了大量Unix/Linux命令的工具集,可以作為Cygwin的輕量級替代品來使用。

我選擇了通過安裝Putty來使用pscp命令。
安裝好Putty之後,需要將Putty的安裝路徑新增到Jenkins中,設定路徑:【Manage Jenkins】->【Configure System】-> 【Global properties】-> 【Environment variables】,設定Name為“Path”的變數值,如下圖所示:
Jenkins Path

注意: Putty的安裝路徑只能通過在Jenkins中設定Path變數的方式新增才能生效,而設定在主機的Path變數中並不能生效。

此時,似乎準備工作都已經就緒,可以通過pscp命令傳輸檔案了,於是在Jekins中執行如下命令:

pscp -pw xxx xxxx.tar.gz root@192.168.56.101:/root

但是!卻意外地報錯了:

ssh_init: Network error: Cannot assign requested address
Build step 'Execute shell' marked build as failure
Finished: FAILURE

好氣哦

於是繼續搜尋解決辦法,看到Stack Overflow上有人提過ssh_init: Network error: Cannot assign requested address的問題,需要指定埠。
於是明確指定埠再次執行:

pscp -P 22 -pw xxx xxxx.tar.gz root@192.168.56.101:/root

繼續報錯:

The server's host key is not cached in the registry. You
have no guarantee that the server is the computer you
think it is.
The server's ssh-ed25519 key fingerprint is:
ssh-ed25519 255 74:3b:39:b1:c3:e8:6c:a2:88:46:b1:46:dd:58:e9:5a
If you trust this host, enter "y" to add the key to
PuTTY's cache and carry on connecting.
If you want to carry on connecting just once, without
adding the key to the cache, enter "n".
If you do not trust this host, press Return to abandon the
connection.
Store key in cache? (y/n) Connection abandoned.
Lost connection
Build step 'Execute shell' marked build as failure
Finished: FAILURE

根據提示資訊可以知道,大概是無法確保目標主機是可信任的,需要手動確認(有點類似於在使用scp命令時需要手動輸入密碼的意思)。

由於在Jenkins中執行命令是無法手動參與的,所以繼續尋找解決辦法,同樣在Stack Overflow上看到有人提出相同的疑問:getting-the-servers-host-key-is-not-cached-in-the-registry-when-using-pscp-ex
解決辦法是通過pscp的選項引數-hostkey明確指定遠端主機的指紋資訊(這個指紋資訊就是上述錯誤資訊中提示一段十六進位制串:74:3b:39:b1:c3:e8:6c:a2:88:46:b1:46:dd:58:e9:5a),再次執行命令如下:

pscp -P 22 -pw xxx -hostkey 74:3b:39:b1:c3:e8:6c:a2:88:46:b1:46:dd:58:e9:5a xxxx.tar.gz root@192.168.56.101:/root

終於成功了!!!

到這裡,無需手動輸入密碼的檔案傳輸終於解決了,於是後續的其他配置也都可以順利進行。

最後總結

如下,對在Windows環境執行Unix/Linux命令做一下小小的總結。

第一,在Windows環境中執行Unix/Linux命令可以通過安裝工具集Cygwin或Gow來實現,當然,也有可能還需要安裝OpenSSH。
第二,在Windows環境下的Jenkins執行Unix/Linux命令需要使用Git客戶端提供的sh.exe環境。
第三,在Windows環境下要實現免輸入密碼方式的檔案傳輸,只能使用pscp.exe來實現,並且在Jenkins中執行時還必須明確指定埠(-P 22)和遠端主機的指紋資訊(-hotkey xx:...)。

最後的最後,還是要再次告誡大家,除非萬不得已,千萬不要在Windows環境折騰Unix/Linux命令的事情,坑太多了!
祝你幸福

【參考】
https://stackoverflow.com/questions/62817854/ssh-init-network-error-cannot-assign-requested-address
https://stackoverflow.com/questions/42841923/getting-the-servers-host-key-is-not-cached-in-the-registry-when-using-pscp-ex

相關文章