打造前端CI/CD工作流


歡迎關注前端早茶,與廣東靚仔攜手共同進階

前端早茶專注前端,一起結伴同行,緊跟業界發展步伐~

公眾號作者:廣東靚仔

CI/CD 是 Continuous Intergration/Continuous Deploy 的簡稱,翻譯過來就是持續集成/持續部署。CD 也會被解釋為持續交付(Continuous Delivery),但是對於軟件工程師而言,最直接接觸的應該是持續部署。

我剛開始工作時,就有接觸過CI的概念,那個時候主要是團隊 QA(質量保證)使用 hudson 對工程進行質量掃描,跑一些基礎的自動化測試。當時印象最深的一幕就是 QA 對我說:”你的代碼靜態告警了,趕緊改一下...“。

現在一想,我不禁感到詫異,”咦?我們當時沒有用 ESLint 嗎?記不清楚了...“於是我翻了下 ESLint 的更新記錄,發現那時候 ESLint 的大版本號才剛到3,VSCode 的 ESLint 插件也還是比較早期的版本,可能還沒普及開吧。

后面我也慢慢地聽到了 Jenkins, Travis CI 這樣一些名詞,但是由於太菜,我一個都不會用。

 

而且我發現,我對 CI/CD 並沒有什么興趣,為什么呢?因為我還沒有使用它的動機。

構建/部署那些事

構建/部署說的簡單點,就是先利用 webpack 或者 gulp 這類的工具把工程打包,然后把打包得到的文件放在服務器上某個托管靜態資源的 Web 容器里,像 Java 就可以放在 Tomcat,不過現在流行用 Nginx 托管靜態資源。有了 Web 容器,前端打包的那些文件(比如index.html, main.js等等)就可以被訪問到了,這個相信大家都懂。

16年~18年時,我還不負責打包部署這些事(另一方面也是因為前端根本沒權限碰服務器啊,emmm...),所以我壓根沒關注打包部署這些事情。

18年到19年時,我開始負責打包部署了。當時完全沒這方面經驗,Linux 命令都是靠着一邊百度一邊敲。不過我清楚地記得,之前在測試組那間辦公室看他們用的是xshellxftp,把這倆工具搞來用后,我覺得部署真是簡單,我只要跑個腳本,安靜地等 webpack 和 gulp 的工作流結束后,把文件通過 xftp 傳到服務器就行,只要注意不要操作出錯就行了(顯然,人為操作就容易出錯,這也是個隱患)。由於構建部署的頻率不高,項目數量也不是很多,這一年我基本應付得過來。

直到去年,我手底下有差不多5個項目,接近10個前端工程。在這種日常部署節奏下,我覺得 xshell+xftp 也救不了我,雖然這些項目不是天天都發版上線,但是測試環境還是經常發的,每天光部署這事我就夠煩躁,寫代碼經常被打斷,而且也非常浪費時間。

 

我想着要尋求些改變了,但我還是沒考慮 CI/CD 這事,因為我覺得我好像還是不太懂 CI/CD。於是我考慮先用 shell 腳本來做構建/部署的事情,所以后來就有了這么兩篇探索性的文章:

  • 自動化部署的一小步,前端搬磚的一大步[1]
  • 前端自動化部署的深度實踐[2]

靠着這一波腳本的探索,我基本上也是過渡到半自動化的階段了,這種焦慮的狀況基本上得到了一些緩解。但是,我發現我的電腦還是扛不住,風扇急速旋轉的聲音能讓我自閉。。。畢竟一邊跑本地開發環境,一邊還可能同時跑1~2個工程的構建/部署腳本,再加上電腦運行的其他軟件,這發熱量你懂的!

所以,構建/部署這活不應該由我的電腦來承擔,它太累了。

 

而且,我也不想手動觸發部署腳本了,太累了,是時候讓代碼學會自己部署了。也就是這個時候,我對 CI/CD 就有了訴求

由於我們的代碼是托管在自建的 gitlab 服務器上,所以 CI/CD 這塊我直接選擇了用 gitlab 自帶的 CI/CD 能力。工作之余,我差不多花了兩天時間去熟悉gitlab CI/CD的文檔[3]

然后我按照文檔先把環境搭建好,接着一遍遍地調試.gitlab-ci.yml配置文件,我記得第一次成功跑完一個 Pipeline 前,我一共失敗了大概11次,這個過程挺折磨人,有時候你就是不知道到底哪里配錯了。

不過調通這個流程后,你就會覺得這整個試錯的過程都是值得的。Nice!

 

 

 

CI/CD到底干了啥?

其實我前面也提到了,一個版本發布的過程,主要就是分為以下幾個步驟:

  • 代碼合並:測試環境或生產環境都有獨立的分支,等所有待發版的代碼都合並到對應分支后,就可以考慮發版了。
  • 打包:或者叫構建。以生產環境部署為例,我們切到生產環境分支並 pull 最新代碼后,就可以開始打包步驟了。這一步主要是通過一些 bundler 完成的,比如 webpack。而打包命令嘛,一般都是定義在package.jsonscripts中了,我這兒定義的命令是build:prod,所以只要運行npm run build:prod就行了。
  • 部署:把打包得到的文件放在 web 容器中,而 web 容器通常在 Linux 服務器上,這涉及到遠程傳輸文件,這個時候我們一般要借助 shell 腳本或者 xftp。

而 CI/CD 做的事情就是:用自動化技術接管流程

監控Mutation

我的訴求是:當代碼合並到某個分支后,gitlab能自動幫我執行完打包和部署這兩個步驟。

所以,首先就必須有代碼變動的監控能力。這個確實有,如果你有關注過git hook[4],就知道這是可以實現的。

而且,絕大部分代碼托管平台都提供了 webhooks,能監控不少事件,比如 push 和 merge。

 

 

 

這也就是說,即便不使用代碼托管平台提供的 CI/CD 能力,開發者也有能力實現自己的 CI/CD 機制。

ps:當然,除了 CI/CD,做短信/郵件通知也是可行的,只要你敢去嘗試,基於平台開放的能力,我們能做很多事情。自研 CI/CD 的事情我們就不去搞了,人家造的輪子已經6翻了,直接拿來用。

回歸主題,只要我監控到代碼變動了,服務器端自動執行構建/部署腳本即可。

Gitlab CI/CD是怎么工作的

軟件服務於生活,也源於生活。Gitlab CI/CD 設計了很多概念,其中我覺得最有意思的是:Pipeline 和 Runner

Pipeline

Pipeline是CI/CD的最上層組件,它翻譯過來是管道,其實你可以將之理解為流水線,每一個符合.gitlab-ci.yml觸發規則的 CI/CD 任務都會產生一個 Pipeline。這個概念就有點像工廠中的車間流水線了,我們知道車間中有很多條流水線,不同的流水線可能會處理同一類型的生產任務,也可能處理不同類型的生產任務。當一條流水線空閑的時候,就有可能會被用來安排執行其他的生產任務。而 Gitlab 的 Pipeline 雖然沒有空閑的概念,一個 Pipeline 執行結束后也不會被復用,但是會將資源讓出來給其他的 Pipeline,所以和車間流水線也有異曲同工之妙。

 

Runner

有了流水線,還必須有辛勤的工人進行生產作業,Runner在 Gitlab Pipeline 中就扮演着工人角色,根據我們下達的指令進行作業。

Runner的類型

在 Gitlab 中,Runner 有很多種,分為Shared Runner, Group Runner, Specific Runner

  • Shared Runner 可以理解為機動人員,他可能會在工廠的各個流水線機動作業,隨時支援!在整個 Gitlab 應用中,Shared Runner 可以服務於各個 Project。

 

  • Group Runner 就比較好理解了,他只在這個組上班,別的組他是不會去的。在 Gitlab 中,我們是可以建立不同的 Group 的,比如前端一個 Group,后端一個 Group,甚至前端里面還可以分 N 個 Group。所以,Group Runner 只服務於指定的 Group。

 

  • Specific Runner 就更牛逼了,它只服務於指定的項目,也就是 Project 級別,別的項目咱都不去。

 

注冊Runner

工人是要持證上崗的,同樣地,Runner 有一個注冊的過程,就相當於在工廠中入職登記的意思。具體見Registering runners[5]。只有合法注冊的 Runner,才有資格執行 Pipeline。不過,Gitlab 好像沒給 Runner 發工資啊!

 

.gitlab-ci.yml配置

流水線和工人都安排好之后,就必須制定車間生產規章制度了。一條流水線到底怎么干活,總要有個規矩吧,你說呢?

沒錯,.gitlab-ci.yml文件就是來制定規則的!其實我要求的 CI/CD 流程並不復雜,只要幫我把構建和部署兩步搞定就行了。下面以一個簡化的生產環境構建部署流程為例說明:

workflow:
  rules:
    - if: '$CI_COMMIT_REF_NAME == "master"'

stages:
  - build
  - deploy

build_prod:
  stage: build
  cache:
    key: build_prod
    paths:
      - node_modules/
  script:
    - yarn install
    - yarn build:prod
  artifacts:
    paths:
      - dist
      
deploy_prod:
  stage: deploy
  script:
    - scp -r $CI_PROJECT_DIR username@host:/usr/share/nginx/html

首先,我希望只在 master 分支進行構建/部署作業,這個可以通過workflow.rules下的if條件約束完成。

然后,我希望把整個過程分為兩個階段執行,第一個階段是build,用於執行構建任務;第二個階段是deploy,用於執行部署任務。這可以通過stages來完成定義。

接着,我定義了兩個job,第一個jobbuild_prod,屬於build階段;第二個jobdeploy_prod,屬於deploy階段。

buiild_prod這個job中,主要是運行了yarn installyarn build:prod兩個腳本,打包生成的文件資產會根據artifacts的配置保存下來,供后面的job使用。

deploy_prod這個job中,主要是通過scp命令向 linux 服務器上的 nginx 目錄下傳輸文件。

這個簡單的 Pipeline 配置示例其實應用的是 Basic Pipeline Architecture,只不過示例中每個 stage 只定義了一個 job。

 

 

Gitlab CI/CD Variables

Gitlab 通過 Variables 為 CI/CD 提供了更多配置化的能力,方便我們快速取得一些關鍵信息,用來做流程決策。上述示例中的$CI_COMMIT_REF_NAME$CI_PROJECT_DIR就是 Gitlab 的預定義變量。

 

 

除了預定義變量,我們也可以自行定義一些環境變量,比如服務器 ip,用戶名等等,這樣就免去了在配置文件中明文列出私密信息的風險;另一方面也方便后期快速調整配置,避免直接修改.gitlab-ci.yml

 

 

授信問題

在不同主機間通過scp傳輸文件需要建立信任關系,在 CI/CD 中最好選擇免密方式,其基本原理就是把 ssh公鑰 交給對方。而這一點我在自動化部署的一小步,前端搬磚的一大步[1]這篇文章中也提到了,這里就不再贅述。

Runner獨立部署

由於我是將 Runner 直接部署到了 Gitlab 代碼服務器上,而我司配的這台代碼服務器的配置本身就不高,用來跑高 CPU 占用的構建部署 Pipeline 還是有點吃力的,有時候 Pipeline 跑起來甚至直接把 Gitlab 的 Web 服務搞崩了。

隊友問我:”怎么 Gitlab 白屏打不開了?“

 

沒過多久,領導那邊給我發了一台 Linux 服務器,專門給前端搞日常工作用的。bingo,我就順手把 Runner 獨立部署到新機器上了,這樣就不會影響隊友了,而且每次發版時間直接從 8min 縮短到 2min 以內,簡直 Nice!

 

CI/CD帶來的收益

直觀來看,我的重復勞動被去除了大部分,多出來的這部分時間我可以用來干更多有意義的事情,或者摸魚它不香嗎?而且,每天不用手動發版,心情也是倍兒棒!

此外,由於 CI/CD 采用自動化作業方式,只要腳本寫對了,幾乎不會出錯,出生產事故的幾率也就大大降低了。

 

參考

[1]

自動化部署的一小步,前端搬磚的一大步: https://juejin.cn/post/6844904049582538760#heading-0

[2]

前端自動化部署的深度實踐: https://juejin.cn/post/6844904056498946055

[3]

gitlab CI/CD的文檔: https://docs.gitlab.com/ee/ci/quick_start/

[4]

git hook: https://git-scm.com/book/zh/v2/%E8%87%AA%E5%AE%9A%E4%B9%89-Git-Git-%E9%92%A9%E5%AD%90

[5]

Registering runners: https://docs.gitlab.com/runner/register/

 

歡迎關注前端早茶,與廣東靚仔攜手共同進階

前端早茶專注前端,一起結伴同行,緊跟業界發展步伐~

公眾號作者:廣東靚仔


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM