Gitlab CI/CD 教學 從零開始快速上手 Runner 與 YAML 設定

me
林彥成
2022-05-30 | 4 min.
文章目錄
  1. 1. 什麼是 CI/CD?
    1. 1.1. DevOps
    2. 1.2. Infrastructure as code (IaC)
    3. 1.3. Docker
    4. 1.4. 專案的準備
  2. 2. Gitlab CI
    1. 2.1. .gitlab-ci.yml 案例解析

什麼是 CI/CD?

CI (Continuous Integration)、CD (Continuous Delivery/Deployment) 目的是從測試、建置到部署自動化,取代原來人工需要做的事情。

  • CI (Continuous Integration): 專注在持續整合,透過程式碼的自動化測試和建置,將穩定品質的程式碼合併,越早頻繁整合,整合難度的就越低且能確保最新版本是可運行的
  • CD (Continuous Delivery/Deployment): 專注在持續部屬和交付,依照需要的環境進行建置和部屬

在相關版本控制工具尚未推出 CI/CD 服務前,常見的會是 Jenkins,但使用者入門大多使用 GUI 進行配置與操作,所以 GUI 在多人編輯的情況下,配置的版本控制就稍微困難。

近代在 YAML 出現之後,Code as Infrastructure 成為顯學,透過將雲端配置用程式碼描述,即使是 Jenkins UI 非常方便也建議透過程式碼來進行配置。

目前常見的 Github Aciton 和 Gitlab CI 其實都是透過 YAML 進行設定與配置

  • 定義必要的 “觸發條件”、”環境”、”步驟”
  • 讀取預先設定的環境變數進行建置、上板

DevOps

DevOps (Development Operations),是一種新的概念與職缺,透過將系統容器化搭配 CI/CD 並建立 Infrastructure as code (IaC),進而達到自動並有效率的維運雲端的資源和系統,節省時間與成本。

CI pipline -> 產生 Docker Image
CD pipline -> Pull Docker Image -> 環境檔 -> 部屬容器

Infrastructure as code (IaC)

將架構透過程式碼表示的好處

  • 可程式化代表可做到驗證與防呆
  • 能夠進版控
  • 更容易擴充

Docker

Docker 是一種容器化技術,能夠將系統透過 Container 運行。

  • Image: 透過映像檔的建立將環境重複使用
  • Container: 是 Image 運行起來的狀態,會搭配環境變數和配置去運行

因此開發或是正式環境能維持隔離減少彼此影響,更容易維護和升級。

常見的 Docker 預備知識

  • YAML: Image 透過 YAML 描述和建置
  • Docker Config:
    • Port binding: 容器內的系統會透過 Port 提供服務,所以需要和本機上的 Port 做連結
    • Logs: 透過容器的 Log 來查看系統紀錄
    • --network=host: 容器網路的模式
    • -d: 背景執行

管理容器的工具軟體

  • Docker Compose: 組合多個 container 依照順序啟動的一個工具
  • Docker Swarm: 原生容器調度管理平台,適合處理多部伺服器部屬多個容器的情境
  • Kubernetes: 容器調度管理平台,適合處理多部伺服器部屬多個容器的情境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Set the base image to node:16-alpine
FROM node:16-alpine as build

# Specify where our app will live in the container
WORKDIR /app

# Copy the React App to the container
COPY . /app/

# Prepare the container for building React
RUN npm install
RUN npm install react-scripts -g
# We want the production version
RUN npm run build

# Prepare nginx
FROM nginx:1.16.0-alpine
COPY --from=build /app/build /usr/share/nginx/html
RUN rm /etc/nginx/conf.d/default.conf
COPY nginx/nginx.conf /etc/nginx/conf.d

# Fire up nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

專案的準備

版本控制: 依照版本持續整合
程式碼分析: 檢查 code style 或基本語法錯誤
建置: 確保程式碼真的可以被建置與執行
自動化測試: 確保功能正常與軟體品質
自動的部署: 用同一個包裝好的套件 (package) 透過環境檔來控制和部署任何版本的軟體到不同的環境

Gitlab CI

一個 .gitlab-ci.yml 如前述會包含 “觸發條件”、”環境”、”步驟”

  • 觸發條件: PR、PUSH、分支合併
  • 環境: Node、Python、Java 等等
  • 步驟: 常見會有三個步驟
    • verify: 透過 Linter 或是測試確認程式碼品質
    • Package: Build Code
    • Release: APK 就會是包版、前後端就會是上版
圖片來源: https://docs.gitlab.com/ee/ci/introduction/

主要是透過 .gitlab-ci.yml 來定義相關的步驟,當步驟設定完成後,會需要了解兩個概念

  • pipeline
  • gitlab runner: 負責運行 pipeline 中 job
    • Shared Runner: 不同的專案可以共用
    • Group Runners: 同開發群組 (部門) 共用
    • Specific Runner: 指定給特定專案使用,小編在實務上也會透過 Specific Runner 來指定要發佈的環境

常用指令

  • sudo gitlab-runner register,有 docker 或是 shell 的區別
    • docker in docker 版本比較適合跑一些 lint
    • shell 版本可以拿來操作本機上 docker 較適合拿來部屬
  • gitlab-runner verify --delete

.gitlab-ci.yml 案例解析

以一個前端專案來說,常見需要人工介入的情況有

  • 進行程式碼的 lint
    • style lint
    • eslint
  • 依照環境
    • 進行 npm install
    • 建置各站台的版本
  • 上傳到各個不同環境的站台
  • 進行單元測試
  • 進行 E2E 測試

實作

  1. 變數設定,因為 config 會是一個公開的檔案,通常不會希望直接把 key 或是 token 直接放在裡面,這時候就會透過變數來存取及互動
  2. 步驟實作
    • 透過 GUI 的畫面
    • 透過 config 的 stages 或 steps
  3. 觸發條件
    • 排程
    • 分支變化
    • 使用者動作

常見問題

  1. 透過 GUI 的介面較容易直觀的去設定 ssh key 或是相關的登入帳號密碼,透過 yaml config 就會稍微複雜一些,通常會是需要直接設定到 Linux 的環境當中。
  2. CI/CD 的過程中在設定的時候需要等實際跑過一遍才知道問題出在哪,會需要大量花時間去試錯
    • Gitlab 的介面中有 ci lint 可以使用
    • Github Action 有很多網友實作的工具蠻建議直接套用
  3. 平行處理加速效能
  4. 重要變數儲存 Environment Variable,讓 Runner 啟動後將這些資訊設為環境變數,Gitlab 就有提供這方面的設定,可以先進到 Gitlab Project > Settings > CI / CD > Variables ,便在裡面逐一設定上方有宣告的變數。

詳細文件請參考:
https://docs.gitlab.com/ee/ci/yaml/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
stages:
- lint
- build
- test
- deploy

eslint:
stage: lint
script:
# Install ESLint in this docker container
- npm install -g eslint
# Configure ESLint (will read your .eslintrc file)
- eslint --init
# Run ESLint
- eslint <your_js_file>

build:
stage: build
script:
- npm run build
- docker build -t f2e-example .

test:
stage: test
script:
- npm run e2e

deploy:
stage: deploy
script:
- docker run -d --name f2e-example -p 3000:3000 f2e-example

喜歡這篇文章,請幫忙拍拍手喔 🤣


share