CI/CD 是 Continuous Intergration/Continuous Deploy 的簡稱,翻譯過來就是持續集成/持續部署。CD 也會被解釋爲持續交付(Continuous Delivery),可是對於軟件工程師而言,最直接接觸的應該是持續部署。php
我剛開始工做時,就有接觸過CI的概念,那個時候主要是團隊 QA(質量保證)使用 hudson 對工程進行質量掃描,跑一些基礎的自動化測試。當時印象最深的一幕就是 QA 對我說:」你的代碼靜態告警了,趕忙改一下...「。html
如今一想,我不由感到詫異,」咦?咱們當時沒有用 ESLint 嗎?記不清楚了...「因而我翻了下 ESLint 的更新記錄,發現那時候 ESLint 的大版本號纔剛到3,VSCode 的 ESLint 插件也仍是比較早期的版本,可能還沒普及開吧。前端
後面我也慢慢地聽到了 Jenkins, Travis CI 這樣一些名詞,可是因爲太菜,我一個都不會用。node
並且我發現,我對 CI/CD 並無什麼興趣,爲何呢?由於我尚未使用它的動機。linux
構建/部署那些事構建/部署說的簡單點,就是先利用 webpack 或者 gulp 這類的工具把工程打包,而後把打包獲得的文件放在服務器上某個託管靜態資源的 Web 容器裏,像 Java 就能夠放在 Tomcat,不過如今流行用 Nginx 託管靜態資源。有了 Web 容器,前端打包的那些文件(好比index.html, main.js等等)就能夠被訪問到了,這個相信你們都懂。webpack
16年~18年時,我還不負責打包部署這些事(另外一方面也是由於前端根本沒權限碰服務器啊,emmm...),因此我壓根沒關注打包部署這些事情。nginx
18年到19年時,我開始負責打包部署了。當時徹底沒這方面經驗,Linux 命令都是靠着一邊百度一邊敲。不過我清楚地記得,以前在測試組那間辦公室看他們用的是xshell和xftp,把這倆工具搞來用後,我以爲部署真是簡單,我只要跑個腳本,安靜地等 webpack 和 gulp 的工做流結束後,把文件經過 xftp 傳到服務器就行,只要注意不要操做出錯就好了(顯然,人爲操做就容易出錯,這也是個隱患)。因爲構建部署的頻率不高,項目數量也不是不少,這一年我基本應付得過來。git
直到去年,我手底下有差很少5個項目,接近10個前端工程。在這種平常部署節奏下,我以爲 xshell+xftp 也救不了我,雖然這些項目不是每天都發版上線,可是測試環境仍是常常發的,天天光部署這事我就夠煩躁,寫代碼常常被打斷,並且也很是浪費時間。web
我想着要尋求些改變了,但我仍是沒考慮 CI/CD 這事,由於我以爲我好像仍是不太懂 CI/CD。因而我考慮先用 shell 腳本來作構建/部署的事情,因此後來就有了這麼兩篇探索性的文章:shell
靠着這一波腳本的探索,我基本上也是過渡到半自動化的階段了,這種焦慮的情況基本上獲得了一些緩解。可是,我發現個人電腦仍是扛不住,風扇急速旋轉的聲音能讓我自閉。。。畢竟一邊跑本地開發環境,一邊還可能同時跑1~2個工程的構建/部署腳本,再加上電腦運行的其餘軟件,這發熱量你懂的!
因此,構建/部署這活不該該由個人電腦來承擔,它太累了。
並且,我也不想手動觸發部署腳本了,太累了,是時候讓代碼學會本身部署了。也就是這個時候,我對 CI/CD 就有了訴求。
因爲咱們的代碼是託管在自建的 gitlab 服務器上,因此 CI/CD 這塊我直接選擇了用 gitlab 自帶的 CI/CD 能力。工做之餘,我差很少花了兩天時間去熟悉gitlab CI/CD的文檔[3]。
而後我按照文檔先把環境搭建好,接着一遍遍地調試.gitlab-ci.yml
配置文件,我記得第一次成功跑完一個 Pipeline 前,我一共失敗了大概11次,這個過程挺折磨人,有時候你就是不知道到底哪裏配錯了。
不過調通這個流程後,你就會以爲這整個試錯的過程都是值得的。Nice!
CI/CD到底幹了啥?其實我前面也提到了,一個版本發佈的過程,主要就是分爲如下幾個步驟:
package.json
的 scripts
中了,我這兒定義的命令是 build:prod
,因此只要運行 npm run build:prod
就好了。而 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是CI/CD的最上層組件,它翻譯過來是管道,其實你能夠將之理解爲流水線,每個符合.gitlab-ci.yml
觸發規則的 CI/CD 任務都會產生一個 Pipeline。這個概念就有點像工廠中的車間流水線了,咱們知道車間中有不少條流水線,不一樣的流水線可能會處理同一類型的生產任務,也可能處理不一樣類型的生產任務。當一條流水線空閒的時候,就有可能會被用來安排執行其餘的生產任務。而 Gitlab 的 Pipeline 雖然沒有空閒的概念,一個 Pipeline 執行結束後也不會被複用,可是會將資源讓出來給其餘的 Pipeline,因此和車間流水線也有殊途同歸之妙。
有了流水線,還必須有辛勤的工人進行生產做業,Runner在 Gitlab Pipeline 中就扮演着工人角色,根據咱們下達的指令進行做業。
在 Gitlab 中,Runner 有不少種,分爲Shared Runner, Group Runner, Specific Runner。
工人是要持證上崗的,一樣地,Runner 有一個註冊的過程,就至關於在工廠中入職登記的意思。具體見Registering runners[5]。只有合法註冊的 Runner,纔有資格執行 Pipeline。不過,Gitlab 好像沒給 Runner 發工資啊!
流水線和工人都安排好以後,就必須制定車間生產規章制度了。一條流水線到底怎麼幹活,總要有個規矩吧,你說呢?
沒錯,.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
,第一個job
是build_prod
,屬於build
階段;第二個job
是deploy_prod
,屬於deploy
階段。
在buiild_prod
這個job
中,主要是運行了yarn install
和yarn build:prod
兩個腳本,打包生成的文件資產會根據artifacts
的配置保存下來,供後面的job
使用。
在deploy_prod
這個job
中,主要是經過scp
命令向 linux 服務器上的 nginx 目錄下傳輸文件。
這個簡單的 Pipeline 配置示例其實應用的是 Basic Pipeline Architecture,只不過示例中每一個 stage 只定義了一個 job。
Gitlab 經過 Variables 爲 CI/CD 提供了更多配置化的能力,方便咱們快速取得一些關鍵信息,用來作流程決策。上述示例中的$CI_COMMIT_REF_NAME
和$CI_PROJECT_DIR
就是 Gitlab 的預約義變量。
除了預約義變量,咱們也能夠自行定義一些環境變量,好比服務器 ip,用戶名等等,這樣就免去了在配置文件中明文列出私密信息的風險;另外一方面也方便後期快速調整配置,避免直接修改.gitlab-ci.yml
。
在不一樣主機間經過scp
傳輸文件須要創建信任關係,在 CI/CD 中最好選擇免密方式,其基本原理就是把 ssh公鑰 交給對方。而這一點我在自動化部署的一小步,前端搬磚的一大步[1]這篇文章中也提到了,這裏就再也不贅述。
因爲我是將 Runner 直接部署到了 Gitlab 代碼服務器上,而我司配的這臺代碼服務器的配置自己就不高,用來跑高 CPU 佔用的構建部署 Pipeline 仍是有點吃力的,有時候 Pipeline 跑起來甚至直接把 Gitlab 的 Web 服務搞崩了。
隊友問我:」怎麼 Gitlab 白屏打不開了?「
沒過多久,領導那邊給我發了一臺 Linux 服務器,專門給前端搞平常工做用的。bingo,我就順手把 Runner 獨立部署到新機器上了,這樣就不會影響隊友了,並且每次發版時間直接從 8min 縮短到 2min 之內,簡直 Nice!
CI/CD帶來的收益直觀來看,個人重複勞動被去除了大部分,多出來的這部分時間我能夠用來幹更多有意義的事情,或者摸魚它不香嗎?並且,天天不用手動發版,心情也是倍兒棒!
此外,因爲 CI/CD 採用自動化做業方式,只要腳本寫對了,幾乎不會出錯,出生產事故的概率也就大大下降了。
小結本文從筆者的一些親身經歷出發,回憶了筆者在構建/部署過程當中遇到的痛點,並圍繞一個最基礎的Gitlab CI/CD案例,講述了筆者使用 CI/CD 來解決這些痛點的過程。雖然本文的主角是Gitlab CI/CD,但它和其餘代碼託管平臺的CI/CD在思路上是相似的,掌握了一個,舉一反三也就不難。而且,利用 Pipeline 這類工具,咱們還能夠作更多事情,好比持續集成+自動化測試。這就考驗你們的想象力了,剩下的就交給聰明的讀者啦!