[教學] Gitlab-CI 入門實作 — 自動化部署篇

陳建宇
陳建宇
Sep 22, 2019 · 13 min read

以實務為例,帶領大家一步步學習 Gitlab-ci 上各種關鍵字的用法

上篇分享如何在 Gitlab-CI 上執行單元測試,並限制通過測試才可合併分支,而接下來就是本篇的部署了,分享重點會著重在 Gitlab-CI 的部分,以實務例子帶大家更進一步理解 Gitlab-CI 語法設定及部署方式:

  1. Gitlab-CI 自動化測試 (單元測試入門篇)
  2. Gitlab-CI 自動化部屬部署 ✔ 本篇
  3. Gitlab-CI 開發流程細節、整合測試、測試報表

注意:本篇將延續上篇講解的內容,如果不清楚以下 Gitlab-ci.yml 內容,建議先看看上篇,可點擊傳送門移動過去:

<單元測試範例> 如有不懂可點擊以下連接看上一篇文章
  1. 有任何方式可以使用指令或腳本將專案部署到遠端伺服器嗎?
  2. 在 Gitlab-CI 中如何設定才能在測試成功下執行部署?
  3. 在 Gitlab-CI 中如何才能指定 Job 只在特定 branch 執行嗎?

以上議題如果有任何不清楚或不了解的,我覺得此篇文章將可以給你一點方向,本篇閱讀時間約為 10 分鐘,實作 45 分鐘。

  1. 把本機電腦開發完的新功能分支 ( Feature Branch )上傳到 Gitlab
  2. Gitlab 觸發 Gitlab-CI 執行 pipeline
  3. GitlabCI 執行自動化測試
  4. GitlabCI 回傳結果至 Gitlab,pipeline 執行通過則可以被執行 Merge
自動化部署流程
  1. 把新功能分支 Merge 進入 master 分支(此時功能代表已經是合法可上線的功能了)
  2. Gitlab 觸發 Gitlab-CI 執行 pipeline
  3. GitlabCI 執行自動化測試
  4. GitlabCI 測試成功後,執行部署到正式伺服器
  5. 回傳執行結果至 Gitlab

想要達成「自動化部屬」之前

要先能達成「能遠端用指令下達部署更新」

實作上大概要做兩件事:

  1. 整理在更新專案時需要哪些指令,將其寫成腳本
  2. 獲得伺服器授權,來對伺服器下達更新專案的腳本

以 laravel 專案為例:

  1. 腳本製作:上線新版本大概要執行以下圖片中的內容

補充:細節上還要注意打包、更新套件時間會不會影響產品服務,如果可以透過一些預先打包、更新來優化

在 laravel 上線新版本程式碼,預計會下達的指令

2. 對遠端伺服器下指令:最底層都是使用 ssh 與伺服器連線溝通,所以先在伺服器產生授權金鑰給與要遠端控制的電腦,如果是想給 Gitlab-CI 控制的就也要把金鑰存在 Gitlab 上,以下舉例一個最基礎使用 git 更新專案的控制程式碼。

補充:在管理指令腳本上有許多工具,比如 Ansible 或 Laravel有 envoy 套件

ssh 遠端對伺服器下達 git pull (更新專案) 指令

搭建實作環境:使用 Heroku 平台建置遠端伺服器環境

因本篇文重點想著重在於 Gitlab-CI 如何做自動化部屬,所以我們選用 Heroku 這種 Paas 的平台做為遠端伺服器,以減少過度花時間架設環境。(且他有免費的方案正適合這種開發練習)
如果有跟我一樣對雲端平台不是很熟悉的朋友,推薦這份簡報「十分鐘讓程式人搞懂雲端平台與技術」。

擷取一部分來補助說明大家常見的虛擬機與 heroku 平台上部署專案的差別:

圖片取至簡報 十分鐘讓程式人搞懂雲端平台與技術
  1. 虛擬機是由主機服務商提供 “基礎建設即服務”( Iaas ):初級的如 Linode,高級點的如 AWS EC2,在服務商將上圖綠色選項目完成,剩餘的藍色項目。如想架設一個 Laravel 為底的網頁服務,免不了連上虛擬機中手動安裝如:php、nginx、php-fpm、mysql、node、composer 等等服務相依的套件。
  2. “平台即服務” (Paas):代表如 Heroku ,如果同樣想架設一個 Laravel 服務,將改以服務的 API 指令需要的套件內容,該平台將依據這些內容把整個服務架設起來。

創建 Heroku 帳號即專案

註冊帳號後點選 Create a new app

觀看產出的專案服務頁面

點選右上角的 Open app 就可以看到此 專案頁面 在公開的網域頁面了
預設專案服務畫面

申請部署 API 並加入到 Gitlab 上

點選右上角帳號設定 => Applications => Create Authorization 產生一組 Token

在 Gitlab 中加入部署所需的變數

  1. 變數名(HEROKU_PRODUCTION_PROJECT_NAME):同 Heroku 部署專案名稱
  2. 變數名(HEROKU_PRODUCTION_API_KEY):部署 Token
回到 Gitlab 平台點選 Setting -> CI/CD -> Variables 加入部署Token

調整程式碼及 .gitlab-ci.yml

注意檔案位置及內容( Procfile 、.gitlab-ci.yml 都是在專案根目錄)
  1. 承接上篇 laravel 專案範例,開設新分支 test_for_cd
  2. 新增檔案名稱為 Procfile 於專案根目錄(注意不需要副檔名),此為 Heroku 在部署更新時啟動的對象,比如範例為我們網頁服務使用 apache2 指令運行並把入口指向專案資料夾中 laravel 專案的入口資料夾
web: vendor/bin/heroku-php-apache2 public/

3. 建立或取代 .gitlab-ci.yml 檔,設定自動化部屬的任務 Job 及腳本

上傳至 Gitlab 來觸發 Gitlab-CI 執行自動化部屬

git commit -a -m "settle for continuous deployment"
git push origin test_for_cd
自動化部屬執行完成
(這步不需要實作)把 Debug 模式打開後可發現,問題是沒給予環境變數 APP_KEY
補加專案所需環境變數 APP_KEY,可以從本地專案的 .env 中取得,Heroku -> Setting -> Config vars
成功部署完成畫面
自動化部署(CD)腳本

環境變數 (environment variables)
環境變數大致可分為三個地方設定

  1. 預設環境變數:例如 $CI_COMMIT_REF_NAME 可以取得 branch 名稱、$CI_COMMIT_SHA可以得此次版本最後的 commit hash 資料
  2. CI/CD 環境變數:撰寫在 Gitlab 上,在本篇文章前已經有先把 Heroku 專案的名稱及部署 Token 存進去了(名稱為 HEROKU_PRODUCTION_PROJECT_NAME 跟HEROKU_PRODUCTION_API_KEY)
  3. 任務環境變數:可以在任務中自行定義變數,此次範例中使用 HEROKU_PROJECT_NAME 變數取用已經有設定在 CI/CD 環境變數的值,雖然有點雞肋,因為其實腳本原本就是可以取用 CI/CD變數,不需要重複宣告一次,但這樣設定可以提醒這個任務是會使用到變數的,習慣上我會這樣設定。

自動化部屬腳本(Continuous Deployment Script)

  1. 任務執行前腳本(Before Script)
    因為這一部分執行目的是將部署需要的套件成功安裝,跟任務主要邏輯是相依關係不是直接關係,但區隔後可以比較明確知道哪些部分是主要 Script,因此決定與 Script 分離。但實際上合併或分離並不會影響執行結果
  2. 主要執行腳本(Script)
    自動化部屬指令執行使用 dpl 這個指令套件,裡面建立有 heroku 的部署工具,只要指定部署專案名稱、部署 Token,即可完成部署。
實際執行任務的畫面

目標:將自動化單元測試、自動化部屬整合成一個 Pipeline (產線)

部署條件1:完成測試的版本才能進行部署

這邊是一個 CI/CD 合併的 gitlab-ci.yml,裡面包含到

  1. 自動化單元測試(任務為 unit_test)
  2. 自動化部屬(任務為 production_deploy)

我們試著 push 到 Gitlab 觸發看看會發生什麼問題。

自動化整合、部署 ( CI/CD ) 錯誤範例 v1 設定檔
自動化整合、部署 ( CI/CD ) 錯誤範例 v1 執行結果

問題描述:

如果測試單元沒有通過,理論上此版本不應該被部署,因為這樣就會把錯誤的內容丟到正式機器上。


要在 Gitlab-CI 上達成有限制的執行任務,可以使用 stages 語法

自動化整合、部署 ( CI/CD ) 範例 v2
當 unit test 不通過時,後面階段 ( stage ) 預設將會被略過
當 unit test 不通過時,後面階段 ( stage ) 預設將可依序被執行

這個設定的執行結果可以看到成功達成了部署條件1:

在持續性整合(CI)都通過後,才能進行持續性部屬(CD)。

以下再來統整一下一直提到的 Pipeline、Stage、Job 關係。

Pipeline、Stage、Job 涵蓋範圍

Pipeline > Stage > Job

  • Job:是整個 Gitlab-CI 裡面最小的執行單位
  • Stage:可以包含一個或多個 Job,代表一個執行階段
  • Piepline:可以由一個或多個 Stage 組成,即是一次 CI/CD 的所有執行階段,且會依序執行 Stage。如果執行過程中只要有一個 Job 錯誤了,預設後續的 Stage 都會被略過(skip)。

以下有一個比較豐富、完整的 pipeline 動圖,可以比較清楚整個執行的方式。此 pipeline 有三個 stage,stage 內的任務 Job 如果 gitlab runner 夠將可以同步執行,一個 stage 都通過後才會往下一個 stage 移動。

圖片取至 https://lorisleiva.com/laravel-deployment-using-gitlab-pipelines/

目標:設定 Job 執行條件
部署條件2:要是 master 分支 (指定 branch) 才進行自動化部署

問題敘述:如果不設定自動化部屬的執行條件,將會造成線上版本不斷被不相關的版本覆蓋,造成極大的不穩定,因此通常開發上只有一個分支能部署到正式環境上,那就是 master 分支。而 Gitlab 中還可以設定 master 分支必要通過以下步驟才能有新版本

  1. 只能通過發 Merge Request 方式
  2. 需要被 Review 過並寫上通過評論
  3. 需要有管理者權限才能執行
使用 only 語法修改 gitlab-ci.yml 自動化部屬(只能在 master 分支執行)
可看到一般 branch 無執行部署,只有在合併到 master 的版本才執行

非常感謝大家鼓勵,原本預計搭配公司的工程月會時程產出文章,想不到此篇一週後就完成了。而此次內容已經完整實作一個產品最基礎的 CI/CD 設定了,這系列文章目的是希望大家能藉此入門 Gitlab-CI ,甚至在工作上應用看看,而講述方式比較是以實作導向。如果要對 Gitlab-CI 有更全面認識可以參考官方文件都寫的蠻清楚的。

發問 1 :伺服器大集合

此文章中講述自動化部屬時,是用 heroku 為伺服器。但大部分公司應該不會使用 heroku 作為服務的伺服器,因為很貴很貴,大部分還是使用 AWS、GCP、Linode 等等自己管理的伺服器。但不同的伺服器設定方式會有些差異,所以想整理一篇自動化部屬與伺服器溝通的文章。因此想問問大家:

工作上都用哪些平台作為伺服器,及使用什麼方式部署新版本?

發問 2 :開發流程大集合

下篇系列文章預計針對實際開發流程上進行優化,並帶入 Gitlab-CI 一些如 cache、artifact 的實務用法,但這些內容使用我自己工作上的方式可能不太完整,所以:

想問問大家平常工作上都使用哪種開發流程呢?

例如但不限於,希望大家可以留言告訴我:

  1. 開發測試上有無需要先 build 專案的需求,如整合測試、前端打包
  2. 開發流程到正式部版前是否有什麼 Review階段,比如 staging 測試機
  3. 開發上實際有使用什麼樣的測試項目

補充:如果使用 Laravel 及 GCP 為開發環境的,可以參考這篇文章:

如果喜歡我這篇文,可以幫我拍手 1-10 下
如果覺得這文章對你有幫助,可以幫我拍手 10–30
如果覺得想看到更多關於學習筆記的文章,可以幫我拍手 30–50
讓我知道也記得 Follow我 陳建宇
更歡迎你在下方留言,我很樂意與你討論聊天或回答問題!

Nick-hacking

在踩雷的路上有你有我不孤單,希望藉由這個紀錄讓更多人路走更直

陳建宇

Written by

陳建宇

熱愛利用科技解決問題 | 喜愛分享 | 超過四年兒童程式教育經驗 | 現為 Pinkoi 前端工程師 | 曾任小雞上工全端工程師 | 往Clean Coder 邁進

Nick-hacking

在踩雷的路上有你有我不孤單,希望藉由這個紀錄讓更多人路走更直

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade