產品需求評審後,各自拆分任務,從 master
分支切出一個 release
分支,根據各自任務狀況切出 update
或 feature
的開發分支;html
開發調試或提測時,將代碼 push
到遠程分支,提 merge request
(如下簡稱 mr)到 test
分支,GitLab CI
將項目代碼自動構建並部署到測試環境;node
測試完畢後提 mr
到 release
分支,待本次需求的開發分支都 code review
併合並後,從 release
分支提 mr
到 pre
分支,GitLab CI
將項目代碼自動構建並部署到預生產環境,而後進行迴歸測試,有問題再從 release
分支切出開發分支進行修改,重複以前的流程。linux
預生產環境沒問題後,從 release
分支提 mr
到 master
分支,,而後打 tag
上線,GitLab CI
將項目代碼自動構建並部署到生產環境,而後進行迴歸測試,有問題再發版。webpack
至此一次需求的完整開發流程就告一段落了,其中構建/部署等一些重複工做都是 GitLab CI
幫咱們完成,對此一直很好奇,接下來咱們就來嘗試搭建一個使用 GitLab CI
的項目。git
現有項目中使用 GitLab CI
能夠直接跳過這步,從這裏開始github
能夠按下面的步驟一步一步搭建,也能夠直接克隆這個倉庫:gitlab-ci-exampleweb
mkdir gitlab-ci-example cd gitlab-ci-example
git init npm init -y
mkdir src build
gitlab-ci-example/.gitignore
dist node_modules
gitlab-ci-example/.editorconfig
# editorconfig.org root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false
gitlab-ci-example/src/index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> <h1>Learn Gitlab CI</h1> </div> </body> </html>
gitlab-ci-example/src/main.js
function appendElementToAPP({ tag = "div", content = "" }) { const appEle = document.getElementById("app"); const newEle = document.createElement(tag); newEle.innerHTML = content; appEle.append(newEle); } appendElementToAPP({ tag: "div", content: `append content by js on ${new Date().toUTCString()}`, });
gitlab-ci-example/build/webpack.dev.js
"use strict"; const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const resolve = (dir) => path.resolve(__dirname, "../", dir); module.exports = { mode: "development", entry: { app: "./src/main.js", }, output: { path: resolve("dist"), filename: "[name].[hash].js", }, resolve: { extensions: [".js"], }, devServer: { port: 8090, contentBase: resolve("dist"), }, plugins: [ new HtmlWebpackPlugin({ filename: resolve("dist/index.html"), template: "src/index.html", }), ], };
gitlab-ci-example/build/webpack.prod.js
"use strict"; const path = require("path"); const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const resolve = (dir) => path.resolve(__dirname, "../", dir); module.exports = { mode: "production", entry: { app: "./src/main.js", }, output: { path: resolve("dist"), filename: "[name].[hash].js", }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ filename: resolve("dist/index.html"), template: "src/index.html", }), ], };
gitlab-ci-example/build/append-element.js.sh
const path = require("path"); const fs = require("fs"); const cheerio = require("cheerio"); const htmlFilePath = path.resolve(__dirname, "../dist/index.html"); fs.readFile(htmlFilePath, (err, data) => { if (err) { return; } const $ = cheerio.load(data); $("#app").append( `<div style="color: red;">append content by build on ${new Date().toUTCString()}</div>` ); fs.writeFileSync(htmlFilePath, $.html()); });
gitlab-ci-example/build/deploy-test.sh
cp -rf dist/* /www/test/gitlab-ci-example
gitlab-ci-example/package.json
{ "name": "gitlab-ci-example", "version": "0.0.1", "description": "", "main": "index.js", "scripts": { "deploy-test": "build/deploy-test.sh", "dev": "webpack-dev-server --config build/webpack.dev.js", "build": "webpack --config build/webpack.prod.js && node build/append-element.js" }, "keywords": [], "author": "", "license": "ISC" }
npm i -D cheerio webpack webpack-cli webpack-dev-server clean-webpack-plugin html-webpack-plugin
npm run dev
在瀏覽器中打開連接:http://localhost:8090/ ,你應該能看到:docker
npm run build
在瀏覽器中打開 dist
目錄下的 index.html
文件,你應該能看到:shell
至此項目的基本功能搭建完成,接下來開始在項目中使用 GitLab CI
。npm
使用 GitLab CI
以前,你得先準備一下:
GitLab
倉庫在倉庫主頁,點擊側邊欄 - Settings
- CI / CD
,跳轉 CI / CD Settings
頁面,展開 Runners
選項,按步驟手動設置 GitLab Runner
:
根據系統架構,下載並安裝對應的軟件包,查看詳情
# 下載(適用於amd64的軟件包) curl -LJO https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb # 若是下載太慢,建議在本地下載好以後,經過scp命令複製到遠程,相似這樣 # scp ~/gitlab-runner_amd64.deb yourUserName@yourIPAddress:/home/yourUserName # 安裝 sudo dpkg -i gitlab-runner_amd64.deb # 輸出 Selecting previously unselected package gitlab-runner. (Reading database ... 67015 files and directories currently installed.) Preparing to unpack gitlab-runner_amd64.deb ... Unpacking gitlab-runner (13.0.1) ... Setting up gitlab-runner (13.0.1) ... GitLab Runner: detected user gitlab-runner Runtime platform arch=amd64 os=linux pid=28968 revision=21cb397c version=13.0.1 gitlab-runner: Service is not installed. Runtime platform arch=amd64 os=linux pid=28975 revision=21cb397c version=13.0.1 gitlab-ci-multi-runner: Service is not installed. Runtime platform arch=amd64 os=linux pid=28993 revision=21cb397c version=13.0.1 Runtime platform arch=amd64 os=linux pid=29039 revision=21cb397c version=13.0.1 # 若是你收到相似上面的報錯,運行下面的命令,若是能輸出信息表示正常 sudo gitlab-runner status # 輸出 Runtime platform arch=amd64 os=linux pid=29971 revision=21cb397c version=13.0.1 gitlab-runner: Service is running!
對於上面的報錯信息,能夠看看這個 gitlab issue
開始註冊,下面是 Linux
的例子,其餘系統請看這裏
# 註冊 sudo gitlab-runner register # 輸出 Runtime platform arch=amd64 os=linux pid=31237 revision=21cb397c version=13.0.1 Running in system-mode. # 指定 GitLab 實例 URL Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/): https://gitlab.com/ # 輸入註冊令牌(從項目-設置-CI/CD 設置-Runners 那裏拷貝) Please enter the gitlab-ci token for this runner: JhXh7o********yDXATd # 輸入描述 Please enter the gitlab-ci description for this runner: [hostname]: runner-001 # 輸入關聯標籤 Please enter the gitlab-ci tags for this runner (comma separated): runner-001-tag # 輸出 Registering runner... succeeded runner=JhXh7oEx # 選擇執行環境,這裏選擇的是 shell Please enter the executor: virtualbox, docker-ssh+machine, kubernetes, parallels, shell, ssh, docker+machine, custom, docker, docker-ssh: shell # 輸出 Runner registered successfully. Feel free to start it, but if it\'s running already the config should be automatically reloaded!
下載安裝並註冊完 Runner
後,返回 CI / CD Settings
頁面,如今應該能看到項目關聯的 Runner
設置完 GitLab Runner
後,咱們就能夠開始配置 GitLab CI
了,新建 .gitlab-ci.yml
文件
gitlab-ci-example/.gitlab-ci.yml
# 工做名稱 job-test: # 階段 stage: test # 觸發條件:test 分支更新時 only: - test # 指定工做給具備特定標籤的 Runners tags: - runner-001-tag # 腳本 script: - npm install - npm run build - npm run deploy-test
默認狀況下 GitLab Runner
不會運行沒有 tags
的工做,因此這裏咱們指定註冊 GitLab Runner
時候設置的標籤:runner-001-tag
,查看更多 GitLab CI/CD 配置選項
若是你不想設置 tags
,能夠修改 GitLab Runner
的配置,勾選 Run untagged jobs
,表示容許 GitLab Runner
運行沒有設置 tags
的任務。
保存 .gitlab-ci.yml
文件後,將改動 push
到遠程倉庫
配置文件有了以後,咱們須要將其觸發,從包含上面改動的分支,切出一個 test
分支,提交到遠程,用於觸發 GitLab CI
(新提交和合並 test
分支都會觸發 CI
),固然經過圖形化界面建立 test
分支也是能夠的
git checkout test git push -u origin test
在倉庫主頁,點擊側邊欄 - CI / CD
- Pipelines
,就能看到當前倉庫全部的 CI
記錄,相似下面這樣:
Running with gitlab-runner 13.0.1 (21cb397c) on runner-001 3-1Hb5zy Preparing the "shell" executor 00:00 Using Shell executor... Preparing environment 00:00 Running on xx-ubuntu... Getting source from Git repository 00:00 mkdir: cannot create directory ‘/home/gitlab-runner/builds/3-1Hb5zy’: Permission denied Uploading artifacts for failed job 00:00 mkdir: cannot create directory ‘/home/gitlab-runner/builds/3-1Hb5zy’: Permission denied ERROR: Job failed: exit status 1
緣由:
將代碼 push
到遠程以後,構建出現了上面的報錯,GitLab Runner
構建時使用的是 gitlab-runner
用戶,建立目錄的時候提示權限不足,嘗試查看目錄信息:
# 查看文件和目錄信息 ls -alF /home/gitlab-runner # drwxr-xr-x 4 root root 4096 Jun 2 17:45 builds/
當前目錄的權限和權限組都是 root
,gitlab-runner
用戶不在 root
權限組下,因此沒權限操做。
仔細想一想 🤔 發現不對勁,GitLab Runner
構建時使用的是 gitlab-runner
用戶,可是爲何 builds
目錄在 root
權限組下?回想一下在此以前作過哪些和 root
用戶相關的操做,通過確認和查閱資料後發現,原來是在此次構建以前,手動安裝服務(gitlab-runner install
)的時候指定使用 root
用戶(--user root
)致使的:
# 安裝服務,指定工做目錄,指定運行任務的用戶爲 root 用戶 sudo gitlab-runner install --working-directory /home/gitlab-runner --user root
如何解決:
刪除 builds
目錄、卸載重裝 gitlab-runner
服務,將服務關聯的用戶指回 gitlab-runner
用戶
# 中止服務 sudo gitlab-runner stop # 卸載服務 sudo gitlab-runner uninstall # 從新安裝服務,指定工做目錄和用戶 sudo gitlab-runner install --working-directory /home/gitlab-runner --user gitlab-runner # 完整配置 # sudo gitlab-runner install --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service gitlab-runner --syslog --user gitlab-runner # 校驗 sudo gitlab-runner verify # 啓動服務 sudo gitlab-runner start # 查看狀態 sudo gitlab-runner status
# 再次查看文件和目錄信息 ls -alF /home/gitlab-runner # drwxrwxr-x 3 gitlab-runner gitlab-runner 4096 Jun 3 16:21 builds/
如今 builds
目錄的權限歸回 gitlab-runner
用戶全部了,在 gitlab
倉庫的 Pipelines
或 Jobs
頁面找到此次工做關聯的 retry
按鈕,點擊按鈕嘗試從新運行構建
Running with gitlab-runner 13.0.1 (21cb397c) on runner-001 3-1Hb5zy Preparing the "shell" executor 00:00 Using Shell executor... Preparing environment 00:00 Running on VM-0-5-ubuntu... Getting source from Git repository 00:03 Fetching changes with git depth set to 50... Reinitialized existing Git repository in /home/gitlab-runner/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example/.git/ Checking out 4e716630 as test... Skipping Git submodules setup Restoring cache 00:00 Downloading artifacts 00:00 Running before_script and script 00:00 $ npm install bash: line 92: npm: command not found Running after_script 00:00 Uploading artifacts for failed job 00:00 ERROR: Job failed: exit status 1
緣由:
重裝服務後 retry
構建後,出現了上面的報錯,緣由是由於 gitlab-runner
用戶所處的環境沒有安裝 node
致使的(默認狀況下在 root
或者其餘用戶上安裝的 node
在 gitlab-runner
用戶所處環境是訪問不到的)
如何解決:
登陸服務器,切換到 gitlab-runner
用戶,安裝 nvm
,再安裝 node
# 切換到 root 用戶 sudo su # 登陸 gitlab-runner 用戶 su -l gitlab-runner # 安裝 nvm(https://github.com/nvm-sh/nvm),若是訪問腳本443,嘗試用其餘方式安裝 nvm 或者直接安裝 node curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash # 查看 nvm nvm ls # 安裝 node(截止目前最新LTS版本爲:12.18.0,自行選擇版本安裝) nvm install 12.16.2 # 查看 node 和 npm 版本 node -v npm -v
如今 gitlab-runner
用戶所處環境已經安裝 node
了,高興的嘗試 retry
後,發現依然是 bash: line 92: npm: command not found
,一度覺得是錯覺、是服務沒有檢測到 node
的存在,嘗試重裝、重啓 gitlab-runner
服務後 retry
依然是 failed
。
冷靜一番後,查閱大量相似案例,初步判斷多是環境變量沒加載,也就是 nvm
沒有加載致使的,嘗試在構建過程當中手動加載 ~/.bashrc
文件:
before_script: - source ~/.bashrc
從新 retry
後依然仍是 failed
,最後仍是在 ~/.profile
和 ~/.bashrc
兩個配置文件頭部的一些註釋信息裏,找到了一些新的靈感:
~/.profile
# ~/.profile: executed by the command interpreter for login shells. # ...
直譯過來:~/.profile
: 由命令解釋器針對登陸 shell
執行。
~/.bashrc
# ~/.bashrc: executed by bash(1) for non-login shells. # ...
直譯過來:~/.bashrc
:由 bash(1)
對非登陸 shell
執行。
以上信息中提到了登陸與非登陸兩種狀態,配置文件在對應狀態下才會執行,經過添加調試信息發現,在 gitlab-runner
執行任務構建時,不會加載 ~/.bashrc
文件,只會加載 ~/.profile
文件;而經過 ssh
登陸服務器時,兩個文件都會加載,是否是有些疑惑 🤔,這是由於 ~/.profile
文件在開頭會根據環境(bash
)決定是否要先加載 ~/.bashrc
文件,具體代碼以下:
# ~/.profile: executed by the command interpreter for login shells. # This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login # exists. # see /usr/share/doc/bash/examples/startup-files for examples. # the files are located in the bash-doc package. # the default umask is set in /etc/profile; for setting the umask # for ssh logins, install and configure the libpam-umask package. #umask 022 # if running bash if [ -n "$BASH_VERSION" ]; then # include .bashrc if it exists if [ -f "$HOME/.bashrc" ]; then . "$HOME/.bashrc" fi fi
要解決 npm
命令找不到這個問題,須要在 ~/.profile
配置文件添加上加載 nvm
的代碼:
# 編輯配置文件 vi ~/.profile # 配置 nvm 加載,將下面的代碼添加到配置文件中(https://github.com/nvm-sh/nvm#installing-and-updating) export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm # 保存配置文件後,從新加載配置文件 source ~/.profile
$ npm run deploy-test > gitlab-ci-example@1.0.0 deploy-test /home/ubuntu/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example > build/deploy-test.sh sh: 1: build/deploy-test.sh: Permission denied npm ERR! code ELIFECYCLE npm ERR! errno 126 npm ERR! gitlab-ci-example@1.0.0 deploy-test: `build/deploy-test.sh` npm ERR! Exit status 126 npm ERR! npm ERR! Failed at the gitlab-ci-example@1.0.0 deploy-test script. # ...
緣由:
# 在項目構建目錄下(相似:/home/ubuntu/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example),查看部署腳本的權限信息 ls -alF ./build/deploy-test.sh # -rw-rw-r-- 1 ubuntu ubuntu 42 Jun 2 19:40 deploy-test.sh
經過以上命令發現和搜索相關問題,發現 deploy-test.sh
文件不具有可執行權限,因此沒法執行
如何解決:
deploy-test.sh
文件權限# 代表 deploy-test.sh 文件是可執行的 git update-index --chmod=+x ./build/deploy-test.sh # 改動會直接進入暫存區,編輯器的 git state 可能代表還有新的更改,忽略後直接提交本次更改後,git state 的狀態會更新 git commit -m 'Make build.sh executable' # 提交到遠程,master, test 或者其餘分支 git push
sh
命名執行 deploy-test.sh
文件# package.json - "deploy-test": "build/deploy-test.sh", + "deploy-test": "sh build/deploy-test.sh",
$ npm run deploy-test > gitlab-ci-example@1.0.0 deploy-test /home/gitlab-runner/builds/3-1Hb5zy/0/Lsnsh/gitlab-ci-example > build/deploy-test.sh /www/test/gitlab-ci-example: No such file or directory Please create this directory and then assign the directory permissions to the gitlab-runner user. You can execute the following command as root: mkdir /www/test/gitlab-ci-example chown gitlab-runner /www/test/gitlab-ci-example
緣由:
build/deploy-test.sh
腳本會將構建好的代碼,拷貝到 /www/test/gitlab-ci-example
目錄下,所以在構建以前須要先建立好這個目錄
如何解決:
參考 build/deploy-test.sh
腳本中打印出的提示信息,新建並分配目錄權限便可:
# 新建目錄(使用 root 用戶或者其餘 gitlab-runner 用戶覺得的用戶) mkdir /www/test/gitlab-ci-example # 分配 gitlab-runner 用戶文件夾權限 chown gitlab-runner /www/test/gitlab-ci-example
至此,CI
終於能夠跑通了,部署後頁面的內容是這樣的,點擊查看:
經過 .gitlab-ci.yml
配置文件,你能夠在構建的各個階段作處理,好比你能夠在 before_script
和 after_script
階段調用釘釘機器人接口,及時將部署狀態同步到我的/羣:
before_script: # 釘釘通知 釘釘羣 - curl -X POST 'https://oapi.dingtalk.com/robot/send?access_token=xxx&xxxx'
通知相似下面這樣:
更多關於 .gitlab-ci.yml
文件的配置信息,請看官方文檔
好利用 CI / CD
這件工具,相信會大大提高團隊協做和開發效率。萬事開頭難,起初確定會有抵觸心理,邁過這道坎以後,還有下一道坎等着你[手動狗頭]
示例項目的倉庫連接以下,歡迎 star
🌟:
github
倉庫(template
):https://github.com/Lsnsh/gitl...
gitlab
倉庫:https://gitlab.com/Lsnsh/gitl...
# 查看 gitlab-runner 相關進程 ps aux|grep gitlab-runner # 註冊 gitlab-runner sudo gitlab-runner register # 重裝 gitlab-runner 服務 # 中止服務 sudo gitlab-runner stop # 卸載服務 sudo gitlab-runner uninstall # 從新安裝服務,指定工做目錄和用戶 sudo gitlab-runner install --working-directory /home/gitlab-runner --user gitlab-runner # 完整配置 # sudo gitlab-runner install --working-directory /home/gitlab-runner --config /etc/gitlab-runner/config.toml --service gitlab-runner --syslog --user gitlab-runner # 校驗 sudo gitlab-runner verify # 啓動服務 sudo gitlab-runner start # 查看狀態 sudo gitlab-runner status # 拷貝文件到遠程主機 # scp ~/gitlab-runner_amd64.deb yourUserName@yourIPAddress:/home/yourUserName # eg: (將文件 ~/gitlab-runner_amd64.deb 拷貝到遠程主機,公網 IP 爲 110.120.130 的 root 用戶目錄下) scp ~/gitlab-runner_amd64.deb root@110.120.130:/home/root # 查看文件和目錄信息 # eg: (查看 /home/gitlab-runner 目錄) ls -alF /home/gitlab-runner # 切換到 root 用戶 sudo su # root 用戶登陸其餘用戶 # eg: (登陸 gitlab-runner 用戶) su -l gitlab-runner # 代表文件是可執行的 # git update-index --chmod=+x 文件路徑 # 代表文件是不可執行的 # git update-index --chmod=-x 文件路徑 # eg: (代表 ./build/deploy-test.sh 文件是可執行的) git update-index --chmod=+x ./build/deploy-test.sh # 給用戶分配文件或文件夾權限 # chown 用戶名 文件或文件夾路徑 # eg: (分配 gitlab-runner 用戶 /www/test/gitlab-ci-example 文件夾權限) chown gitlab-runner /www/test/gitlab-ci-example