由於 Jenkins 安裝成 Windows 服務之後,預設的執行身分會變成 Local System (本機系統) 這個系統帳戶,因此可能會造成某些 Jenkins 外掛發生一些問題,要釐清問題背後的細節,就讓我來細說從頭。
基本上,安裝 Jenkins 有兩種方法:
- 下載 Java Web Archive (.war) 檔 ( jenkins.war ) 並用 JRE 執行程式
- java -jar jenkins.war
- 預設安裝目錄為 %userprofile%\.jenkins
- 下載 Windows Native packages 安裝檔 ( jenkins.msi )
- 點選 setup.exe 或 jenkins.msi 安裝完後就會自動註冊並啟動 Jenkins 服務
- 預設安裝目錄為 %ProgramFiles(x86)%\Jenkins
如果你是用上述第一種方法啟動服務,你也一樣可以透過 Jenkins 管理介面安裝成 Windows 服務,其安裝步驟如下:
安裝完成後,你可以從 Windows 服務管理員看到 jenkins 服務已被成功安裝,登入身分為 Local System (本機系統)
以最小權限執行 Jenkins 服務
由於本機系統帳戶 ( Local System ) 的權限,等同於本機最高權限管理者,因此用這個身分執行 Jenkins 並不是非常安全,如果你擔心這點的話,建議可以先建立一個一般使用者,然後將 jenkins 服務的登入身分改為相對權限較小的一般使用者即可。
如果你在修改登入身分之後無法啟動服務,有可能是 Jenkins 的主目錄沒有給該使用者完全控制的權限,請記得設定 Jenkins 主目錄的資料夾安全性,將目錄的 NTFS 權限設定給該使用者即可正常啟動服務。
在 使用者目錄 ( User Profile ) 下建立設定檔
我們知道有許多命令列工具在執行的時候,都會有一些設定檔被建立在使用者目錄下 ( 預設都會用 %userprofile% 環境變數指令這個路徑 ),例如:
- Git 會讀取 %userprofile%\.gitconfig 設定檔 ( 例如你第一次使用 Git 時都要先設定 user.name 與 user.email 一樣,這兩個設定值就是儲存在這個檔案裡 )
- Npm 會讀取 %userprofile%\.npmrc 設定檔 ( 通常這個檔不會用到,但我在另一篇 如何在強制使用代理伺服器的環境下設定 git, npm, bower, gem, ionic 工具 文章中提到的 設定 npm 使用代理伺服器 就會把設定值儲存在該檔案 )
- Bower 會讀取 %userprofile%\.bowerrc 設定檔
- BabelJS 會讀取 %userprofile%\.babel.json 設定檔
- 以及其他許許多多的工具程式,都有可能將預設設定檔儲存在使用者目錄下。
如果你將 Jenkins 服務執行在自訂的使用者帳戶下,你其實可以很容易得知使用者目錄就在 C:\Users\<使用者名稱>\ 這個路徑下。不過,如果 Windows 服務的登入身分若是 Local System 這個系統帳戶呢?系統帳戶有使用者目錄嗎?事實上是有的!本機系統的預設使用者目錄就在 C:\WINDOWS\system32\config\systemprofile 這裡。因此,如果你想透過 Jenkins 執行自訂的建置步驟時 (執行 Windows 批次指令),記得要將工具所需的設定檔預先設定好,並放置在正確的目錄下才行。
照理說,這個觀念很簡單對吧?!你只要把預設準備好的設定檔複製到系統帳戶的預設使用者目錄就好啦,雖然第一次將設定檔複製進去後就可以正常執行任何命令,不過我卻遇到一個超級詭異的靈異現象!
這個靈異現象,只會出現在當你使用 Local System 帳戶執行 Jenkins 的時候才會發生,欲知詳情請務必看下去。
問題是這樣發生的,當我第一次將 .gitconfig 複製到 C:\WINDOWS\system32\config\systemprofile 目錄下,這時當我想透過 Jenkins 建置步驟執行自訂的 git commit 時,我的 git 可以正確執行,而且他真的讀的到 C:\WINDOWS\system32\config\systemprofile\.gitconfig 設定檔的內容,所以我可以很正常的 commit 版本。
不過,當我用 Notepad++ 編輯該檔案時,我想把原本設定好的 user.name 與 user.email 改掉,我改了,也儲存了,不過我從 Jenkins 去驗證 git 命令執行,他卻一直讀取到我第一次設定的值,我對這個 .gitconfig 檔案,可以開檔、可以存檔,我可以重新開檔,看到的都是我修改後的版本,一切都是那麼的自然,但就是 Jenkins 讀不到我修改後的內容,重開機也不行喔,這根本是標準的靈異現象啊! >"<
好,我決定了,把檔案砍了,然後複製一個全新的檔案進去,完全不同的內容,只是同檔名而已,你猜猜看發生了什麼事?!竟然讀到的檔案內容,還是我之前修改過的那個內容耶,並不是刪掉重建的這個檔案內容,你說這問題夠詭異吧!!! Orz
我大概花了一個半小時想找出這個問題的原因,後來還真的被我找到真正的原因,這次靈異事件背後的兇手就是:WoW64
萬萬沒想到,原來 WoW64 不僅僅是針對 DLL 做 32-bit 應用程式的相容性處理,連所有在 C:\WINDOWS\system32 下的檔案也全都套用相同規則,其規則如下:
- 當你執行 64-bit 應用程式時,只要讀取 C:\WINDOWS\system32 資料夾下的任何內容,預設就是以這個目錄為主。
- 當你執行 32-bit 應用程式時,預設也是會讀取 C:\WINDOWS\system32 資料夾下的任何內容,不過當你要寫入檔案時,預設卻會改用 C:\Windows\SysWOW64 這個目錄為主。
- 當 C:\WINDOWS\system32 資料夾與 C:\Windows\SysWOW64 資料夾下有相同檔名存在時,32-bit 應用程式會讀取 C:\Windows\SysWOW64 資料夾下的檔案,而 64-bit 應用程式會讀取 C:\WINDOWS\system32 資料夾下的檔案。
好死不死,原來 Notepad++ 編輯器就是一套 32-bit 應用程式,而且他沒有 64-bit 版本,所以用 Notepad++ 編輯 C:\WINDOWS\system32 資料夾下任何檔案時 (包含所有子目錄下的檔案),就會遇到這個靈異現象,真是超詭異的啦!
我後來就改用我常用的 Notepad2 或 Windows 內建的 記事本 (Notepad) 編輯該檔案,就可以開啟正確的檔案了! :-)
因為這個狀況,算是讓我徹底了解原來 WoW64 架構是這樣玩的,原本的 WoW64 立意非常單純,就是讓 32-bit 應用程式可以順利且無縫的在 64-bit 的 CPU 架構下正確執行,沒想到卻讓我遇到這個問題,所幸最後還是被我解決了,不然這問題要是給初學者遇到,我想不知道會卡關卡多久!
相關連結