本文記錄一個前端部署Gitlab的CI。不是在自己的伺服器上面搭建的Gitlab。使用的是Gitlab.com的Gitlab的CI,在騰訊雲擼的羊毛的小水管也搭不起Gitlab,做個CI的伺服器還是能勉勉強強的。
Gitlab和Github
Github 一個網站,提供給使用者空間建立git倉儲,儲存使用者的一些資料文件或者程式碼等。
Gitlab 一個基於git實現的線上程式碼倉庫軟體,你可以用Gitlab自己搭建一個類似於Github一樣的系統,一般用於在企業、學校等內部網路搭建Git私服。
什麼是持續整合
阮一峰的這個文章寫的挺好的持續整合是什麼?
持續整合指的是,頻繁地(一天多次)將程式碼整合到主幹。
持續整合的目的,就是讓產品可以快速迭代,同時還能保持高質量。它的核心措施是,程式碼整合到主幹之前,必須通過自動化測試。只要有一個測試用例失敗,就不能整合。
Gitlab的CI
從 GitLab 8.0 開始,GitLab CI 就已經整合在 GitLab 中,我們只要在專案中新增一個 .gitlab-ci.yml 檔案,然後新增一個 Runner,即可進行持續整合。 而且隨著 GitLab 的升級,GitLab CI 變得越來越強大。
首先明白Gitlab CI 幾個基本的概念
GitLab-CI
這個是一套配合GitLab使用的持續整合系統,是GitLab自帶的,也就是你裝GitLab的那臺伺服器上就帶有的。無需多考慮。.gitlab-ci.yml的指令碼解析就由它來負責。
GitLab-Runner
這個是指令碼執行的承載者,.gitlab-ci.yml的script部分的執行就是由runner來負責的。GitLab-CI瀏覽過專案裡的.gitlab-ci.yml檔案之後,根據裡面的規則,分配到各個Runner來執行相應的指令碼script。這些指令碼有的是測試專案用的,有的是部署用的。
.gitlab-ci.yml
這個是在git專案的根目錄下的一個檔案,記錄了一系列的階段和執行規則。GitLab-CI在push後會解析它,根據裡面的內容呼叫runner來執行。
簡單來說就是,你利用Git版本管理Push了原生程式碼到Remote上(這裡就是你gitlab.com),然後Gitlab,就通知你的伺服器,也就是Gitlab-runner來執行構建任務。然後跑測試用例,測試用例通過了就生成Build出相應的環境的程式碼,自動部署上不同的環境伺服器上面去。
安裝Gitlab Runner
如果想要使用Docker Runner,則需要安裝Docker。(可選)
curl -sSL https://get.docker.com/ | sh
複製程式碼
安裝 GitLab Runner 太簡單了,按照著 官方文件 的教程來就好拉! 下面是 Debian/Ubuntu/CentOS 的安裝方法,其他系統去參考官方文件:
# For Debian/Ubuntu
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
$ sudo apt-get install gitlab-ci-multi-runner
# For CentOS
$ curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
$ sudo yum install gitlab-ci-multi-runner
複製程式碼
然後註冊Gitlab Runner Runner需要註冊到Gitlab才可以被專案所使用,一個gitlab-ci-multi-runner服務可以註冊多個Runner。
在 GNU/Linux 系統上註冊 Runner:
執行下面命令啟動註冊程式:
sudo gitlab-runner register
複製程式碼
輸入 GitLab 例項 URL:
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com
複製程式碼
輸入獲取到的用於註冊 Runner 的 token:
Please enter the gitlab-ci token for this runner
xxx //這個token在你gitlab.com的專案的 setting >> CI/CD >> Runners settings 下
複製程式碼
輸入該 Runner 的描述,稍後也可通過 GitLab's UI 修改:
Please enter the gitlab-ci description for this runner
一個配置很低的伺服器
複製程式碼
給該 Runner 指派 tags, 稍後也可以在 GitLab's UI 修改:
Please enter the gitlab-ci tags for this runner (comma separated):
tengxun // 這個就相當於每一個runner的唯一id,記住這個tag。
複製程式碼
選擇 Runner 是否接收未指定 tags 的任務(預設值:false), 稍後可以在 GitLab's UI 修改:
Whether to run untagged jobs [true/false]:
[false]: true
複製程式碼
選擇是否為當前專案鎖定該 Runner, 之後也可以在 GitLab's UI 修改。 該功能通常用於被指定為某個專案的 Runner (預設值:true):
Whether to lock Runner to current project [true/false]:
[true]: true
複製程式碼
選擇 Runner executor:
Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
docker // 我選擇的docker,請記住,選擇docker的之前要把docker啟動,docker的使用就不是本文所講的了
複製程式碼
如果你選擇 Docker 作為你的 executor,註冊程式會讓你設定一個預設的映象, 作用於 .gitlab-ci.yml 中未指定映象的專案:
Please enter the Docker image (eg. ruby:2.1):
alpine:latest
複製程式碼
然後,你重新整理你setting下面的配置
有個綠色的小圓點,這就表明你已經註冊Runner成功了。配置.gitlab-ci.yml
配置好 Runner 之後,我們要做的事情就是在專案根目錄中新增 .gitlab-ci.yml 檔案了。 當我們新增了 .gitlab-ci.yml 檔案後,每次提交程式碼或者合併 MR 都會自動執行構建任務了。
在.gitlab-ci.yml有一些需要講解的概念
Pipeline
一次 Pipeline 其實相當於一次構建任務,裡面可以包含多個流程,如安裝依賴、執行測試、編譯、部署測試伺服器、部署生產伺服器等流程。我們的任何提交或者 Merge Request 的合併都可以觸發 Pipeline。如下圖:
+------------------+ +----------------+
| | trigger | |
| Commit / MR +---------->+ Pipeline |
| | | |
+------------------+ +----------------+
複製程式碼
Stages
Stages 表示構建階段,說白了就是上面提到的流程。 我們可以在一次 Pipeline 中定義多個 Stages,每個Stage可以完成不同的任務。 Stages有下面的特點:
- 所有 Stages 會按照順序執行,即當一個 Stage 完成後,下一個 Stage 才會開始
- 只有當所有 Stages 完成後,該構建任務 (Pipeline) 才會成功
- 如果任何一個 Stage 失敗,那麼後面的 Stages 不會執行,該構建任務 (Pipeline) 失敗
因此,Stages 和 Pipeline 的關係就是:
+--------------------------------------------------------+
| |
| Pipeline |
| |
| +-----------+ +------------+ +------------+ |
| | Stage 1 |---->| Stage 2 |----->| Stage 3 | |
| +-----------+ +------------+ +------------+ |
| |
+--------------------------------------------------------+
複製程式碼
Jobs
Jobs 表示構建工作,表示某個 Stage 裡面執行的工作。 我們可以在 Stages 裡面定義多個 Jobs,這些 Jobs 會有以下特點:
- 相同 Stage 中的 Jobs 會並行執行
- 相同 Stage 中的 Jobs 都執行成功時,該 Stage 才會成功
- 如果任何一個 Job 失敗,那麼該 Stage 失敗,即該構建任務 (Pipeline) 失敗
所以,Jobs 和 Stage 的關係圖就是:
+------------------------------------------+
| |
| Stage 1 |
| |
| +---------+ +---------+ +---------+ |
| | Job 1 | | Job 2 | | Job 3 | |
| +---------+ +---------+ +---------+ |
| |
+------------------------------------------+
複製程式碼
這些是部署指令碼里面的一些基本結構,接下來說一些.gitlab-ci.yml的基本構成
下面是一個最簡單的Node專案的部署指令碼。
image: node:alpine // 預設的ci部署的docker映象
stages: // 首先按順序定義有幾個步驟。步驟下面的所有job是同步執行的
- test
- build
job1:
stage: test // 屬於test的stage
script:
- npm run test // 這個job執行的指令碼
only:
- master // 只監聽master分支的程式碼提交
tags:
- tengxun // 要使用哪個runner
job2:
stage: build
script:
- npm run build
only:
- master
tags:
- tengxun
複製程式碼
注意這裡的job1,job2名字是隨便取的,沒有關係,只要不用Gitlab-CI的關鍵字就可以。
列出一些常用的關鍵字,掌握了這些就可以開發了。
關鍵字 | 是否必須 | 描述 |
---|---|---|
image | 否 | 用於docker映象,檢視docker文件 |
services | 否 | 用於docker服務,檢視docker文件 |
stages | 否 | 定義構建階段 |
types | 否 | stages 的別名(已廢除) |
before_script | 否 | 定義在每個job之前執行的命令 |
after_script | 否 | 定義在每個job之後執行的命令 |
variable | 否 | 定義構建變數 |
cache | 否 | 定義一組檔案列表,可在後續執行中使用 |
發現這篇文章對每個關鍵字對解釋的好清楚,算是個拋磚引玉吧。比我寫的都還要清楚。
配置之前,你還要在你gitlab.com的對應專案裡面的setting >> CI/CD >> Secret variables 定義一些構建變數,因為你的Gitlab-CI要去自動的登入伺服器,然後把打包出來的檔案自動更新上去。
Runner 登入你的伺服器是不能用傳統輸入賬號密碼的形式,(因為都自動化了,還需要輸入密碼,那還叫什麼自動化)。只能通過走SSH登入的形式,如果不懂SSH登入,請自行谷歌。私鑰這些東西肯定不能寫在yml檔案裡面,因為yml檔案是每個人都能看見的,所以Gitlab-CI就可以在專案裡面自定義私有的變數名。至少專案開源出去之後,不是每個人都能看見部署伺服器的私鑰的。
這裡的$SSH_PRIVATE_KEY 是你開發機(也就是你的的開發電腦)生成的私鑰。 注意一定要複製
-----BEGIN RSA PRIVATE
-----END RSA PRIVATE KEY-----
複製程式碼
這些東西。(這裡是個坑。。。因為很少會讓你複製私鑰的) 下面配置的${CI_COMMIT_REF_NAME},是Gitlab CI 的預設關鍵字。詳情見文件
最後貼上我那個騰訊雲小水管的配置,親測有用。
還真是一個很簡單的vue專案。就用vue-cli生成,然後釋出到伺服器上面指定的目錄,伺服器上面的nginx配置已經配置好了。
stages:
- test
- build
- deploy
cache:
key: ${CI_COMMIT_REF_NAME}
paths:
- node_modules/
test_dev:
image: node:alpine
stage: test
only:
- dev
tags:
- tengxun
script:
- npm run test
build:
image: node:alpine
stage: build
only:
- master
- dev
tags:
- tengxun
script:
- npm set registry https://registry.npm.taobao.org # 設定淘寶映象地址
- npm install --progress=false
- npm run build
artifacts:
expire_in: 1 week
paths:
- dist
deploy_dev:
image: alpine
stage: deploy
only:
- dev
tags:
- tengxun
script:
- echo "http://mirrors.aliyun.com/alpine/v3.7/main/" > /etc/apk/repositories
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
- chmod 600 ~/.ssh/id_dsa
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- rsync -rav --delete dist/ "$SERVER_USER_HOST:$SERVER_DEV_PATH"
deploy_master:
image: alpine
stage: deploy
only:
- master
tags:
- tengxun
script:
- echo "http://mirrors.aliyun.com/alpine/v3.7/main/" > /etc/apk/repositories
- apk add --no-cache rsync openssh
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" >> ~/.ssh/id_dsa
- chmod 600 ~/.ssh/id_dsa
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
- rsync -rav --delete dist/ "$SERVER_USER_HOST:$SERVER_MASTER_PATH"
when: manual
複製程式碼
這裡用rsync來同步Build出來的程式碼,其實也很簡單的。
rsync 是一個開源工具,可以進行快速的增量的檔案傳輸。相關文章
簡單來說就是讓你源計算機和目標計算機進行檔案的同步。
附上rsync的翻譯的文件 點我
在GitLab-CI中, cache與artifacts比較容易混淆.
其中 cache 指的是快取, 常用於依賴安裝中, 如幾個jobs都需要安裝相同的依賴, 可以使用依賴, 此時可以加快依賴的安裝進度; 對於artifacts則是將某個工件上傳到GitLab提供下載或後續操作使用, 由於每個job啟動時, 都會自動刪除.gitignore中指定的檔案, 因此對於依賴安裝目錄, 即可以使用cache, 也可以使用artifacts.
兩個主要有以下幾個區別:
- 雖然定義了cache, 但是如果cache和.gitignore中重複的這部分, 仍然需要重新安裝
- 重新安裝時因為使用的是快取, 所以很有可能不是最新的
- 特別是開發環境, 如果每次都希望使用最新的更新, 應當刪除cache, 使用artifacts, 這樣可以保證確定的更新
- artifacts中定義的部分, 會自動生成, 並可以傳到下面的job中解壓使用, 避免了重複依賴安裝等工作 如果使用Docker執行Gitlab-Runner, cache會生成一些臨時容器, 不容易清理
- artifacts可以設定自動過期時間, 過期自動刪除
- artifacts會先傳到GitLab伺服器, 然後需要時再重新下載, 所以這部分也可以在GitLab下載和瀏覽
因為我們這裡要重複使用之前job打包出來在dist下面的檔案,所以我會使用artifacts。
when: manual
這裡master一般是值穩定的程式碼版本,所以最好手動執行的。when: manual
就是需要手動部署,所有job預設都是自動執行的。
魯迅曾經說過:有國內加速映象地址的一定要用國內映象地址
這裡的映象地址配置包括Docker,APK,NPM。一定要設定啊,當時就卡在這裡了很久。
然後我們push程式碼到master,點選你專案的CI/CD皮膚。
然後小水管過了2分鐘才跑完Build,扎心了。 點選右面的那個播放三角形,就可以部署到我的那個騰訊雲伺服器上面去了。(當然,dev分支是預設自動部署和的),這就開始構建了。好啦,一個簡單的前端CI嘗試就完了。
that's all。
參考資料
gitlab之gitlab-ci自動部署 GitLab 中文文件 Gitlab CI yaml官方配置檔案翻譯 用 GitLab CI 進行持續整合