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

目錄

寫在前面

首先聲明,除非萬不得已,千萬不要在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 [email protected]:/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 [email protected]:/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 [email protected]:/root

終於成功了!!!

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

最後總結

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

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

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

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