前端工程化:保姆級教學(xué) Jenkins 部署前端項目
DevOps
提到 Jenkins,想到的第一個概念就是 CI/CD 在這之前應(yīng)該再了解一個概念。
DevOps Development 和 Operations 的組合,是一種方法論,并不特指某種技術(shù)或者工具。DevOps 是一種重視 Dev 開發(fā)人員和 Ops 運維人員之間溝通、協(xié)作的流程。通過自動化的軟件交付,使軟件的構(gòu)建,測試,發(fā)布更加的快捷、穩(wěn)定、可靠。
CI
CI 的英文名稱是Continuous Integration,中文翻譯為:持續(xù)集成。
試想軟件在開發(fā)過程中,需要不斷的提交,合并進行單元測試和發(fā)布測試版本等等,這一過程是痛苦的。持續(xù)集成CI是在源代碼變更后自動檢測、拉取、構(gòu)建的過程。

CD
CD 對應(yīng)兩個概念 持續(xù)交付Continuous Delivery 持續(xù)部署Continuous Deployment
持續(xù)交付
提交交付顧名思義是要拿出點東西的。在 CI 的自動化流程階段后,運維團隊可以快速、輕松地將應(yīng)用部署到生產(chǎn)環(huán)境中或發(fā)布給最終使用的用戶。
從前端的角度考慮,在某些情況下肯定是不能直接通過自動化的方式將最終的 build 結(jié)果直接扔到生產(chǎn)機的。持續(xù)交互就是可持續(xù)性交付供生產(chǎn)使用的的最終 build。最后通過運維或者后端小伙伴進行部署。

持續(xù)部署
作為持續(xù)交付的延伸,持續(xù)部署可以自動將應(yīng)用發(fā)布到生產(chǎn)環(huán)境。

Jenkins 安裝
示例服務(wù)器為 阿里云 CentOS 服務(wù)器。安全組中增加 8080 端口 Jenkins 默認(rèn)占用
Jenkins 安裝大體分兩種方式,一種使用 Docker 另一種則是直接安裝,示例選擇后者。不管使用哪種方式安裝,最終使用層面都是一樣的。 Linux 安裝[1], Docker 安裝[2]
點擊查看Linux安裝過程
# 下載 Jenkins 資源
sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat/jenkins.repo
# 獲取并導(dǎo)入信任 的包制作者的秘鑰
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
# 升級 yum 源中的所有包
sudo yum upgrade
# Jenkins 依賴于 java 所以需要安裝 JDK
sudo yum install java-11-openjdk
# 安裝 Jenkins
sudo yum install jenkins
復(fù)制代碼
如果最終 Jenkins 沒有找到包而導(dǎo)致沒有安裝成功,檢查第一步和第二部執(zhí)行結(jié)果并重新執(zhí)行。
可以使用 systemctl 命令管理 Jenkins 服務(wù) systemctl[3]
# 啟動 Jenkins 服務(wù)
systemctl start jenkins
# 重啟 Jenkins 服務(wù)
systemctl restart jenkins
# 停止 Jenkins 服務(wù)
systemctl stop jenkins
# 查看 Jenkins 服務(wù)狀態(tài)
systemctl status jenkins
復(fù)制代碼
啟動服務(wù)后訪問服務(wù)器地址 + 8080 端口,Jenkins 默認(rèn)為 8080 端口。
Jenkins 使用及 Freestyle 任務(wù)構(gòu)建

首次進入使用 cat /var/lib/jenkins/secrets/initialAdminPassword 查看密碼。
隨后進入插件安裝頁面,暫時安裝系統(tǒng)推薦插件即可。
然后創(chuàng)建用戶

構(gòu)建目標(biāo):拉取 github 代碼
點擊 新建 Item 創(chuàng)建一個 Freestyle Project

在 源碼管理 處選擇 git ,輸入倉庫地址,點擊添加。

輸入 github 賬號和密碼,這里的密碼有時候可能會出現(xiàn)問題,可以使用 token github 如何生成 token ?[4]
配置只是一方面,同時服務(wù)器也要具備 git 環(huán)境。 yum install git

構(gòu)建目標(biāo):部署到本機
部署前端項目肯定是離不開 nginx 的。 yum install nginx。
安裝完成后同樣可以使用 systemctl 命令管理 nginx 服務(wù)。
nginx 具體配置這里就不說了。本示例項目中,靜態(tài)文件托管目錄為 /usr/share/nginx/html/dist。
接著來到 Jenkins 這里。想要部署前端項目還需要依賴一個 Node 環(huán)境,需要在 Manage Jenkins -> Manage Plugins 在可選插件中搜索 nodejs 選擇對應(yīng)插件進行安裝,安裝完成后需要重啟才會生效。

然后到 系統(tǒng)管理 -> 全局工具配置 中配置 Node (吐槽:沒有安裝任何插件時系統(tǒng)管理以及其子頁面全是英文,安裝完插件后又變成了中文。這國際化不知道是系統(tǒng)原因還是它的原因 ??)。

隨后去修改剛才創(chuàng)建的任務(wù)。在 構(gòu)建環(huán)境 中會多出一個選項 Provide Node & npm bin/ folder to PATH 勾選即可。然后在 構(gòu)建 中選擇 增加構(gòu)建步驟 -> 執(zhí)行 shell 輸入打包發(fā)布相關(guān)的命令。Jenkins 會逐行執(zhí)行。
npm install yarn -g
yarn install
yarn build
# 打包 build 后的文件
tar -zcvf dist.tar.gz dist/
# 刪除 build 后的文件
rm -rf dist/
# 移動 build 后的壓縮包到 nginx 托管目錄下。
sudo mv dist.tar.gz /usr/share/nginx/html
# 進入托管目錄下
cd /usr/share/nginx/html
# 解壓
sudo tar -zxcf dist.tar.gz
# 刪除壓縮包
sudo rm -rf dist.tar.gz
復(fù)制代碼
由于項目構(gòu)建時是在 Jenkins的工作目錄下執(zhí)行腳本,會出現(xiàn)權(quán)限問題。導(dǎo)致即使使用了sudo還會出現(xiàn)類似以下錯誤。
We trust you have received the usual lecture from the local System
Administrator. It usually boils down to these three things:
#1) Respect the privacy of others.
#2) Think before you type.
#3) With great power comes great responsibility.
復(fù)制代碼
解決方案:在 /etc/sudoers 文件中增加 jenkins ALL=(ALL) NOPASSWD:ALL 表示在執(zhí)行 sudo 時不需要輸入密碼。
如果不使用 sudo則會出現(xiàn)以下錯誤。
xxxxxxx: Permission denied
復(fù)制代碼
解決方案:修改 /lib/systemed/system/jenkins.service 文件。將 User=jenkins 修改為 User=root,表示給 Jenkins 賦權(quán)限。修改配置文件后記得重啟服務(wù)。
構(gòu)建的過程中還可能出現(xiàn)以下錯誤
ERROR: Error fetching remote repo 'origin'
復(fù)制代碼
解決方案:由于需要構(gòu)建的代碼在 github 上面,這種錯誤表示拉取代碼失敗了,重試幾次就可以了。
工作目錄
上面提到一個很重要的概念就是 工作目錄 在上面的 shell 默認(rèn)就是在這里執(zhí)行的。工作目錄是由兩部分組成。
/var/lib/jenkins/workspace/類似于前綴吧。web-deploy這個其實是上面構(gòu)建任務(wù)的名字。
總結(jié):Jenkins 的執(zhí)行目錄是 /var/lib/jenkins/workspace/web-deploy。也就是說輸入的每一條命令都是在這里面執(zhí)行的。(搞清楚定位能避免好多問題,特別是前端的部署,就是打包,移動,解壓很容易搞錯路徑。)
構(gòu)建目標(biāo):偵聽 git 提交到指定分支進行構(gòu)建
來到
Jenkins中選擇 系統(tǒng)管理 -> 系統(tǒng)配置 找到Jenkins URL將其復(fù)制。隨后在尾部添加
github-webhook/尾部斜杠一定不要丟。整體結(jié)構(gòu)大致為http://192.168.0.1:8080/github-webhook/登錄
github需要集成的項目中添加webhook。在Payload URL中將上述內(nèi)容填入。

然后修改 Jenkins任務(wù)配置 構(gòu)建觸發(fā)器中選擇 GitHub hook trigger for GITScm polling

由于在上面的源碼管理中已經(jīng)指定了main分支,此時如果這個分支的代碼有改動就會觸發(fā)自動構(gòu)建。
構(gòu)建目標(biāo):部署到目標(biāo)主機
在真實的開發(fā)場景中,
Jenkins幾乎不會和前端資源放到一個服務(wù)器。大多數(shù)情況下Jenkins所處的服務(wù)器環(huán)境就是一個工具用的服務(wù)器,放置了一些公司中常用的工具。因此構(gòu)建到指定的服務(wù)器也至關(guān)重要。
1,系統(tǒng)管理 -> 插件管理 搜索 Publish Over SSH 進行安裝。

2,然后在系統(tǒng)管理 -> 系統(tǒng)配置中找到 Publish over SSH 點擊新增,再點擊高級,然后選中 Use password authentication, or use a different key

完成后可點擊右下角 Test Confirguration 進行測試。
3,繼續(xù)修改構(gòu)建任務(wù)。先修改原有的構(gòu)建腳本。因為要發(fā)布到遠(yuǎn)程,所以原有的發(fā)布命令要進行去除。
npm install yarn -g
yarn install
yarn build
# 只打包,然后刪除文件夾。
tar -zcvf dist.tar.gz dist/
rm -rf dist/
復(fù)制代碼
4,選擇構(gòu)建后操作 -> Send build artifacts over SSH

Rransfer Set Source files:要上傳到目標(biāo)服務(wù)器的文件。它是一個相對路徑,相對于 Jenkins 的工作目錄 由于上面的 shell 執(zhí)行之后在工作目錄中只有一個壓縮包,so 直接寫一個文件名即可。Remove prefix:去前綴。假設(shè)此時打包文件在/var/lib/jenkins/workspace/web-deploy/assets/dist.tar.gz,那么Rransfer Set Source files則應(yīng)該為assets/dist.tar.gz,此時Remove prefix配置為assets/則可以去除這個前綴,否則會在目標(biāo)服務(wù)中創(chuàng)建assets。Remote directory:遠(yuǎn)程的靜態(tài)資源托管目錄。由于配置服務(wù)器默認(rèn)為/,所以usr/share/nginx/html/不用以/開頭。Exec command:遠(yuǎn)程機執(zhí)行shell,由于配置服務(wù)器默認(rèn)為/, 所以 工作目錄也是以/開始。
執(zhí)行成功后查看執(zhí)行日志會有類似以下結(jié)果:
SSH: Connecting from host [iZuf6dwyzch3wm3imzxgqfZ]
SSH: Connecting with configuration [aliyun-dev] ...
SSH: EXEC: completed after 202 ms
SSH: Disconnecting configuration [aliyun-dev] ...
# 如果 Transferred 0 file 則需要查看配置的路徑是否正確。表示文件并沒有被移動到遠(yuǎn)程主機中。
SSH: Transferred 1 file(s)
Finished: SUCCESS
復(fù)制代碼
構(gòu)建目標(biāo):釘釘機器人通知
1,系統(tǒng)管理 -> 插件管理 搜索 DingTalk 進行安裝。文檔[5]

2,釘釘群創(chuàng)建機器人。釘釘群 -> 只能群助手 -> 添加機器人 -> 自定義

3,定義機器人名字和關(guān)鍵字,創(chuàng)建完成后先將 webhook 中的內(nèi)容復(fù)制。

4,Jenkins 中 系統(tǒng)管理 -> 系統(tǒng)配置 -> 釘釘 -> 新增 配置完成后可點擊右下角進行測試。

5,修改構(gòu)建任務(wù)配置。

通知人:atAll 勾選后
@不到準(zhǔn)確的人。??。輸入框內(nèi)可填寫需要被@人的手機號,多個換行。自定義內(nèi)容:支持
markdown寫法,可以使用一些環(huán)境變量。192.168.0.1:8080/env-vars.html/實現(xiàn)默認(rèn) `@` 執(zhí)行人[6]
6,構(gòu)建成功

Pipline 構(gòu)建
上一章節(jié)中著重介紹了如何構(gòu)建 freestyle 的任務(wù),但是 Jenkins 遠(yuǎn)不止于此。在本章開始之前強烈建議閱讀文檔[7],重點關(guān)注流水線相關(guān)內(nèi)容。
新建任務(wù) -> 選擇流水線 其他內(nèi)容可以都不用管,只關(guān)注流水線 有兩種選擇,演示就選擇第一種。
直接在 Jenkins 中書寫配置。

在項目的 Jenkinsfile 配置文件中寫配置。

在正式開始之前應(yīng)該了解 Jenkins Pipline 的基礎(chǔ)概念。
pipeline {
agent any // 在任何可用的代理上,執(zhí)行流水線或它的任何階段。
stages {
stage('Build') { // 定義 "Build" 階段。
steps {
// 執(zhí)行與 "Build" 階段相關(guān)的步驟。
}
}
stage('Deploy') { // 定義 "Deploy" 階段。
steps {
// 執(zhí)行與 "Deploy" 階段相關(guān)的步驟。
}
}
}
}
復(fù)制代碼
pipline:定義流水線整個結(jié)構(gòu),可以看做是根節(jié)點agent:指示Jenkins為整個流水線分配一個執(zhí)行器,比如可以配置Dockerstages:對整個CI流的包裹,個人認(rèn)為沒多大用,還必須得有。stage:可以理解為是對某一個環(huán)節(jié)的描述。注意:參數(shù)就是描述內(nèi)容,可以是任何內(nèi)容。不要想歪了只能傳遞BuildDeploy這些。steps:描述了stage中的步驟,可以存在多個。
了解到這里還是不夠的。流水線入門[8] 流水線語法參考[9]
Pipline 復(fù)刻 Freestyle
這里先直接把配置貼出來。后續(xù)結(jié)合內(nèi)容在進行分析。
點擊查看完整配置
// 自定義 釘釘插件 的 錯誤信息和成功信息
def successText = [
""" ### 新的構(gòu)建信息,請注意查收""",
""" ${env.JOB_BASE_NAME}任務(wù)構(gòu)建<font color=green>成功</font> ,點擊查看[構(gòu)建任務(wù) #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""
]
def failureText = [
""" ### 新的構(gòu)建信息,請注意查收""",
""" ${env.JOB_BASE_NAME}任務(wù)構(gòu)建<font color=red>失敗</font> ,點擊查看[構(gòu)建任務(wù) #${env.BUILD_NUMBER}](http://106.14.185.47:8080/job/${env.JOB_BASE_NAME}/${env.BUILD_NUMBER}/)"""
]
// 1,偵聽 github push 事件
properties([pipelineTriggers([githubPush()])])
pipeline {
agent any
// 環(huán)境變量定義。
environment {
GIT_REPO = 'http://github.com/vue-ts-vite-temp.git'
}
stages {
// 2,拉取 github 代碼,通過 GitSCM 偵聽 push 事件。
stage('Pull code') {
steps {
checkout(
[
$class: 'GitSCM',
branches: [[name: '*/main']],
extensions: [],
userRemoteConfigs: [
[
credentialsId: '381325e4-0f9c-41ea-b5f6-02f8ea2a475a',
url: env.GIT_REPO
]
],
changelog: true,
poll: true,
]
)
}
}
stage('Install and build') {
steps {
// 3,前面安裝過的 nodejs 插件使用
nodejs('v14.19.0') {
sh 'npm install yarn -g'
sh 'yarn install'
sh 'yarn build'
}
}
}
stage('Pack') {
steps {
sh 'tar -zcvf dist.tar.gz dist/'
sh 'rm -rf dist/'
}
}
stage('Deploy') {
steps {
// 4,前面下載的 Publish Over SSH 插件的使用
sshPublisher(
publishers: [
sshPublisherDesc(
configName: 'aliyun-dev',
transfers: [
sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: '''
cd /usr/share/nginx/html/
tar -zxvf dist.tar.gz
rm -rf dist.tar.gz
''',
execTimeout: 120000,
flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '/usr/share/nginx/html/',
remoteDirectorySDF: false,
removePrefix: '',
sourceFiles: 'dist.tar.gz'
)
],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: false
)
]
)
}
}
}
post {
success {
// 5,DingTalk 插件的使用。
dingtalk (
robot: '1314',
type: 'ACTION_CARD',
title: 'Jenkins構(gòu)建提醒',
text: successText,
btns: [
[
title: '控制臺',
actionUrl: 'http://106.14.185.11:8080/'
],
[
title: '項目預(yù)覽',
actionUrl: 'http://github.com/'
],
],
at: []
)
}
failure {
dingtalk(
robot: '1314',
type: 'ACTION_CARD',
title: 'Jenkins構(gòu)建提醒',
text: failureText,
btns: [
[
title: '控制臺',
actionUrl: 'http://106.14.185.11:8080/'
],
[
title: '項目預(yù)覽',
actionUrl: 'http://github.com/'
],
],
at: []// 這里是手機號多個之間,隔開
)
}
}
}
復(fù)制代碼
這么多內(nèi)容手寫無疑是很難受的,好在 Jenkins 提供了一些幫助工具。訪問地址為:Jenkins地址 + /job + 當(dāng)前任務(wù) + /pipeline-syntax/,例如:http://localhost:8080/job/dev-deploy/pipeline-syntax/,或者進入任務(wù)構(gòu)建頁面,點擊流水線語法進入

進入該頁面后請熟讀并背誦以下三項。重點放到第一項。

回頭看上面的腳本注釋都帶有序號。根據(jù)注釋序號開始解釋。
1,在片段生成器中選擇 properties: Set job properties 生成代碼片段。由于只是使用了 git hook trigger 所以要對生成的片段稍作修改。

2,如果不是為了偵聽 github push 選擇 git: Git 即可,但現(xiàn)在應(yīng)該選擇 checkout: Check out from version control,隨后填寫信息生成代碼即可。

3,選擇 nodejs: Provide Node & npm bin/folder to Path

4,選擇 sshPublisher: Send build artifacts over SSH,像上面流水線一樣配置之后直接生成代碼即可。

5,DingTalk 文檔
總結(jié): 通過插件生成的代碼,稍作組合就成為了完整的配置。但整體難度還是要略高于 Freestyle 任務(wù)。畢竟生成的代碼有部分也不是拿來即用的,并且 Pipline 基本語法一定要有所掌握。不然生成的代碼都不曉得放到哪里合適。
關(guān)于本文
來自:DoubleX
https://juejin.cn/post/7102360505313918983
