2017年10月13日 星期五

gitlab CI/CD 簡單測試環境建置

和前一篇文章標題看起來差不多, 多了個  CD , 但花了不少時間測試才跑起來  ^^

主要是參考 這篇文件, 寫的非常完整.
部署用的工具是 envoy , 這是給 php 開發環境的.  如果是別的程式語言, 可以換成 ansible 或其他類似的工具.

這邊將主要說明上面那篇文件的做法與流程, 然後再補充實作時遇到的問題與處理/除錯方式.

文件提供的步驟,  剛開始看好像不是很直覺, 因為有些東西是後來要用到, 在較早的步驟就先準備好. 但是弄清楚整個 CI/CD 流程後, 會發現文件步驟其實是非常流暢的.

以 CI/CD 流程來說大致如下
  1. 將程式碼 push 到 gitlab
  2. gitlab-runner 依 .gitlab-ci.yml 設定的 stage 進行
  3. 第一個 stage 是 unit test
  4. 第二個 stage 是透過 envoy 來 deploy 到遠端的機器

從文件來看, 前面準備的項目用途如下:
  1. Unit Test Code :  供 phpunit 測試用的程式, 其實不寫也沒關係, laravel 有預設一個範例, 會讓 phpunit 回傳成功
  2. Configure the production server  , 先準備好要部署的目標機器
    a. create new user,  可以 ssh 登入的帳號, 並且對網頁 document root 有讀寫權限
    b. add ssh key , 這有兩個地方會用到
        一個是讓 enovy 不用密碼連到這台機器, 要將金鑰內容先以變數的方式放在 gitlab 設定裡, 然後在 .gitlab-ci.yml 裡透過變數取得金鑰內容
        另一個是讓這台機器可以從 gitlab clone project
    c. configuring nginx ,  主要是將 document root 先指向預備要部署的路徑
  3. create container image , 以 php 官方的 image 為主, 再加上 php composer 及 envoy 的自訂 image, 作者連 Dockerfile 都提供了.
    作者是將 image 放到  gitlab container register 裡, 這個非必要. 如果要放到 dockerhub 或其他地方, 記得修改 .gitlab-ci.yml 裡的 image 設定即可.

文件中提到一些 CI/CD 流程裡的小技巧蠻實用的 (對我這個新手來說), 例如說
  1. 將 ssh 金鑰以變數的方式存在 gitlab project 設定裡, 然後在 .gitlab-ci.yml 就可以透過變數取得內容, 避免將金鑰直接放在 git repo 裡.
  2. 測試用的 mysql 是透過 gitlab-runner 帶起來的, 所以可以另外指定測試用的連線資訊放在 .env.example , 就不會把實際的連線資訊放到 git repo 裡.

實作時的環境, 一台 google cloud engine (gcloud) , 一台 aws ec2 . 
gcloud 上以 docker 環境執行 gitlab / gitlab-runner ,  ec2 則是直接跑 nginx + php-fpm

在過程中, 因為不瞭解以及環境的差異, 有遇到的問題如下
  1.  gitlab-runner 會執行指定的 image 所跑起來的 container 內自動取得 project, 放置的路徑是在  /build/[gitlab 的 username]/[project name]
    例如我的 gitlab user 是 duan , project name 是 MyFamily , 所以路徑就是 /build/duan/MyFamily
    一開始不知道, 想說為什麼沒有在 .gitlab-ci.yml 做取得 code 的步驟, 就可以進行相關的動作如 composer install
  2.  一開始流程想錯, 想在自訂的  php-fpm image 就先透過 git 取得 code , 後來發現這樣每次都要重新 build image ,  還是依文件的流程才對.
  3. 因為我程式開發環境也是用 docker , 而且和 gitlab 放同一台. 原本想讓測試環境用現成的 mysql container , 但這樣會讓測試與開發環境使用的 database 混在一起, 應該不正確.
  4. 在 .gitlab-ci.yml 裡設定的 variable 是給測試環境裡執行 mysql container 用的, 而 .env.example 則是在測試時, 在跑 artisan migrate 時用的連線資訊.
    因為我不是用官方的 mysql image, 和作者環境不太一樣, 在這邊遇到一些連線問題, 從 gitlab jobs 的資訊可以看到無法連上 mysql.
    除錯方式就是自己手動跑一下  docker run -it mysql /bin/bash , 發現第一個問題是這個 image 的 mysql user 不能用 root 去執行, 會有錯誤.
    修正後, container 跑起來後,  手動以 mysql 指令來登入, 發現第二個問題.
    無法以 mysql user 變數裡指定的名稱做登入, 而是用 root 登入.
  5. 在以 envoy 部署時, 因為之前沒用過 envoy,  看到在  git clone 的步驟出現連線錯誤資訊, 以為是連到目標機器時產生的, 後來才發現這是從目標機器要 clone project 時的權限錯誤.
    除錯方式就是自己 docker run 測試用的 image , 然後一步步模擬 .gitlab-ci.yml 裡的動作, 才發現 ssh key 沒問題, 可以連到目標機器, 才發現可能是目標機器在 clone project 時的錯誤 (ssh key 沒設好, 直接改用 http 的 url 來 clone 就沒問題了).

其實還有不少小問題, 都是基於不瞭解整個流程而造成的, 而且一開始也因為不瞭解各流程的相關性, 而不知道該如何除錯, 導致每次改一點設定檔 , 就 push 到 gitlab 看結果, 這還蠻花時間的.

最後看到 CI/CD 整個流程完成,  感覺真是太爽了, 雖然這只是個新手入門的程度而已.  QQ

之後近期目標放在幾個方向
  1. CI/CD 的部份:
    a. 用 ansible 取代 envoy  ,  這樣可以處理其他程式語言的需求
    b. 把部署目標的環境改成 docker .  不過這點我還在思考, 這樣做的目的是什麼.
  2. php / Laravel 的部份:
    a. 練習多寫 unit test ,  這方面我很缺乏.
    b. 除了 unit test 外的測試方式.

另外, 隨著程式架構開始複雜,  也會影響 CI/CD 流程上的處理方式,  這就要隨時間慢慢累積經驗了.

沒有留言: