前言
玩K8S也有一段時(shí)間了,借助云服務(wù)提供商的K8S控制臺(tái)扼雏,已經(jīng)可以很方便的快速部署應(yīng)用至K8S南捂。通過(guò)簡(jiǎn)單的點(diǎn)擊,可以一次性幫忙創(chuàng)建K8S 對(duì)象:Deployment缸兔、Service日裙、Ingress、ConfigMap等惰蜜。但是當(dāng)服務(wù)的規(guī)模上來(lái)后昂拂,這種方式就有點(diǎn)捉襟見(jiàn)肘。尤其是需要同時(shí)更新多個(gè)關(guān)聯(lián)服務(wù)時(shí)抛猖,就需要一個(gè)一個(gè)的去更改格侯,就有點(diǎn)不太方便。為了解決這個(gè)問(wèn)題财著,最近上手實(shí)操了一下Helm联四,發(fā)現(xiàn)生產(chǎn)力大大提升。
Helm 簡(jiǎn)介
Helm 是一個(gè)為K8S打造的包管理器撑教。通過(guò)Helm可以方便管理Kubernetes應(yīng)用程序朝墩。Helm主要有兩大核心概念:Charts、Release伟姐。
- Chart:用來(lái)定義收苏,安裝和升級(jí)K8S 應(yīng)用亿卤。亦可分享及版本化控制。
- Release:類似Image之于Container鹿霸,Release是Chart的運(yùn)行實(shí)例排吴。
目前Helm最新的版本為V3.1,較之前版本杜跷,在整體架構(gòu)上移除服務(wù)端Tiller傍念。
對(duì)于Windows系統(tǒng)而言可借助Choco快速安裝:choco install kubernetes-helm
,通過(guò)執(zhí)行helm version
確認(rèn)是否安裝成功葛闷。
version.BuildInfo{Version:"v3.1.0", GitCommit:"b29d20baf09943e134c2fa5e1e1cab3bf93315fa", GitTreeState:"clean", GoVersion:"go1.13.7"}
在繼續(xù)往前憋槐,請(qǐng)確保已具備基礎(chǔ)的K8S基礎(chǔ)知識(shí),并且確保本機(jī)已安裝Docker和K8S淑趾。安裝教程和K8S簡(jiǎn)單入門(mén)可參考我的這篇文章ASP.NET Core 借助 K8S 玩轉(zhuǎn)容器編排阳仔。
對(duì)于第一次接觸Helm .NETer 來(lái)說(shuō)我們可以通過(guò)VS 2019來(lái)快速體驗(yàn)一下。請(qǐng)確保已安裝Visual Studio Tools for Kubernetes扣泊。
創(chuàng)建 Chart (helm create)
打開(kāi)VS 創(chuàng)建項(xiàng)目近范,選擇Container Application for Kubernetes,創(chuàng)建一個(gè)空的ASP.NET Core Web 項(xiàng)目延蟹。
創(chuàng)建后评矩,項(xiàng)目結(jié)構(gòu)如下圖所示,與平時(shí)之間創(chuàng)建的Web項(xiàng)目而言阱飘,主要是多了一個(gè)
charts
目錄斥杜、Dockerfile
和一個(gè)azds.yaml
。除了創(chuàng)建項(xiàng)目時(shí)通過(guò)選擇Container Application for Kubernetes類型外沥匈,我們也可以通過(guò)其他方式創(chuàng)建蔗喂。我們這里手動(dòng)刪除
charts
目錄、Dockerfile
和一個(gè)azds.yaml
高帖。然后如下圖步驟即可重新生成Helm Chart缰儿。當(dāng)然也可以通過(guò)helm create
創(chuàng)建。
安裝 Chart (helm install)
在展開(kāi)之前散址,先來(lái)簡(jiǎn)要介紹Chart目錄:
k8shelmdemo/ # Chart 目錄
├── charts # 這個(gè) charts 依賴的其他 charts乖阵,始終被安裝
├── Chart.yaml # 描述這個(gè) Chart 的相關(guān)信息、包括名字预麸、描述信息义起、版本等
├── templates # 模板目錄
│ ├── deployment.yaml # deployment 控制器的 Go 模板文件
│ ├── _helpers.tpl # 以 _ 開(kāi)頭的文件不會(huì)部署到 k8s 上,可用于定制通用信息
│ ├── ingress.yaml # ingress 的模板文件
│ ├── NOTES.txt # Chart 幫助文本师崎,安裝后會(huì)顯示給用戶默终,例如:如何使用、列出缺省值
│ ├── service.yaml # service 的 Go 模板文件
│ ├── secrets.yaml # secrets 的 Go 模板文件
│ └── tests
│ └── test-connection.yaml
└── values.yaml # 模板的值文件,這些值會(huì)在安裝時(shí)應(yīng)用到 GO 模板生成部署文件
簡(jiǎn)單來(lái)說(shuō)齐蔽,Helm Chart 定義常用的K8S 對(duì)象模板两疚,通過(guò)values.yaml來(lái)填充模板。那我們就來(lái)看看填充后的輸出結(jié)果是怎樣的含滴。打開(kāi)命令提示符诱渤,進(jìn)入到Chart目錄,通過(guò)helm template --debug [release name] [chart dir]
命令就可以測(cè)試Chart(亦可通過(guò)helm --dry-run --debug [release name] [chart dir]
測(cè)試)谈况∩酌溃可以看到輸出了Service和Deployment。這里你可能就納悶了碑韵,不是定義了4個(gè)K8S對(duì)象模板嗎赡茸,為什么就是輸出2個(gè)yaml文件呢。這里先按住不表祝闻。
PS \K8S.Helm.Demo\charts> helm template --debug k8s-helm-demo .\k8shelmdemo\
install.go:158: [debug] Original chart version: ""
install.go:175: [debug] CHART PATH: \K8S.Helm.Demo\charts\k8shelmdemo
---
# Source: k8shelmdemo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: k8shelmdemo
labels:
app: k8shelmdemo
chart: k8shelmdemo-0.1.0
release: k8s-helm-demo
heritage: Helm
spec:
type: ClusterIP
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: k8shelmdemo
release: k8s-helm-demo
---
# Source: k8shelmdemo/templates/deployment.yaml
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: k8shelmdemo
labels:
app: k8shelmdemo
chart: k8shelmdemo-0.1.0
draft: draft-app
release: k8s-helm-demo
heritage: Helm
spec:
replicas: 1
selector:
matchLabels:
app: k8shelmdemo
release: k8s-helm-demo
template:
metadata:
labels:
app: k8shelmdemo
draft: draft-app
release: k8s-helm-demo
annotations:
buildID: ""
spec:
containers:
- name: k8shelmdemo
image: "k8shelmdemo:stable"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
env:
resources:
{}
這里目前需要注意一點(diǎn)就是上面輸出的Deployment中使用的鏡像為image: "k8shelmdemo:stable"
占卧。所以在安裝該Chart之前,我們需要構(gòu)造鏡像联喘。鏡像構(gòu)造很簡(jiǎn)單华蜒,在Vs中右鍵Dockerfile選擇構(gòu)建就好(請(qǐng)確保Docker已啟動(dòng))。
觀察VS輸出窗口豁遭,會(huì)有以下輸出:
1>K8S.Helm.Demo -> D:\Programming\Coding\dotnet\K8S.Ocelot.Demo\src\K8S.Helm.Demo\bin\Debug\netcoreapp3.1\K8S.Helm.Demo.dll
1>Docker version 19.03.1, build 74b1e89
1>docker build -f "d:\programming\coding\dotnet\k8s.ocelot.demo\src\k8s.helm.demo\dockerfile" --force-rm -t k8shelmdemo --label "com.microsoft.created-by=visual-studio" --label "com.microsoft.visual-studio.project-name=K8S.Helm.Demo" "d:\programming\coding\dotnet\k8s.ocelot.demo\src"
1>Sending build context to Docker daemon 6.192MB
1>
1>Step 1/18 : FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
1>Step 2/18 : WORKDIR /app
1> ---> e28362768eed
1> ---> Using cache
1> ---> 6457841dbdf1
1>Step 3/18 : EXPOSE 80
1> ---> Using cache
1> ---> bb9dc51530fe
1>Step 4/18 : FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
1> ---> 0a4c7c13f9d6
1>Step 5/18 : WORKDIR /src
1> ---> Using cache
1> ---> ddc36742b71c
1>Step 6/18 : COPY ["K8S.Helm.Demo/K8S.Helm.Demo.csproj", "K8S.Helm.Demo/"]
1> ---> d18831c83acd
1>Step 7/18 : RUN dotnet restore "K8S.Helm.Demo/K8S.Helm.Demo.csproj"
1> ---> Running in 64d3624eb9c0
1> Restore completed in 7.19 sec for /src/K8S.Helm.Demo/K8S.Helm.Demo.csproj.
1>Removing intermediate container 64d3624eb9c0
1> ---> ba3624442138
1>Step 8/18 : COPY . .
1> ---> 43c4f6c4769f
1>Step 9/18 : WORKDIR "/src/K8S.Helm.Demo"
1> ---> Running in 145e155d3a5d
1>Removing intermediate container 145e155d3a5d
1>Step 10/18 : RUN dotnet build "K8S.Helm.Demo.csproj" -c Release -o /app/build
1> ---> e547e8caed4a
1> ---> Running in 146df981f291
1>Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core
1>Copyright (C) Microsoft Corporation. All rights reserved.
1>
1> Restore completed in 27.08 ms for /src/K8S.Helm.Demo/K8S.Helm.Demo.csproj.
1> K8S.Helm.Demo -> /app/build/K8S.Helm.Demo.dll
1>Build succeeded.
1> 0 Warning(s)
1>
1>Time Elapsed 00:00:02.09
1> 0 Error(s)
1>Removing intermediate container 146df981f291
1>Step 11/18 : FROM build AS publish
1> ---> 94f07ad82c1c
1> ---> 94f07ad82c1c
1>Step 12/18 : RUN dotnet publish "K8S.Helm.Demo.csproj" -c Release -o /app/publish
1> ---> Running in 60d63984fe28
1>Microsoft (R) Build Engine version 16.4.0+e901037fe for .NET Core
1>
1>Copyright (C) Microsoft Corporation. All rights reserved.
1> Restore completed in 26.94 ms for /src/K8S.Helm.Demo/K8S.Helm.Demo.csproj.
1> K8S.Helm.Demo -> /src/K8S.Helm.Demo/bin/Release/netcoreapp3.1/K8S.Helm.Demo.dll
1> K8S.Helm.Demo -> /app/publish/
1>Removing intermediate container 60d63984fe28
1>Step 13/18 : FROM base AS final
1> ---> 85d893dc4a81
1> ---> bb9dc51530fe
1>Step 14/18 : WORKDIR /app
1> ---> Running in 69b7fd56c371
1>Removing intermediate container 69b7fd56c371
1> ---> 219310025c54
1>Step 15/18 : COPY --from=publish /app/publish .
1>Step 16/18 : ENTRYPOINT ["dotnet", "K8S.Helm.Demo.dll"]
1> ---> 6e63a4449dbb
1> ---> Running in a43a0516c6dc
1>Removing intermediate container a43a0516c6dc
1> ---> 36f422c923fd
1>Step 17/18 : LABEL com.microsoft.created-by=visual-studio
1> ---> Running in 88d100227ee1
1>Removing intermediate container 88d100227ee1
1> ---> 4a71f8e5e761
1>Step 18/18 : LABEL com.microsoft.visual-studio.project-name=K8S.Helm.Demo
1> ---> Running in f609881010ad
1>Removing intermediate container f609881010ad
1> ---> 3301427c0fb8
1>Successfully built 3301427c0fb8
1>Successfully tagged k8shelmdemo:latest
1>SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.
========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========
最終構(gòu)建的鏡像名稱為k8shelmdemo:latest
叭喜。與我們上面Chart中使用的鏡像k8shelmdemo:stable
不一致。如果現(xiàn)在安裝Chart蓖谢,那么應(yīng)用將無(wú)法找對(duì)應(yīng)的鏡像無(wú)法啟動(dòng)域滥。那怎么辦呢。查看deployment.yaml
模板文件蜈抓,我們發(fā)現(xiàn)其鏡像引用定義為image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
。查看values.yaml
發(fā)現(xiàn)如下定義:
image:
repository: k8shelmdemo
tag: stable
pullPolicy: IfNotPresent
所以改法就很簡(jiǎn)單了昂儒,將values.yaml
的tag更改為latest
即可沟使。更改后在執(zhí)行helm template --debug [release name] [chart dir]
驗(yàn)證下。接下來(lái)通過(guò)helm install
來(lái)安裝Chart渊跋。在執(zhí)行之前腊嗡,我們先通過(guò)kubectl create ns helmdemo
創(chuàng)建一個(gè)獨(dú)立的命名空間以方便確認(rèn)和清理。再執(zhí)行helm install k8shelmdemo .\k8shelmdemo\ -n helmdemo
安裝(-n 指定我們剛剛創(chuàng)建的命名空間)拾酝。具體命令如下:
PS \K8S.Helm.Demo\charts> kubectl create ns helmdemo
namespace/helmdemo created
PS \K8S.Helm.Demo\charts> helm install k8shelmdemo .\k8shelmdemo\ -n helmdemo
NAME: k8shelmdemo
LAST DEPLOYED: Sun Feb 23 17:33:54 2020
NAMESPACE: helmdemo
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace helmdemo -l "app=k8shelmdemo,release=k8shelmdemo" -o jsonpath="{.items[0].metadat
a.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
PS \K8S.Helm.Demo\charts>
我們看到同時(shí)輸出了模板文件夾下的NOTES模板燕少,這時(shí)說(shuō)明helm已經(jīng)安裝了。那怎樣確保是否安裝成功了呢蒿囤。繼續(xù)執(zhí)行以下命令:
PS \K8S.Helm.Demo\charts> helm list -n helmdemo #查看指定命名空間下已安裝的chart客们,也就是運(yùn)行中的Release
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
k8shelmdemo helmdemo 1 2020-02-23 17:33:54.2196357 +0800 CST deployed k8shelmdemo-0.1.0 1.0
PS \K8S.Helm.Demo\charts> kubectl get all -n helmdemo # 查看指定命名空間下K8S下所有的對(duì)象
NAME READY STATUS RESTARTS AGE
pod/k8shelmdemo-689bd54677-fcfx7 1/1 Running 0 5m8s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/k8shelmdemo ClusterIP 10.97.204.227 <none> 80/TCP 5m8s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/k8shelmdemo 1/1 1 1 5m8s
NAME DESIRED CURRENT READY AGE
replicaset.apps/k8shelmdemo-689bd54677 1 1 1 5m8s
至此我們可以確定Chart成功安裝。那如何訪問(wèn)剛剛部署的Web應(yīng)用呢,安裝剛剛Chart的安裝Notes底挫,通過(guò)kubectl port-forward
配置端口轉(zhuǎn)發(fā)恒傻,來(lái)完成。從上面的輸出我們已經(jīng)知道對(duì)應(yīng)的Pod Name 為k8shelmdemo-689bd54677-fcfx7建邓。執(zhí)行kubectl port-forward k8shelmdemo-689bd54677-fcfx7 8090:80
盈厘。
PS \K8S.Helm.Demo\charts> kubectl port-forward k8shelmdemo-689bd54677-fcfx7 8090:80 -n helmdemo
Forwarding from 127.0.0.1:8090 -> 80
Forwarding from [::1]:8090 -> 80
換一個(gè)命令行執(zhí)行curl -l http://localhost:8090
會(huì)看到輸出Hello world
。
更新 Chart (helm upgrade)
假設(shè)我現(xiàn)在想將輸出更新為Hello Helm
官边,我們來(lái)看下怎么辦沸手。對(duì)于當(dāng)前應(yīng)用來(lái)說(shuō),更新輸出注簿,只需要更改Startup的Hello World
改為Hello Helm
就好契吉,然后重新構(gòu)建鏡像。
這里思考一下滩援,因?yàn)橹匦聵?gòu)建的鏡像Tag還是k8shelmdemo:latest
栅隐,所以無(wú)需對(duì)當(dāng)前Helm Chart做任何改動(dòng),所以也就無(wú)需更新玩徊。那我們?cè)撊绾胃聭?yīng)用呢租悄。如果有K8S基礎(chǔ)的同學(xué)應(yīng)該很快就能想到,直接刪除Pod即可恩袱。因?yàn)閺纳厦?code>kubectl get all -n helmdemo的輸出中泣棋,我們可以看到Chart為我們的應(yīng)用自動(dòng)創(chuàng)建了一個(gè)ReplicaSet
實(shí)例,ReplicaSet主要用于確保應(yīng)用始終保持指定數(shù)量的實(shí)例運(yùn)行畔塔。所以如果刪除一個(gè)Pod潭辈,K8S會(huì)按照ReplicaSet的定義,重新啟用一個(gè)新的Pod澈吨。再重新執(zhí)行kubectl port-forward
把敢,會(huì)發(fā)現(xiàn)應(yīng)用已更新。
PS: 因?yàn)楫?dāng)前demo使用的是本地鏡像谅辣,所以刪除Pod后修赞,重新運(yùn)行的pod能夠輸出更新后的結(jié)果。如果鏡像來(lái)源并非本地桑阶,那么對(duì)于同一個(gè)鏡像tag來(lái)說(shuō)柏副,就要考慮更新鏡像拉取策略。
PS \K8S.Helm.Demo\charts> kubectl delete pod/k8shelmdemo-689bd54677-fcfx7 -n helmdemo # 刪除pod
PS \K8S.Helm.Demo\charts> kubectl get all -n helmdemo
NAME READY STATUS RESTARTS AGE
pod/k8shelmdemo-689bd54677-mrr64 1/1 Running 0 29s # 新的Pod創(chuàng)建成功
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/k8shelmdemo ClusterIP 10.97.204.227 <none> 80/TCP 33m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/k8shelmdemo 1/1 1 1 33m
NAME DESIRED CURRENT READY AGE
replicaset.apps/k8shelmdemo-689bd54677 1 1 1 33m
假設(shè)現(xiàn)在需要服務(wù)部署后直接通過(guò)指定端口訪問(wèn)蚣录,無(wú)需通過(guò)kubeclt port-forward
進(jìn)行端口轉(zhuǎn)發(fā)割择。那么我們就需要對(duì)Chart進(jìn)行相應(yīng)更新,將生成的Service的類型由默認(rèn)的Cluster
更改為LoadBalancer
模式萎河。更新values.yaml
中的service節(jié)點(diǎn)如下:
service:
type: LoadBalancer
port: 8093
緊接著通過(guò)執(zhí)行helm upgrade [release name] [chart dir]
命令更新應(yīng)用荔泳,如下蕉饼。
PS \K8S.Helm.Demo\charts> helm upgrade k8shelmdemo .\k8shelmdemo\ -n helmdemo
Release "k8shelmdemo" has been upgraded. Happy Helming!
NAME: k8shelmdemo
LAST DEPLOYED: Sun Feb 23 18:39:30 2020
NAMESPACE: helmdemo
STATUS: deployed
REVISION: 3
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w k8shelmdemo'
export SERVICE_IP=$(kubectl get svc --namespace helmdemo k8shelmdemo -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:8093
PS \K8S.Helm.Demo\charts> kubectl get all -n helmdemo
NAME READY STATUS RESTARTS AGE
pod/k8shelmdemo-689bd54677-pj5pd 1/1 Running 0 22m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/k8shelmdemo LoadBalancer 10.97.204.227 localhost 8093:30035/TCP 65m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/k8shelmdemo 1/1 1 1 65m
NAME DESIRED CURRENT READY AGE
replicaset.apps/k8shelmdemo-689bd54677 1 1 1 65m
PS \K8S.Ocelot.Demo\src\K8S.Helm.Demo\charts> curl -l localhost:8093
Hello Helm!
PS \K8S.Helm.Demo\charts> helm ls -n helmdemo # 版本已更新
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
k8shelmdemo helmdemo 2 2020-02-23 18:39:30.2059395 +0800 CST deployed k8shelmdemo-0.1.0 1.0
刪除 Chart (helm delete)
演示完畢澳叉,那如何刪除已發(fā)布的Release呢婴程,執(zhí)行helm delete k8shelmdemo -n helmdemo
端幼。
PS \K8S.Helm.Demo\charts> helm delete k8shelmdemo -n helmdemo
release "k8shelmdemo" uninstalled
PS \K8S.Helm.Demo\charts> helm ls -n helmdemo
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
PS \K8S.Helm.Demo\charts> kubectl get all -n helmdemo
No resources found.
執(zhí)行后仗考,可以發(fā)現(xiàn)創(chuàng)建的K8S資源也已清理干凈哮幢。
最后
以上僅是對(duì) ASP.NET Core 如何使用 Helm 部署到K8S的簡(jiǎn)單介紹诸蚕,希望對(duì)入門(mén)的你有所幫助某残!對(duì)于Helm復(fù)雜的應(yīng)用鄙信,主要在于模板填充的復(fù)雜應(yīng)用译荞,大家可以結(jié)合官方Helm文檔以及eShopOnContainer中Helm示例進(jìn)行學(xué)習(xí)瓤的。
參考資料:
Get started with Visual Studio Kubernetes Tools
玩K8S不得不會(huì)的HELM