天天看點

搭建項目_搭建一個使用 GitLab CI 的項目

搭建項目_搭建一個使用 GitLab CI 的項目

前言

産品需求評審後,各自拆分任務,從

master

分支切出一個

release

分支,根據各自任務情況切出

update

feature

的開發分支;

開發調試或提測時,将代碼

push

到遠端分支,提

merge request

(以下簡稱 mr)到

test

分支,

GitLab CI

将項目代碼自動建構并部署到測試環境;

測試完畢後提

mr

release

分支,待本次需求的開發分支都

code review

并合并後,從

release

分支提

mr

pre

分支,

GitLab CI

将項目代碼自動建構并部署到預生産環境,然後進行回歸測試,有問題再從

release

分支切出開發分支進行修改,重複之前的流程。

預生産環境沒問題後,從

release

分支提

mr

master

分支,,然後打

tag

上線,

GitLab CI

将項目代碼自動建構并部署到生産環境,然後進行回歸測試,有問題再發版。

至此一次需求的完整開發流程就告一段落了,其中建構/部署等一些重複工作都是

GitLab CI

幫我們完成,對此一直很好奇,接下來我們就來嘗試搭建一個使用

GitLab CI

的項目。

搭建新項目

現有項目中使用

GitLab CI

可以直接跳過這步,從這裡開始

可以按下面的步驟一步一步搭建,也可以直接克隆這個倉庫:gitlab-ci-example

初始化項目

建立項目檔案夾

mkdir gitlab-ci-example
cd gitlab-ci-example
           

初始化 git 和 npm

git init
npm init -y
           

建立項目檔案

mkdir src build
           

建立 .gitignore 檔案

gitlab-ci-example/.gitignore
dist
node_modules
           

建立 .editorconfig 檔案

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
           

建立 index.html 檔案

gitlab-ci-example/src/index.html
<!DOCTYPE html>
<html >
  <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>
           

建立 main.js 檔案

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()}`,
});
           

建立 webpack.dev.js 檔案

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",
    }),
  ],
};
           

建立 webpack.prod.js 檔案

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",
    }),
  ],
};
           

建立 append-element.js 檔案

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());
});
           

建立 deploy-test.sh 檔案

gitlab-ci-example/build/deploy-test.sh
cp -rf dist/* /www/test/gitlab-ci-example
           

修改 package.json 檔案

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/ ,你應該能看到:

搭建項目_搭建一個使用 GitLab CI 的項目

打包項目

npm run build
           

在浏覽器中打開

dist

目錄下的

index.html

檔案,你應該能看到:

搭建項目_搭建一個使用 GitLab CI 的項目

至此項目的基本功能搭建完成,接下來開始在項目中使用

GitLab CI

項目中使用 GitLab CI

使用

GitLab CI

之前,你得先準備一下:

  • 一台雲伺服器
  • 一個

    GitLab

    倉庫

設定 GitLab Runner

在倉庫首頁,點選側邊欄 -

Settings

-

CI / CD

,跳轉

CI / CD Settings

頁面,展開

Runners

選項,按步驟手動設定

GitLab Runner

搭建項目_搭建一個使用 GitLab CI 的項目

安裝 GitLab Runner

根據系統架構,下載下傳并安裝對應的軟體包,檢視詳情

# 下載下傳(适用于amd64的軟體包)
curl -LJO https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb

# 如果下載下傳太慢,建議在本地下載下傳好之後,通過scp指令複制到遠端,類似這樣
# scp ~/gitlab-runner_amd64.deb [email protected]:/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

注冊 GitLab Runnner

開始注冊,下面是

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 CI 的項目

配置 GitLab CI

設定完

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 的項目
搭建項目_搭建一個使用 GitLab CI 的項目

儲存

.gitlab-ci.yml

檔案後,将改動

push

到遠端倉庫

觸發 GitLab CI

配置檔案有了之後,我們需要将其觸發,從包含上面改動的分支,切出一個

test

分支,送出到遠端,用于觸發

GitLab CI

(新送出和合并

test

分支都會觸發

CI

),當然通過圖形化界面建立

test

分支也是可以的

git checkout test
git push -u origin test
           

在倉庫首頁,點選側邊欄 -

CI / CD

-

Pipelines

,就能看到目前倉庫所有的

CI

記錄,類似下面這樣:

搭建項目_搭建一個使用 GitLab CI 的項目

遇到的問題

1. mkdir: cannot create directory ‘/home/gitlab-runner/builds/3-1Hb5zy’: Permission denied

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

按鈕,點選按鈕嘗試重新運作建構

2. bash: line 92: npm: command not found

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
           

3. sh: 1: build/deploy-test.sh: Permission denied

$ npm run deploy-test
> [email protected] 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! [email protected] deploy-test: `build/deploy-test.sh`
npm ERR! Exit status 126
npm ERR!
npm ERR! Failed at the [email protected] 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

檔案不具備可執行權限,是以無法執行

如何解決:
  1. 直接更改

    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
           
  1. 通過

    sh

    命名執行

    deploy-test.sh

    檔案
# package.json
- "deploy-test": "build/deploy-test.sh",
+ "deploy-test": "sh build/deploy-test.sh",
           

4. /www/test/gitlab-ci-example: No such file or directory

$ npm run deploy-test
> [email protected] 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 的項目

通過

.gitlab-ci.yml

配置檔案,你可以在建構的各個階段做處理,比如你可以在

before_script

after_script

階段調用釘釘機器人接口,及時将部署狀态同步到個人/群:

before_script:
  # 釘釘通知 釘釘群
  - curl -X POST 'https://oapi.dingtalk.com/robot/send?access_token=xxx&xxxx'
           

通知類似下面這樣:

搭建項目_搭建一個使用 GitLab CI 的項目

更多關于

.gitlab-ci.yml

檔案的配置資訊,請看官方文檔

好利用

CI / CD

這件工具,相信會大大提升團隊協作和開發效率。萬事開頭難,起初肯定會有抵觸心理,邁過這道坎之後,還有下一道坎等着你[手動狗頭]

示例項目的倉庫連結如下,歡迎

star

github

倉庫(

template

):https://github.com/Lsnsh/gitlab-ci-example

gitlab

倉庫:https://gitlab.com/Lsnsh/gitlab-ci-example

指令彙總

# 檢視 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 [email protected]:/home/yourUserName
# eg: (将檔案 ~/gitlab-runner_amd64.deb 拷貝到遠端主機,公網 IP 為 110.120.130 的 root 使用者目錄下)
scp ~/gitlab-runner_amd64.deb [email protected]:/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
           

參考連結

  • Install GitLab Runner
  • Registering Runners
  • Error when installing gitlab-runner
  • Permission denied for build.sh file
  • GitLab CI/CD Pipeline Configuration Reference
  • Gitlab CI Failed: NPM command not found
  • How to create file execute mode permissions in Git on Windows?

繼續閱讀