我們之前有個 Jenkins CI/CD 的導入顧問案,由於客戶是政府部門,客戶端的防火牆已經設定了無法連接到任何中國大陸的 IP 或 URL,但是 Jenkins 的更新伺服器預設會判定來自台灣的 IP 全部導向到清华大学的 Jenkins Mirror 伺服器,因此當你要安裝或更新 Plugins 外掛的時候,一定會連線失敗。也因為這樣,客戶那邊的 Jenkins Plugins 都將無法自動更新!不僅如此,安裝新的 Plugins 時通常也需要一併安裝相依外掛,因此各種困難接踵而來。這篇文章我將說明我們是如何解決這個難題的!
使用 Docker 安裝與啟動 Jenkins 最新版本
-
取得最新版 jenkins/jenkins:lts
image
docker pull jenkins/jenkins:lts
-
建立 jenkins-data
volume 用來保存 Jenkins 所有設定
docker volume create jenkins-data
-
啟動 Jenkins 容器
docker run -d --name jenkins -p 8080:8080 -p 50000:50000 -v jenkins-data:/var/jenkins_home jenkins/jenkins:lts
注意:Port 8080
是 Jenkins 預設 Web 介面。Port 50000
則是用來讓 Jenkins Agent 建立連線的 Port 埠號。
注意:請勿加上 --rm
參數,因為我們在安裝 Plugins 的過程中需要重新啟動 Jenkins 容器。
-
取得預設管理者密碼(initialAdminPassword
)
docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword | clip
Windows 10 有內建一個 C:\Windows\System32\clip.exe
執行檔,可以將 Console 輸出直接放入「剪貼簿」中,對於複製 Jenkins 預設管理者密碼非常方便!👍
-
啟動 Jenkins 介面
start http://localhost:8080/
因為步驟 4 已經複製了預設管理者密碼,所以直接 Ctrl-V
貼上即可登入成功!
模擬 Jenkins 無法連接中國大陸鏡像伺服器的狀況
因為 Jenkins 在下載任何 Plugins 時,都會連到 mirrors.tuna.tsinghua.edu.cn 域名,因此我打算將這個域名設定為無法連線,藉此模擬客戶端無法連線的狀況:
docker exec -it -u root jenkins bash
echo "127.0.0.1 mirrors.tuna.tsinghua.edu.cn" > /etc/hosts
首次啟動請跳過所有 Plugins 安裝的過程
-
在首次安裝的時候,你就可以選取 Select plugins to install 按鈕
-
請按下 None 取消所有建議外掛的安裝步驟
改用 jenkins-plugin-cli
安裝 Plugins 外掛
如果你是使用 Docker 執行 Jenkins 伺服器,可以直接使用內建的 /bin/jenkins-plugin-cli
來管理 Plugins 的安裝與執行。如果是其他的安裝方式,就要到 Plugin Installation Manager Tool for Jenkins 下載 jenkins-plugin-manager-*.jar
檔案 (jenkins-plugin-manager-2.9.2.jar) 來執行。
這裡最重要的步驟,就是設定一個 JENKINS_UC_DOWNLOAD
環境變數,並指向到一個可用的 Jenkins Mirror Sites (Jenkins 鏡像伺服器)。
目前官方維護的 Jenkins Mirror Sites 有分三個區域,截至今日為止可用的站台與網址如下:
- cn (中國大陸)
- http://mirrors.tuna.tsinghua.edu.cn/jenkins/
- jp (日本)
- http://ftp.yz.yamagata-u.ac.jp/pub/misc/jenkins/
- http://mirror.esuni.jp/jenkins/
- us (美國)
- ftp://mirror.xmission.com/jenkins/
- http://mirror.xmission.com/jenkins/
- http://archives.jenkins-ci.org/
- ftp://ftp-chi.osuosl.org/pub/jenkins/
- http://ftp-chi.osuosl.org/pub/jenkins/
要正確設定 JENKINS_UC_DOWNLOAD
環境變數的值,必須從 Jenkins Mirror Sites 複製正確的網址才行!
-
我們先進入 Jenkins 容器中
docker exec -it jenkins bash
-
先執行以下命令安裝 Folders 外掛
jenkins-plugin-cli --verbose -d $JENKINS_HOME/plugins/ --plugins cloudbees-folder
注意:請務必加上 -d $JENKINS_HOME/plugins/
參數,明確指定 Jenkins Plugins 安裝的資料夾!
此時你應該可以看見 Unable to resolve plugin URL
的錯誤,也可以看到 Tried downloading cloudbees-folder from https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi
的錯誤訊息:
No .txt or .yaml file containing list of plugins to be downloaded entered.
Plugin download location: /var/jenkins_home/plugins
Using update center https://updates.jenkins.io/update-center.json from JENKINS_UC environment variable
Using experimental update center https://updates.jenkins.io/experimental/update-center.json from JENKINS_UC_EXPERIMENTAL environment variable
Using incrementals mirror https://repo.jenkins-ci.org/incrementals from JENKINS_INCREMENTALS_REPO_MIRROR environment variable
No CLI option or environment variable set for plugin info, using default of https://updates.jenkins.io/plugin-versions.json
No war entered. Will use default of /usr/share/jenkins/jenkins.war
Retrieving update center information
Returning cached value for: update-center-2.277.3
Returning cached value for: experimental-update-center-2.277.3
Returning cached value for: plugin-versions
Couldn't find checksum for cloudbees-folder at version: latest
cloudbees-folder depends on:
credentials 2.3.18
Setting checksum for: cloudbees-folder to vqUU9iK9k3WlVkbwGJ9sqBGVeQ+1kpm4dykagSSO07Q=
Setting checksum for: cloudbees-folder to vqUU9iK9k3WlVkbwGJ9sqBGVeQ+1kpm4dykagSSO07Q=
Will install new plugin cloudbees-folder 6.15
Will use url: https://updates.jenkins.io/download/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi to download cloudbees-folder plugin
Unable to resolve plugin URL https://updates.jenkins.io/download/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi, or download plugin cloudbees-folder to file
Tried downloading cloudbees-folder from https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi
Unable to resolve plugin URL https://updates.jenkins.io/download/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi, or download plugin cloudbees-folder to file
Tried downloading cloudbees-folder from https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi
Unable to resolve plugin URL https://updates.jenkins.io/download/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi, or download plugin cloudbees-folder to file
Tried downloading cloudbees-folder from https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi
Downloaded file is not a valid ZIP
java.io.FileNotFoundException: /tmp/plugin-installation-manager-downloads2553358770239004420/cloudbees-folder.jpi (No such file or directory)
at java.util.zip.ZipFile.open(Native Method)
at java.util.zip.ZipFile.<init>(ZipFile.java:225)
at java.util.zip.ZipFile.<init>(ZipFile.java:155)
at java.util.jar.JarFile.<init>(JarFile.java:166)
at java.util.jar.JarFile.<init>(JarFile.java:130)
at io.jenkins.tools.pluginmanager.impl.PluginManager.downloadToFile(PluginManager.java:1276)
at io.jenkins.tools.pluginmanager.impl.PluginManager.downloadToFile(PluginManager.java:1198)
at io.jenkins.tools.pluginmanager.impl.PluginManager.downloadPlugin(PluginManager.java:1127)
at io.jenkins.tools.pluginmanager.impl.PluginManager.lambda$downloadPlugins$4(PluginManager.java:537)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:401)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:650)
at io.jenkins.tools.pluginmanager.impl.PluginManager.lambda$downloadPlugins$5(PluginManager.java:536)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)
io.jenkins.tools.pluginmanager.impl.DownloadPluginException: Unable to download cloudbees-folder
at io.jenkins.tools.pluginmanager.impl.PluginManager.lambda$downloadPlugins$4(PluginManager.java:542)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:401)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:734)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:485)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:650)
at io.jenkins.tools.pluginmanager.impl.PluginManager.lambda$downloadPlugins$5(PluginManager.java:536)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:175)
Unable to download cloudbees-folder
此時,你只要先設定好 JENKINS_UC_DOWNLOAD
環境變數,就可以順利安裝 Plugins 外掛:
export JENKINS_UC_DOWNLOAD=http://ftp.yz.yamagata-u.ac.jp/pub/misc/jenkins/
jenkins-plugin-cli --verbose -d $JENKINS_HOME/plugins/ --plugins cloudbees-folder
注意:請務必加上 -d $JENKINS_HOME/plugins/
參數,明確指定 Jenkins Plugins 安裝的資料夾!
以下是成功安裝外掛的訊息:
No .txt or .yaml file containing list of plugins to be downloaded entered.
Plugin download location: /var/jenkins_home/plugins
Using update center https://updates.jenkins.io/update-center.json from JENKINS_UC environment variable
Using experimental update center https://updates.jenkins.io/experimental/update-center.json from JENKINS_UC_EXPERIMENTAL environment variable
Using incrementals mirror https://repo.jenkins-ci.org/incrementals from JENKINS_INCREMENTALS_REPO_MIRROR environment variable
No CLI option or environment variable set for plugin info, using default of https://updates.jenkins.io/plugin-versions.json
No war entered. Will use default of /usr/share/jenkins/jenkins.war
Retrieving update center information
Returning cached value for: update-center-2.277.3
Returning cached value for: experimental-update-center-2.277.3
Returning cached value for: plugin-versions
Couldn't find checksum for cloudbees-folder at version: latest
cloudbees-folder depends on:
credentials 2.3.18
Setting checksum for: cloudbees-folder to vqUU9iK9k3WlVkbwGJ9sqBGVeQ+1kpm4dykagSSO07Q=
Setting checksum for: cloudbees-folder to vqUU9iK9k3WlVkbwGJ9sqBGVeQ+1kpm4dykagSSO07Q=
Will install new plugin cloudbees-folder 6.15
Will use url: http://ftp.yz.yamagata-u.ac.jp/pub/misc/jenkins/plugins/cloudbees-folder/6.15/cloudbees-folder.hpi to download cloudbees-folder plugin
Downloaded plugin cloudbees-folder
Checksum valid for: cloudbees-folder
Done
冷知識:這個工具在 Oct 28, 2020 之前一直無法正常使用,直到 Remove '/download' subpath for JENKINS_UC_DOWNLOAD (#213) 這個 commit 才把問題給解決!
-
在確認可以成功安裝之後,就可以批次安裝所有建議的外掛
以下是 Jenkins 預設建議安裝的外掛:
- https://plugins.jenkins.io/cloudbees-folder
- https://plugins.jenkins.io/antisamy-markup-formatter
- https://plugins.jenkins.io/build-timeout
- https://plugins.jenkins.io/credentials-binding
- https://plugins.jenkins.io/timestamper
- https://plugins.jenkins.io/ws-cleanup
- https://plugins.jenkins.io/ant
- https://plugins.jenkins.io/gradle
- https://plugins.jenkins.io/workflow-aggregator
- https://plugins.jenkins.io/github-branch-source
- https://plugins.jenkins.io/pipeline-github-lib
- https://plugins.jenkins.io/pipeline-stage-view
- https://plugins.jenkins.io/git
- https://plugins.jenkins.io/ssh-slaves
- https://plugins.jenkins.io/matrix-auth
- https://plugins.jenkins.io/pam-auth
- https://plugins.jenkins.io/ldap
- https://plugins.jenkins.io/email-ext
- https://plugins.jenkins.io/mailer
其實不只這些外掛會被安裝,而是包含「相依的外掛」也都會全部自動安裝完成!
以下則是我經常安裝的外掛:
- https://plugins.jenkins.io/locale
- https://plugins.jenkins.io/msbuild
我們只要用一個命令,就可以全部安裝完畢:
export JENKINS_UC_DOWNLOAD=http://ftp.yz.yamagata-u.ac.jp/pub/misc/jenkins/
jenkins-plugin-cli -d $JENKINS_HOME/plugins/ --plugins cloudbees-folder antisamy-markup-formatter build-timeout credentials-binding timestamper ws-cleanup ant gradle workflow-aggregator github-branch-source pipeline-github-lib pipeline-stage-view git ssh-slaves matrix-auth pam-auth ldap email-ext mailer locale msbuild
用 jenkins-plugin-cli
安裝 Plugins 不但方便,而且安裝速度極快!
-
重新啟動 Jenkins 伺服器
docker restart jenkins
注意:所有透過 jenkins-plugin-cli
安裝的 Plugins 都需要重啟 Jenkins 伺服器才會生效!
預設的 Jenkins Plugins 路徑
上述技巧是透過直接將 Jenkins Plugins 安裝到指定的目錄下,在 Linux 環境下通常是 $JENKINS_HOME/plugins
目錄。
但是 Windows 環境預設則是依據安裝時設定的啟動身份而有不同的目錄:
-
一般本機帳戶 (Local or Domain users)
C:\Users\[Username]\AppData\Local\Jenkins\.jenkins\plugins
注意:若要使用一般本機帳戶執行 Jenkins 服務,必須先將帳戶授予服務執行權限才行。詳細步驟請參見 Assigning a user account Logon as Service Rights 文章說明。
-
本機系統帳戶 (LocalSystem)
C:\Windows\System32\config\systemprofile\AppData\Local\Jenkins\.jenkins\plugins
相關連結