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的工具
注:以下所有的相關部署代碼,都在下面這個倉庫
- 倉庫內容只是我自己用的一個小工具,當然具體是什么內容不重要,這篇只是演示部署相關的
- 整個演示的demo已經遷移至csharp-archived分支
https://github.com/lzw5399/toc-generator/tree/csharp-archived
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