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

Nick
13 min readSep 22, 2019

以實務為例,帶領大家一步步學習 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 分鐘。

流程說明:持續性整合 ( CI )時機

  1. 把本機電腦開發完的新功能分支 ( Feature Branch )上傳到 Gitlab
  2. Gitlab 觸發 Gitlab-CI 執行 pipeline
  3. GitlabCI 執行自動化測試
  4. GitlabCI 回傳結果至 Gitlab,pipeline 執行通過則可以被執行 Merge

流程說明: 持續性部署 ( CD ) 時機

自動化部署流程
  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 (更新專案) 指令

重點一:如何在 Gitlab-CI 上執行自動化部署

搭建實作環境:使用 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
成功部署完成畫面

說明 gitlab-ci.yml 中自動化部署 ( CD ) 腳本

自動化部署(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,即可完成部署。
實際執行任務的畫面

重點二:整合 Gitlab CI/CD

目標:將自動化單元測試、自動化部屬整合成一個 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/

重點三:控制自動化部署(CD)只在特定分支執行

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

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

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

此次分享完整 .gitlab-ci.yml 程式碼

結尾

非常感謝大家鼓勵,原本預計搭配公司的工程月會時程產出文章,想不到此篇一週後就完成了。而此次內容已經完整實作一個產品最基礎的 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

嗨 我是 Nick,目前在 ShopBack 擔任軟體工程師,喜歡用科技解決問題,偶爾會整理一些工作上的發現分享在這,歡迎大家追蹤及交流