1. 前言
前前後後學習kubernetes也有一個來月了,關於kubernetes的部落格也寫了有十多篇。但是技術如果無法落地到實際的應用場景終歸是紙上談兵,所以就有了這一出:通過結合kubernetes
和azure devops
實現專案的CI/CD
以及均衡負載
寫完這篇後kubernetes
的相關學習也暫時告一段落了,有種終於闖關成功了啊的感覺,當然這是題外話了。
注1:以下只是以Net Core專案為例,實際運用場景中,除了dockfile的編寫有差別,剩下整個自動化部署鏈條中的技術也好,工具也好,都可以複用,與語言和語言框架本身無關。
注2:本文演示的也只是其中一種簡便的方式,具體的自動化流程中,由於自由度非常高,所以實際的流程可能會更加複雜,這裡就不做贅述了
以下場景需要用到的工具或者技術:
- .Net Core
部署的應用本身
作為程式碼倉庫
- kubernetes
- docker
- helm【kubernetes的包管理工具】
- ingress【使用ingress繫結域名和https證書,實現域名訪問】
- Azure DevOps
作為CI/CD的工具
注:以下所有的相關部署程式碼,都在下面這個倉庫
- 倉庫內容只是我自己用的一個小工具,當然具體是什麼內容不重要,這篇只是演示部署相關的
2. Net Core專案本身的準備
2.1 dockerfile
你需要一個dockerfile
來構建一個docker image
, 如果是.Net Core
專案,vs提供了傻瓜式生成dockerfile
的功能,可以免去初學時編寫dockerfile
的煩惱
- 本示例dockerfile路徑和內容
2.2 建立kubernetes用於helm的chart包
2.2.1 說明
這一部分需要有helm相關的知識,說白了就是將你的如果熟悉k8s但不熟悉helm,可以參照:
2.2.2 chart檔案目錄和檔案組成
自定義的chart包,位於以下路徑
https://github.com/lzw5399/TocGenerator/tree/master/kubernetes
如上圖可以看出是一個很經典的自定義chart包的檔案目錄,即:
.
├── Chart.yaml 【chart的name和version等資訊】
├── templates 【k8s的資源清單模板,可以引用values.yaml的變數】
| ├── deployment.yaml
| └── service.yaml
├── values.yaml 【定義變數,供template/下的yaml使用,實現動態替換yaml內容】
3. Azure Devops建立倉庫的pipeline
3.1 前言
Azure DevOps
是微軟出品的DevOps
平臺,裡面包含了Pipelines
工具鏈,對個人免費,可以用於專案的CI/CD
3.2 使用azure devops準備操作
- 如果之前使用過
azure devops
,這幾步可以視情況跳過。
- 進入
azure devops
註冊賬號 - 之後按照引導新建一個
organization
- 再新建一個
project
- 進入
project
3.3 建立service connections
這裡要建立一個service connections,用於之後pipeline訪問k8s的master伺服器
- 點選peject setting
- 這裡點選
service connections
來建立一個連線,用於訪問k8s的master伺服器
- 然後填寫具體的憑證,之後的pipeline上需要
3.4 新建pipeline流水線
新建pipeline
流水線用於自定義部署流程
- 點選
pipelines
,然後點選create pipelines
,新建一條流水線來部署我們的應用
- 選擇程式碼倉庫位置,選github
- 然後會跳到github進行授權,授權完成後會顯示github的repo列表,選擇具體的倉庫
- 選擇完倉庫後,會自動按照你當前專案的語言,在github倉庫的根目錄生成一個預設的
azure-pipelines.yml
檔案, - 替換檔案的內容,我們最終使用的yaml檔案步驟大概如下
- 第一步:構建docker映象
- 第二步:將自定義的chart包拷貝到master伺服器上
- 第三步:執行
deploy.sh
指令碼,完成部署
# 哪條分支會觸發構建
trigger:
- master
resources:
- repo: self
# 定義變數
variables:
- name: appName
value: tocgenerator
- name: tag
value: $(Build.BuildNumber)
- name: imageNameWithoutTag
value: $(dockerid)/$(appName)
- name: imageNameWithTag
value: $(imageNameWithoutTag):$(tag)
- name: serverChartLocation
value: /root/helm-chart-folder/toc
stages:
- stage: Build
jobs:
- job: Build
pool:
vmImage: 'ubuntu-latest'
# 這下面是每個我們要具體執行的任務
steps:
# build docker images並且push到倉庫
- task: Docker@2
displayName: docker build and push
inputs:
containerRegistry: 'my_docker_hub'
repository: '$(imageNameWithoutTag)'
command: 'buildAndPush'
Dockerfile: '**/Dockerfile'
buildContext: '.'
tags: $(tag)
addPipelineData: false
# 將kubernetes資料夾,即chart包拷貝到k8s的master伺服器
- task: CopyFilesOverSSH@0
displayName: copy helm chart to server
inputs:
# 這個endpoint就是我們剛剛建立的service connection的名字
sshEndpoint: 'my_server'
sourceFolder: 'kubernetes'
contents: '**'
targetFolder: $(serverChartLocation)
readyTimeout: '20000'
# 在k8s的master伺服器上執行我們github倉庫的根目錄的deploy.sh,進行部署操作
- task: SSH@0
displayName: run deploy shell on server
inputs:
# 這個endpoint就是我們剛剛建立的service connection的名字
sshEndpoint: 'my_server'
runOptions: 'script'
scriptPath: 'deploy.sh'
args: '$(tag) $(serverChartLocation)'
readyTimeout: '20000'
3.5 建立部署shell指令碼
部署指令碼的位置
https://github.com/lzw5399/TocGenerator/blob/master/deploy.sh
幾點說明
- echo純粹是為了記錄log使用的,下面的示例把echo部分刪除了
- $1 and $2 代表外部傳入的引數
- $1是image的tag,$2是k8s的master伺服器上我們自定義的chart的目錄
- 移除沒有tag的懸掛docker image,純粹為了節省伺服器空間,為可選項
#!/bin/bash
# 出現錯誤退出指令碼執行
set -o errexit
# $1 and $2 代表外部傳入的引數
# $1是image的tag,$2是k8s的master伺服器上我們自定義的chart的目錄
buildNumber=$1
serverChartLocation=$2
cd $serverChartLocation
# 安裝或者升級我們的helm release
# 即如果查詢到了有release存在就upgrade,沒有則install
if test -z "$(helm ls | grep toc-release)"; then
helm install -f values.yaml --set env.buildnumber=$buildNumber --set image.tag=$buildNumber toc-release .
else
helm upgrade -f values.yaml --set env.buildnumber=$buildNumber --set image.tag=$buildNumber toc-release .
fi
# 移除沒有tag的懸掛docker image(可選)
danglings=$(sudo docker images -f "dangling=true" -q)
if test -n "$danglings"; then
sudo docker rmi $(sudo docker images -f "dangling=true" -q) >>/dev/null 2>&1
if [[ $? != 0 ]]; then
exit $?
fi
fi
exit 0
4. 觸發pipeline部署流水線
這裡有兩種辦法,
- 點選我們剛剛建立的pipeline手動run一個
- 通過push程式碼到倉庫的指定分支(
我們設定的master
)觸發構建
顯示構建成功之後就可以檢視了!
5. 關於均衡負載
均衡負載是kubernetes自帶的基礎功能之一,這裡只是做了一個試驗可以更加直觀地感受到而已
如下
- 定義一個靜態的guid
- 在/version 路由下輸出guid
則如果有2個例項,且均衡負載成功的話,每次重新整理這個介面,會隨機顯示這兩個guid
- deployment的replicas例項數需要設定2以上
最後均衡負載試驗的地址,也是本次例項專案的線上地址
- 如下,會出現兩個不同的guid