概述
在本教程中, 你將學習到如何在 Kubernetes engine 中, 使用 Jenkins
來設定持續交付管道。 Jenkins 是一個開發者們經常會使用到的自動化 server, 這些開發者們會經常的需要將他們的程式碼整合到一個共同分享的倉庫中…
在本教程中你將建立一個解決方案, 如下方圖表:
你可以在這裡找到更多在 Kubernetes 中運行 Jenkins 的資訊
你將會做什麼?
在本教程中, 你將會完成以下的任務:
- 提供一個 Jenkins 應用到 Kubernetes Engine 叢集中
- 使用 Helm Package Manager 來設定你的 Jenkins 應用
- 探索 Jenkins application 的功能
- 建立以及運作 Jenkins 管道
先決條件
這是一個進階等級的教程。 在我們開始之前, 你應該要會基礎的 shell 程式, Kubernetes, 以及 Jenkins 。 這裡有一些 Qwiklabs 的課程可以讓你達到應有的速度:
- Introduction to Docker
- Hello Node Kubernetes
- Managing Deployments Using Kubernetes Engine
- Setting up Jenkins on Kubernetes Engine
如果你已經準備好了, 往下拉, 學習更多 Kubernetes, Jenkins, 以及持續交付。
Kubernetes Engine 是什麼?
Kubernetes Engine 是由 GCP 所管理的 Kubernetes
版本 - 一個強大的叢集管理器以及容器編排系統。
Kubernetes 是一個開源的專案, 可以運行在很多不同的環境上, 從筆電到高可用的多主機叢集; 從公開的雲端到人為部署; 從虛擬機到裸機
如上所敘, Kubernetes 應用建立在 容器上
- 有一些含有所有 dependencies 以及 libraries 的輕量化應用來運行 Kubernetes 應用。 這些底層的架構讓 Kubernetes 更加的高可用, 安全, 以及快速部署 - 這是雲端開發者理想中的框架
Jenkins 是什麼?
Jenkins 是一個開源的自動化 server, 它可以讓你更靈活的編排你的 build, test, 以及部署管道。 Jenkins 讓開發者可以更快速的迭代專案, 不需擔心由持續交付所造成的問題
什麼是持續交付 / 持續部署?
當你需要設定 continuous delivery (CD) pipeline (持續交付管道), 部署 Jenkins 到 Kubernetes Engine 相比傳統一般的 VM 部署, 提供了巨大的好處
當你使用容器來運行 build 程序, 虛擬主機可以在多作業系統上運行 jobs 。 Kubernetes Engine ephemeral build executors (暫時性的 build 執行者)
- 他們只有當 builds 需要運行時才會被使用到, 這個機制可以將資源留給其他有需要的叢集任務, 像是批量處理的工作。 另外一個 ephemeral build executors 的好處是它的速度 - 啟動只是幾秒鐘的事
Kubernetes Engine 也內建了 Google 全球平衡負載, 你可以利用它來將流量自動化的導向你的機器。 平衡負載提供了 SSL 處理端點, 以及使用一個由 Google 的基礎網路設定的全球 IP - 與你的前端配合, 這個平衡負載將建立一條在你的服務與使用者之間最有效率的通道
現在你已經知道一點 Kubernetes, Jenkis, 以及兩者之間如何在 CD 管道中互動的知識, 是時候來自己做一個了。
設定及要求
在你按下 Start Lab 按鈕之前
詳讀所有的教學。Labs 是有時間限制的,而且你不可以停止時間倒數。倒數計時器在你按下 Start Lab 按鈕後開始倒數,上面顯示的時間為你還能使用 Cloud 資源的時間。
Qwiklabs 的手把手環境,讓你可以在真實環境中來操作進行 Qwiklabs 上提供的課程,而不是在一個模擬或是展示的環境。我們透過提供你一個全新的、暫時的帳號密碼,在計時器歸零之前,你可以用來登入並存取 Google Cloud Platform。
你需要什麼?
要完成這個 lab ,你需要:
- 一個一般的網路瀏覽器(推薦 Chrome)
- 完成這個 lab 的時間
備註: 如果你已經有你自己的個人 GCP 帳號或專案,請不要使用在這一個 lab
現在你已經開始你的 lab
, 你將會登入 Google Cloud Shell
主控台,然後開啟命令列工具
如何開始你的 lab ,然後登入 Console?
- 按下 Start Lab 按鈕。如果你需要付費,會有一個彈出視窗來讓你選擇付費的方式。在左方你會看到一個面板,上面有暫時的帳號密碼,你必須使用這些帳號密碼在此次 lab
- 複製
username
, 然後點擊Open Google Console
。 Lab 會開啟另外一個視窗,顯示選擇帳號
的頁面
tip: 開啟一個全新的視窗,然後跟原本的頁面並排
- 在
選擇帳號
頁面, 點擊Use Another Account
- 登入頁面開啟,貼上之前複製的
username
以及password
,然後貼上
重要:必須使用之前於 Connection Details 面板
取得的帳號密碼,不要使用你自己的 Qwiklabs 帳號密碼。 如果你有自己的 GCP 帳號,請不要用在這裡(避免產生費用)
- 點擊並通過接下來的頁面:
- 接受
terms
以及conditions
- 不要增加
recovery optoins
或two factor authentication
(因為這只是一個臨時帳號) - 不要註冊免費體驗
- 接受
稍待一些時候, GCP 控制台將會在這個視窗開啟。
注意:按下左上方位於Google Cloud Platform
隔壁的 Navigation menu
,你可以瀏覽選單,裡面有一系列的 GCP 產品以及服務
啟動 Google Cloud Shell
Google Cloud Shell
是載有開發工具的虛擬機器。它提供了5GB的 home 資料夾,並且運行在 Google Cloud
上。 Google Cloud Shell
讓你可以利用 command-line 存取 GCP
資源
- 在
GCP 控制台
,右上的工具列,點擊Open Cloud Shell
按鈕
- 在打開的對話框裡,按下
START CLOUD SHELL
:
你可以立即按下 START CLOUD SHELL
當對話視窗打開。
連結並提供環境會需要一點時間。當你連結成功,這代表你已成功獲得授權,且此專案已被設為你的專案ID,例如:
gcloud 是 Google Cloud Platform
的 command-line 工具,他已事先被安裝在 Cloud Shell
並且支援自動補齊
使用這個 command ,你可以列出有效帳戶名稱:
gcloud auth list |
輸出:
Credentialed accounts: |
範例輸出:
Credentialed accounts: |
你可以使用以下 command 來列出專案 ID
gcloud config list project |
輸出:
[core] |
範例輸出:
[core] |
gcloud
的完整文件可以參閱 Google Cloud gcloud Overview
複製倉庫
一開始, 在 Cloud Shell 開啟一個新的視窗, 執行以下的指令來設定 zone 為 us-east1-d
gcloud config set compute/zone us-east1-d |
複製本教程的範例程式碼:
git clone https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git |
切換到正確的資料夾內:
cd continuous-deployment-on-kubernetes |
提供 Jenkins
建立一個 Kubernetes 叢集
現在執行以下的指令來建立一個 Kubernetes 叢集
gcloud container clusters create jenkins-cd \ |
這個步驟會耗費幾分鐘完成。 額外的 scopes 讓 Jenkins 可以存取 Cloud Source Repositories 以及 Google Container Registry
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功建立 Kubernetes 叢集, 你將獲得一個評價分數。
在開始前, 使用以下指令來確認你的叢集有在正常運行中
gcloud container clusters list |
現在, 取得叢集的憑證
gcloud container clusters get-credentials jenkins-cd |
Kubernetes Engine 使用這些憑證來存取你新建立的叢集 - 使用以下指令來確認你可以連接它
kubectl cluster-info |
安裝 Helm
在本教程中, 你將會使用 Helm, 從 Charts 倉庫來安裝 Jenkins 。 Helm 是一個套件管理器, 他讓設定以及部署 Kubernetes 應用更加的簡單。 一旦你安裝了 Jenkins 到你的叢集, 你將可以設定你的 CD/CD 管道。
下載以及安裝 helm 二進制檔
wget https://storage.googleapis.com/kubernetes-helm/helm-v2.14.1-linux-amd64.tar.gz
在 Cloud Shell 中解壓縮檔案
tar zxfv helm-v2.14.1-linux-amd64.tar.gz
cp linux-amd64/helm .把你自己加到叢集的 RBAC 中, 身份為叢集管理者, 所以你將可以在叢集中賦予 Jenkins 權限
kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)
Tiller 是 server side 的 Helm, 在叢集中賦予它叢集管理的角色
kubectl create serviceaccount tiller --namespace kube-system
kubectl create clusterrolebinding tiller-admin-binding --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功建立 Tiller 服務帳戶, 你將獲得一個評價分數。
- 初始化 Helm 。 這確保了 server side 的 Helm 已經正確的安裝到你的叢集
./helm init --service-account=tiller
./helm update
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功的初始化 Helm, 以及安裝 Tiller, 你將獲得一個評價分數。
- 執行以下指令來確保 Helm 已經正確的被安裝。 你應該會看到 server 端以及 client 端的版本號:範例輸出
./helm version
Client: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
Server: &version.Version{SemVer:"v2.14.1", GitCommit:"5270352a09c7e8b6e8c9593002a73535276507c0", GitTreeState:"clean"}
設定並安裝 Jenkins
你將使用一個客製的檔案來增加一個必要的 GCP 插件, 要使用 service account 憑證來存取 Cloud Source Repository, 這個插件是必要的
- 使用 Helm CLI 來根據設定部署 chart
./helm install -n cd stable/jenkins -f jenkins/values.yaml --version 1.2.2 --wait
這個指令可能會花幾分鐘完成
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功設定好 Jenkins chart, 你將獲得一個評價分數。
一旦指令完成了, 確保 Jenkins pod 是處於正常運行狀態, 並且容器是 READY 的狀態
kubectl get pods
範例輸出:
NAME READY STATUS RESTARTS AGE
cd-jenkins-7c786475dd-vbhg4 1/1 Running 0 1m設定 Jenkins 服務帳號, 讓它可以部署應用到叢集上
kubectl create clusterrolebinding jenkins-deploy --clusterrole=cluster-admin --serviceaccount=default:cd-jenkins
你應該會收到以下輸出:
clusterrolebinding.rbac.authorization.k8s.io/jenkins-deploy created
執行以下指令來設定 port forwarding, 將本機的 port 映射到 Jenkins UI
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/component=jenkins-master" -l "app.kubernetes.io/instance=cd" -o jsonpath="{.items[0].metadata.name}")
kubectl port-forward $POD_NAME 8080:8080 >> /dev/null &現在, 確認 Jenkins 服務已經被成功建立:
kubectl get svc
範例輸出:
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cd-jenkins 10.35.249.67 <none> 8080/TCP 3h
cd-jenkins-agent 10.35.248.1 <none> 50000/TCP 3h
kubernetes 10.35.240.1 <none> 443/TCP 9h
你正使用 Kubernetes Plugin, 所以我們的 builder nodes 當有需要時, Jenkins master 會發請求給他們, 而這些 nodes 會自動地被啟動。
當這些 nodes 完成了工作, 他們會被自動關閉, 而他們的資源會回到叢集的資源池
注意到這個服務暴露了任何符合 selector
規則的 pods 的 ports 8080
以及 50000
。 這將在叢集內暴露 Jenkins web UI 以及 builder/agent 註冊 ports 。 另外, jenkins-ui
服務是使用 ClusterIP 暴露, 所以不可從叢集外部被存取。
連接到 Jenkins
Jenkins chart 會自動幫你建立一個管理者密碼。 執行以下指令來取得它:
printf $(kubectl get secret cd-jenkins -o jsonpath="{.data.jenkins-admin-password}" | base64 --decode);echo
如下圖, 在 cloud shell 點擊 Web Preview 按鈕, 然後點擊 “Preview on port 8080” 來連接到 Jenkins 使用者介面:
現在你應該能夠使用 username admin, 以及自動產生的密碼登入
現在你已經在叢集中設定好 Jenkins, 在下一個章節使用 Jenkins 來管理我們的 CI/CD 管道
理解應用
你將在持續部署的管道中部署範例應用 gceme
。 這個應用由 GO 語言所編寫, 位於 sample-app 資料夾底下。 當你在 Computer Engine instance 運行這個 gceme 二進制檔, 這個應用將會該 instance 的資訊如下圖般的形式顯示出來:
這個應用藉由支援兩個運作模式來模擬一個微服務
- 在
後端模式
: gceme 監聽 port 8080, 並且以 JSON 格式返回 Computer Engine instance 的 metadata - 在
前端模式
: gceme 向後端發請求, 並在使用者介面渲染收到的 JSON
部署應用
你將部署應用到兩種不同的環境:
- Production: 使用者使用的正式環境
- Canary: 一個規模小一點的網站, 它只會收到一定比例的使用者流量。 在我們將它發佈到所有的使用者之前, 使用這個環境來使用正式流量驗證你的軟體的正確性。
在 Google Cloud Shell, 到範例的資料夾內:
cd sample-app |
建立 Kubernetes 的命名空間來邏輯性的區隔不同的部署
kubectl create ns production |
使用 kbectl apply
指令建立 production, canary 部署, 以及服務
kubectl apply -f k8s/production -n production |
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功建立部署, 你將獲得一個評價分數。
預設來說, 前端只有一個 replica 被部署。 使用 kubectl scale
指令來確保至少有 4 個 replicas 同時運行
執行以下指令來擴大 production 環境的前端
kubectl scale deployment gceme-frontend-production -n production --replicas 4 |
現在確認一下, 你將會有 5 個 pods 運行前端, 4 個運行 production 流量, 1 個運行 canary (canary 的變更只會影響到 1/5, 20% 的使用者)
kubectl get pods -n production -l app=gceme -l role=frontend |
再確認 2 pods 運行後端, 1 個運行 production 然後一個是 canary
kubectl get pods -n production -l app=gceme -l role=backend |
取得 production 服務的外部 IP
kubectl get service gceme-frontend -n production |
備註: 這邊可能需要幾分鐘的時間讓平衡負載外部 IP 顯示出來
範例輸出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE |
在瀏覽器貼上 External IP 來檢視 info card 如下:
現在, 將前端服務的平衡負載外部 IP 記到一個變數, 稍等會用到:
export FRONTEND_SERVICE_IP=$(kubectl get -o jsonpath="{.status.loadBalancer.ingress[0].ip}" --namespace=production services gceme-frontend) |
在瀏覽器打開外部 IP, 確認兩個服務都運作正常。 輸入以下指令確認版本(應該要是 1.0.0):
curl http://$FRONTEND_SERVICE_IP/version |
你已經成功地部署了範例應用, 接下來, 你將設定一個管道以持續的, 可靠的部署你的變更。
建立 Jenkins 管道
建立一個程式碼倉庫來存放範例 app 程式碼
建立一份 gceme
範例 app 的複製, 然後推送到 Cloud Source Repository:
gcloud source repos create default |
如果看到警告請忽略, 你將不會被請款
測試進度
點擊 Check my progress 來確認目前的進度。如果你已經成功建立代碼倉庫, 你將獲得一個評價分數。
git init |
初始化範例 app 資料夾並設定 Git 倉庫:
git config credential.helper gcloud.sh |
執行以下指令:
git remote add origin https://source.developers.google.com/p/$DEVSHELL_PROJECT_ID/r/default |
設定 Git commit 的 username 以及 email 。 請將 [EMAIL_ADDRESS] 及 [USERNAME] 替換成你自己的
git config --global user.email "[EMAIL_ADDRESS]" |
將變更的內容加到 stage area, 提交 commit, 並推送到 Git 倉庫
git add . |
增加你的服務帳戶憑證
設定你的憑證, 讓 Jenkins 可以存取你的程式碼倉庫。 Jenkins 將會使用你的叢集服務帳戶憑證從 Cloud Source Repositories 下載程式碼
Step 1: 在 Jenkins 的使用者介面, 在左邊導覽介面點擊 Credentials
Step 2: 點擊 Jenkins
Step 3: 點擊 Global credentials (unrestricted)
Step 4: 在左側導航介面點擊 Add Credentials
Step 5: 從 KIND 的下拉式窗點擊 Google Service Account from metadata 並點擊 OK
全域憑證已經被加入。 憑證的名字為 CONNECTION DETAILS
區塊的 GCP Project ID
建立 Jenkins job
到你的 Jenkins 使用者介面並依造以下的步驟設定管道工作
Step 1: 左側點擊 Jenkins > New Item
Step 2: 將專案取名為 sample-app, 然後選擇 Multibranch Pipeline 選項, 點擊 OK
Step 3: 在下一頁, Branch Sources 區塊, 點擊 Add Source 然後選擇 git
Step 4: 在 Project Repository 欄位貼上 sample-app 資料夾在 Cloud Source Repositories 的 HTTPS clone URL 。 請將 [PROJECT_ID] 替換成你的 GCP Project ID:
https://source.developers.google.com/p/[PROJECT_ID]/r/default |
Step 5: 在 Credentials 下拉選單, 選擇之前增加服務帳戶時所建立的憑證名稱
Step 6: 在 Scan Multibranch Pipeline Triggers 區塊下, 勾選 Periodically if not otherwise run, 並設定 Interval 為 1 分鐘
Step 7: 你的 job 設定應該看起來會如下:
Step 8: 其餘選項留為預設, 點擊 Save
在你完成這些步驟之後, 一個叫做 “Branch indexing” 的 job 會運行。 這個 meta-job 會辨識你的倉庫中的分支, 並且確保變更沒有出現在現存的分支中。 如果你在左上方點擊 sample-app, 你該會看到 master job
備註: master 的第一次運行應該會失敗, 直到你再下一個步驟提交一些程式變更
你已經成功地建立了一個 Jenkins 管道, 接下來, 你將會建立一個持續整合的開發環境
建立開發環境
開發分支是在我們提交整合到正式環境之前, 讓開發者們用來測試程式碼變更的環境。 這個環境是應用的縮小規模版本, 但需要比較正式環境完全相同的機制下部署。
建立一個開發分支
你可以推送分支到 Git server, 讓 Jenkins 來部署你的環境, 藉此建立從功能分支來建立一個開發環境
建立一個開發分支並且推送到 Git server
git checkout -b new-feature |
修改管道定義
定義管道的 Jenkinsfile
是由 Jenkins Pipeline Groovy syntax 所編寫。 使用 Jenkinsfile
, 可以藉由僅僅一個檔案來敘述整個的 build 管道程序。
管道支援強大的功能, 像是並行化, 以及使用者手動核准
要讓管道如預期般運作, 我們需要修改 Jenkinsfile
來設定我們的 project ID
在 terminal 打開 Jenkinsfile
vim Jenkinsfile |
開始修改
i |
將 REPLACE_WITH_YOUR_PROJECT_ID
替換成你的 PROJECT_ID
。 你可以在這個教程的 CONNECTION DETAILS
區塊找到你的 PROJECT_ID
, 也可以輸入 gcloud config get-value project
來取得它
def project = 'REPLACE_WITH_YOUR_PROJECT_ID' |
儲存並退出 Jenkinsfile
檔案
:wq |
修改網站
要展示應用的變更, 你需要改變 gceme cards 的顏色, 從 藍色 改為 橘色
打開 html.go:
vim html.go |
開始編輯
i |
改變兩個位置的 <div class="card blue">
<div class="card orange"> |
儲存 html.go
檔案, 按下 Esc, 然後:
:wq |
打開 main.io:
vim main.io |
開始編輯:
i |
版本被定義在這一行
const version string = "2.0.0" |
再次儲存 main.go, 按下 Esc, 然後:
:wq |
開始部署
提交 commit 並推送變更
git add Jenkinsfile html.go main.go |
這將會開始一個開發環境的建立
在變更被推送到 Git repository 後, 到 Jenkins 使用者介面可以看到針對 new-feature 分支的建立已經開始。 大概會需要 1 分鐘完成
在 build 開始運行後, 點擊 build 旁, 位於左手邊的下拉箭頭, 選擇 Console output:
花幾分鐘的時間來追蹤 build 的輸出然後可以看到 kubectl --namespace=new-feature apply...
訊息開始。 你的 new-feature 分支將開始被部署到叢集上。
備註: 在開發情境中, 你不會使用面向公開的平衡負載。 你可以使用 kubectl proxy
來讓你的應用更安全。 這個代理 (proxy) 會自己使用 kubernetes API 來驗證, 並且代理從你本機發出到叢集中的服務的請求, 不須將你的服務暴露到網路上。
如果你沒有看到 Build Executor
裡有任何東西, 別擔心。 到 Jenkins homepage -> sample app 。 確認 new-feature
管道已經被建立
一旦全部的工作都完成後, 開始在背景開啟代理
kubectl proxy &
如果有錯誤, 按下 ctrl + c 來退出。 發一個請求到你的 localhost, 並讓 proxy 幫你轉發到你的服務, 確認你的應用是可被存取的。
curl \ |
你應該會看到回應 2.0.0, 這是目前運行中的版本
如果你收到類似錯誤如下:
{ |
這代表你的前端端點還沒有準備好。 等待一下下, 用 curl
指令再試一次。 如果你收到以下的輸出, 那我們可以繼續往下了。
2.0.0 |
你已經設定好開發環境了! 接下來, 你將會建立你之前所學到的, 部署一個金絲雀發佈 (canary release) 來測試一個新功能
部署一個金絲雀發佈 (Canary Release)
你已經確認過你的應用目前正在開發環境運行著最新的程式碼, 所以現在部署這些程式碼到金絲雀環境
建立一個 canary 分支, 然後推送到 Git server:
git checkout -b canary |
在 Jenkins 中, 你應該會看到 canary 管道已經啟動。 一旦它完成了, 你可以確認看看服務的 URL, 確保一些流量已經是由新的版本服務。 每五個請求中應該會有一個請求會返回 version 2.0.0 (無特定的順序)
export FRONTEND_SERVICE_IP=$(kubectl get -o \ |
while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done |
如果你一直看到 1.0.0, 試著再次運行上面的指令。 一但你確認 Okay 了, 按下 Ctrl-c 來結束指令
就是這樣! 你已經部署了金絲雀發佈。 現在你將部署新版到正式環境
部署到正式環境
現在我們的金絲雀發佈已經成功, 且沒有收到任何客戶的抱怨, 可以部署到其他的地方了!
建立一個金絲雀分支, 然後推送到 Git server
git checkout master |
在 Jenkins 中, 你應該會看到 master 管道已經啟動。 一旦它完成了(可能會花個幾分鐘), 你可以確認看看服務的 URL, 確保所有流量都是由 version 2.0.0 所服務
export FRONTEND_SERVICE_IP=$(kubectl get -o \ |
while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done |
如果你一直看到 1.0.0, 試著再次運行上面的指令。 一但你確認 Okay 了, 按下 Ctrl-c 來結束指令
範例輸出:
gcpstaging9854_student@qwiklabs-gcp-df93aba9e6ea114a:~/continuous-deployment-on-kubernetes/sample-app$ while true; do curl http://$FRONTEND_SERVICE_IP/version; sleep 1; done |
你可以到 gceme 應用的網站上, 顯示 info cards 的地方去看看, card 的顏色已經從藍色變為橘色。 以下的指令可以取得外部 IP 位置
kubectl get service gceme-frontend -n production |
範例輸出
測試你的理解
下面有多重選擇的問題來鞏固你對本教程概念的理解,盡你所能的回答吧:
你已經完成了!
幹得好, 你已經成功地將你的應用部署到正式環境!
恭喜
你已經完成本教程!
留言