文章段落
《DevOps 是什麼? Google 實做 DevOps 的 SRE 方法介紹》中我們提到 DevOps 核心概念是解決開發與維運,甚至是測試部門間的衝突,以提高組織交付應用程式和服務的能力。而本次的 DevOps 教學將介紹如何使用 GitLab 部署 Google Kubernetes Engine(GKE),5 步驟達成 CI/CD!
DevOps 教學前言:CI/CD 是什麼?導入須知
CI/CD 是軟體敏捷式開發中「持續改善」理念的具體作法。其中 CI 指的是持續整合(Continuous Integration),將新版的程式碼自動建置和測試,確保程式碼沒有問題。而 CD 可視團隊狀況定義為持續交付(Continuous Delivery),將程式變更推送到測試環境,確保它是一個隨時可以部署到正式環境的狀態,或持續部署(Continuous Deployment),讓它完全自動部署到正式環境,不用手動部署。此次示範的 CI/CD 導入流程如下。
- 建立GitLab Server
- 設定環境
- 建立一個Gitlab Project
- 使用範例 .Net Core 程式碼 Commit 到GitLab
- 觸發 CI/CD 流程來建立 Docker Image,存放在 GCR 並且部署到 GKE
本文流程較長,使用工具很多,需要您先有的知識如下:
- 對 GCP 有初步了解,會建VM並操作SSH
- 對GitLab和Git有初步了解,會Commit程式碼
- 對 Kubernetes 了解一點點即可
為什麼要提這麼多呢?因為本實作有非常多坑在裡面,每個坑掉進去要花好幾個小時才能爬出來,我盡可能把陷阱都提示給您了,但實在太多太瑣碎所以不會 step-by-step來詳細說明,希望您不會踩到!
Gitlab 安裝方式可以參考這篇文章:https://docs.gitlab.com/ee/install/google_cloud_platform/
DevOps 教學步驟一:建立 GitLab Server
首先建立一台機器,如果只是測試不用開太大:
指定作業系統為 Ubuntu 18.04 LTS,Disk 大小建議最少30GB以上,下圖10GB是自己當初沒想到,給自己埋的雷……(你看到後面就知道了)
防火牆看您有沒有憑證,如果沒有只要開放HTTP就好:
等機器建好會拿到一個IP,強烈建議您使用固定IP,本人不在知情的狀況下使用臨時IP,埋了第二個雷……
DevOps 教學步驟二:安裝 GitLab
現在我們直接從GCP的SSH按鈕連進去這台主機,直接看這文件安裝就對了: https://about.gitlab.com/install/#ubuntu
先裝一些相依性的東西:
sudo apt-get update
sudo apt-get install -y curl openssh-server ca-certificates tzdata
接下來裝 postfix
sudo apt-get install -y postfix
它會引導到另一個畫面,詢問郵件設定的問題:
我選擇 Internet Site。
這裡是確認主機名稱,如果您是在GCP建的,它應該會自己帶資料出來,按OK即可。
終於要開始裝GitLab了。用以下指令下載 Gitlab:
curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash
接下來文件上是這樣寫的,記得你要改成你的domain或是IP位址:
sudo EXTERNAL_URL=”https://gitlab.example.com” apt-get install gitlab-ee
像我就是輸入這樣:
sudo EXTERNAL_URL=”http://35.185.135.182” apt-get install gitlab-ee
不用想入侵我的主機,該IP已不存在~嘿嘿~
接下來看它表演,我是說它會開始執行安裝流程:
大概5分鐘之後會看到歡迎畫面:
接著點擊 VM 的 IP, 用 HTTP 就好。
有耶,開心!!
相關環境設定,照一般流程註冊自己的帳號:
因為GitLab 會Build 一個 Docker Image,存在 Cloud Storage,之後也要拉 Image出來,並且部署到 Google Kubernetes Engine,需要兩個權限:
- Storage Admin
- Kubernetes Enginer Developer
所以我們必需要建立一個Service Account:
賦予權限:
不需要增加其他權限,直接按 Done:
另外也要給它一個 key
把key用Json格式下載下來:
檔名取為:
接下來要設定 CI/CD 環境變數,我們先回到GitLab主畫面,建立第一個 GitLab 專案:
命名,並且把專案設定為 Private,按下Create Project:
(後面我的Project Name有更改,因為反覆練了很多次)
它會說你現在不能 Push 程式碼,因為你還沒有 SSH Key
那我們就回到本機 (等等寫程式要Push Code的那台電腦),像我是Mac電腦的話,就輸入以下指令:
cd .ssh #去放有 ssh key的.ssh目錄 (在這裡我假設你已經有了)
cat id_rsa.pub #查看ssh key 的內容
然後複製從 “ssh-rsa”一直到你的 “email@xxx.com” 為止,貼到GitLab專案的 User Setting => SSH Keys
接下來回到首頁,可以看到第一次push code的教學:
在本機照著做看看,設定使用者:
把專案拉下來
這裡要補充一下,為了安全,我有設GCP的防火牆只允許公司的IP去連,所以就不能直接點 GCP Console 的SSH,而是要從我本機電腦去SSH,所以我要把SSH Key放在VM上。
接下來就用基本指令來 push 看看:
確認 code push上去之後,回到GitLab頁面重新整理,看到 README.md 出現了。
太棒了,到此 GitLab的環境設定完成。
DevOps 教學步驟三:CI/CD 環境設定
接下來就是重頭戲了,CI/CD環境設定,我們先到 Project 的Setting=>CI/CD頁面,新增一些環境變數,因為我們要做自動化,所以為了讓它真正做到全自動,就必須把環境變數設定好,不要嫌麻煩,這是一次工,之後就很輕鬆了。
首先是 GCP_SERVICE_KEY,相關的選項照以下的方式設定:
注意:Protect variable 要取消,不要打勾!!後面有洞!
GCP_PROJECT
GCP_ZONE
GCP_CLUSTER_NAME
我們先把 GKE Cluster的名字預先想好,設為環境變數。當然你要先建也沒問題。
gcloud container clusters create cluster-1 –num-nodes 2 –machine-type n1-standard-1 –zone asia-east1-a
如果您只是要測試,就不用先急著先建 Cluster,怕你浪費錢~
GCP_GCR
最後是這樣
做 docker build的設定檔 .gitlab-ci.yml (注意這是第一版)
注意:環境變數還要要補上這兩行,以免 Runner 出錯 (坑出現了,後面會解釋)
另外您的 service account key 要放在家目錄,您的Mac電腦本身的家目錄
而且要改名為 service_account.json
接下來把 asp.Net的範例程式碼抓下來,來源網址為:https://github.com/dotnet/dotnet-docker/tree/main/samples/aspnetapp
因為等等要 Push Code之後會觸發 CI/CD 流程,就先做到這裡,我們還有另一個重要的東西要做。
DevOps 教學步驟四:註冊 GitLab Runner
在GitLab的說明上會教你如何安裝並註冊Runner,我後來依照指引到這個網址來安裝 Ubuntu 的 Runner:
https://docs.gitlab.com/runner/install/linux-repository.html
我先登入到 GitLab 這台 VM,使用以下指令:
https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash
下載完執行安裝指令:
sudo apt-get install gitlab-runner
GitLab Runner 安裝之後,還需要向 GitLab Server 完成註冊,才算是真正的架設完畢。註冊的方式即是執行下面的 Command:
sudo gitlab-runner register
接下來回有一連串的問答
接下來是 Enter the registration token ,這個 token 會在 GitLab project的 setting => CI/CD頁面會看得到。
然後名字就任意輸入即可:
過程中我有碰到網路問題讓我註冊失敗,後來發現是GitLab要允許它自己的IP連線,所以我後來去改了防火牆規則:
整個註冊過程如下,還包括一些額外的問題:
注意:如果你中間有重開機的話,Token 會重新產生,所以要用新的Token重新註冊一次喔!(坑又來了)
整個註冊過程也可以用指令一口氣先寫好如下(後面註解要拿掉喔):
sudo gitlab-runner register -n \
–url http://你的VM的IP或網址/ \
–registration-token “FR7pk-GQwBavt7zysFYs” \ 注意token重開機會換掉,要重新註冊
–executor docker \
–description “you can write anything” \
–docker-image “docker:19.03.12” \ 用這個版本比較好
–docker-privilege true 有指定這個,就不用改 config.toml 的 value 為 true (後面再說明)
DevOps 教學步驟五:Push Code 以觸發 CI/CD 流程
環境已經設定得「差不多了」,真的是差不多而已,開始Run會發現還差很多。
一跑馬上錯,它說沒有 Runner ,但我明明剛剛才註冊好怎麼可能沒有?
後來發現是沒有裝 Docker,原來最基本的Docker都還沒裝~
可參考這個網址,回到GitLab的SSH,一直複製貼上就對了:
https://docs.docker.com/engine/install/ubuntu/
接下來就再跑一次,然後又看到另一個錯誤~
它連到我舊的IP (已經釋放掉了),所以一直出錯:
為什麼會這樣呢?因為我當初建VM的時候,使用的是 Ephermeral (臨時) 的IP,每次重開機它都會換一個新的IP,而我在做初始化設定時,GitLab會記錄那個IP到它的設定檔裡面,但我每次重開機換新IP的時候,GitLab並不知道,這算是一個大坑啊!!
好家在,後來找到這篇文章可以解決:
https://docs.bitnami.com/aws/apps/gitlab/configuration/change-default-address/
要去 vim /etc/gitlab/gitlab.rb
找到 external_url “https://gitlab.example.com”
改成
然後輸入 sudo gitlab-ctl reconfigure 讓它重新跑一次設定:
大概跑了2分鐘
GitLab網頁會出錯,不用擔心,它需要整個重啟,等它開好:
等它重啟完成,我們再按一次 Retry 的按鈕:
又看到另一個錯誤:
這個前面有提過,它是和Docker版本的問題有關,要回去改 .gitlab-ci.yaml
加這2行:
然後再push上去
另外還有一個地方,
/etc/gitlab-runner/config.toml 要把 runner 的 privileged 改成 true
你也可以在註冊 runner 時指定 –docker-privilege true (前面有提過)
還有環境變數要取消 Protect Variable 的勾勾,不然還是會出錯喔!
後來再 retry ,有看到錯誤,但它的狀態還是在 running,此時不要緊張,等它全部跑完……
因為目前VM只有1core,大概等了半個小時
有上GCR耶??好感動
但我的cluster其實還沒建,所以它只做好 build 好image,還沒deploy到GKE,這是正常的。
你想想看,前面錯誤一堆,都花時間在troubleshooting,根本都用不到GKE,如果當時就開好Cluster,看看現在帳單多少錢??(這叫做錢坑)
現在可以建Cluster了。
gcloud container clusters create cluster-1 –machine-type n1-standard-1 –num-nodes 2 –zone asia-east1-b
然後啊……
所以我才說VM在建的時候,Disk調大一點,後來我改成30GB。
你可以在不關機器的情況下加大喔!
但你還是要在機器裡面做 resize才算(其實步驟很多),參考這個: https://cloud.google.com/compute/docs/disks/add-persistent-disk#resize_partitions
我順便把GitLabe調成 n1-standard2 (2core 7.5GB),不然每次跑好久最後才看到錯誤,太浪費時間了!對了,重開機要再重新註冊Runner喔!
好了,再retry一次吧!
它的頁面refresh很慢,不要急。
看到這個,好感動!!
真的部署好了,太感動了!(看我多激動)
這裡我總結一下五大巨坑:
- 建GitLab要用固定IP,否則每次重開機又換新IP。
- 每次建新GitLab專案要重新設定環境變數和Runner。
- 每次重開機都要重新註冊Runner,參數要跟著調整。
- 要確保Disk夠大,避免事後調整浪費時間。
- GKE Cluster等到 Image 部署到GCR再建就好,不用晾在那邊累積帳單。
詳細的設定檔可以來這裡: