一、为什么需要Helm?

Kubernetes目前已成为容器编排的事实标准,随着传统架构向微服务容器化架构的转变,从一个巨大的单体的应用切分为多个微服务,每个微服务可独立部署和扩展,实现了敏捷开发和快速部署,但是由于从大一个应用变成了多个微服务,导致服务数大幅增加,对于Kubernetes来说,针对每个服务需要部署如deployment、statufulset、service、pod 等资源文件,而对于一个复杂的应用来说,可能会有很多类似上面的资源文件,其中还有更新或回滚的需求,若要执行,需要修改和维护相关的大量资源文件,这时候,如何针对每个服务涉及到资源集合到一个整体来实现部署、升级和回滚是亟待需要解决的难题,Helm就是在这个背景下诞生的。

二、Helm的简介和使用场景

那么Helm是如何解决上述难题的呢?它其实是将Kubernetes资源(如deployment、statufulset、service、pod) 打包到一个chart中,而chart被打包并推送保存到chart仓库(repo),然后通过chart仓库用来存储和分享chart包。Helm可直接拉取并安装chart包,生成helm维度整体的应用,其应用会包含如deployment、statufulset、service、pod的资源,并支持以一个整体Helm应用的维度来进行版本控制、打包、发布、删除、更新等操作。针对用户来说主要适用如下场景:

1、将常用搭配、标准化的多个资源文件放在同一个chart包中,方便统一的版本控制、安装、部署、升级、回滚和删除

2、可以大大简化了使用Kubernetes部署的难度,降低了用户使用门槛,只需配置参数即可一键部署

三、Helm实践

本次演示Helm的版本号如下:

[root@k8s-master my-second-helm]# helm version
version.BuildInfo{Version:"v3.3.1", GitCommit:"249e5215cde0c3fa72e27eb7a30e8d55c9696144", GitTreeState:"clean", GoVersion:"go1.14.7"}

1、安装

1)制作chart包的形式

Helm 应用的安装既可以从远程的repo进行拉取chart包进行安装,repo中提供了很多官方的chart包,若无个性化的需求,可以类似公开镜像一样进行拉取并安装,若需要单独调整,可以在已有的chart包进行更新再次打包,然后拉取更新后的chart包进行安装,接下来先来实践下后者,我们先新建一个helm的目录,然后在此目录下执行如下命令:

[root@k8s-master helm]# helm create my-second-helm
Creating my-second-helm
[root@k8s-master helm]# ls
my-first-helm my-second-helm
[root@k8s-master helm]# cd my-second-helm/
[root@k8s-master my-second-helm]# ls
charts Chart.yaml templates values.yaml
[root@k8s-master helm]# tree my-second-helm
my-second-helm
├── charts
├── Chart.yaml
├── templates
│   ├── deployment.yaml
│   ├── _helpers.tpl
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── serviceaccount.yaml
│   ├── service.yaml
│   └── tests
│   └── test-connection.yaml
└── values.yaml directories, files

我们在前面的操作中只是指定了这个文件夹的名字my-second-helm,但是在这个文件下默认创建了多个目录和文件,接下里我们一起看下默认的文件中都包含哪些内容,各自充当什么作用,先一起看下Chart.yaml这个文件

[root@k8s-master my-second-helm]# cat Chart.yaml
apiVersion: v2
name: my-second-helm
description: A Helm chart for Kubernetes # A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application # This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1. # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
appVersion: 1.16.

可以看到Chart.yaml这个文件主要是用来对chart进行的描述,声明了当前 Chart 的名称、版本等基本信息,如果我们自己制作的chart有相关的描述都可以写入到文件,这些信息会在该 Chart 被放入仓库后,供用户浏览检索,方便用户了解这个chart。

templates这个目录下,我们看到了大家比较熟悉的资源,我们看下deployment.yaml的构成

[root@k8s-master templates]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "my-second-helm.fullname" . }}
labels:
{{- include "my-second-helm.labels" . | nindent }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "my-second-helm.selectorLabels" . | nindent }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent }}
{{- end }}
labels:
{{- include "my-second-helm.selectorLabels" . | nindent }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent }}
{{- end }}
serviceAccountName: {{ include "my-second-helm.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort:
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{- toYaml .Values.resources | nindent }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent }}
{{- end }}

细心的读者可能发现了,这个kind为deployment的资源与我们平常自己写的有些出入,主要是出现了很多类似{}的内容,如:replicas: {{ .Values.replicaCount }},经常我们是用replicas: 数字的形式,而这里已经换成了变量,而整个文件出现了很多类似的变量,想必读者也猜到了原来helm是通过设置变量来统一管理很多需要输入的值,若有多个文件引用同一个变量,就再也不用同时修改多个文件了,细心的读者可能会发现,即便对K8s不太了解的用户,也可以仅设置变量的值也可以轻松部署应用,岂不可以大大降低部署的难度,确实如此,这就是helm的一个主要的特点,让部署变的简单,特别是常用的标准的配置我们可将其制作成chart一键部署,让我们再回到replicas: {{ .Values.replicaCount }}这个变量上,既然存在变量,那变量的设值在哪里呢? 我们可以看到变量的组成中存在Values,而和我们templates同级别的目录选还存在一个很重要的文件values.yaml,我们看下这个文件里面的内容:

[root@k8s-master my-second-helm]# cat values.yaml
# Default values for my-second-helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates. replicaCount: image:
repository: nginx
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "" imagePullSecrets: []
nameOverride: ""
fullnameOverride: "" serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: "" podAnnotations: {} podSecurityContext: {}
# fsGroup: securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: service:
type: ClusterIP
port: ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: chart-example.local
paths: []
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi autoscaling:
enabled: false
minReplicas:
maxReplicas:
targetCPUUtilizationPercentage:
# targetMemoryUtilizationPercentage: nodeSelector: {} tolerations: [] affinity: {}

可以看到这个文件包含的是整个chart中各个资源下变量的值,如replicaCount: 1,前面replicas: {{ .Values.replicaCount }},因此上面的deployment的replicas为1,其他变量的值类似,其中{}表示未指定,用户可根据需要进行自定义。

接下来我们通过vim 修改下value.yaml文件中replicaCount: 2内容然后进行安装部署,但是安装部署之前需要先打包,我们在上面的操作都是针对目录和文件的,helm只能针对包进行安装,因此我们需先打包,打包之前,最好先验证下我们之前在各个文件输入的值是否合法,可以通过操作进行校验

[root@k8s-master my-second-helm]# helm lint --strict my-second-helm
==> Linting my-second-helm
Error unable to check Chart.yaml file in chart: stat my-second-helm/Chart.yaml: no such file or directory Error: chart(s) linted, chart(s) failed
[root@k8s-master my-second-helm]# cd ..
[root@k8s-master helm]# ls
my-first-helm my-second-helm
[root@k8s-master helm]# helm lint --strict my-second-helm
==> Linting my-second-helm
[INFO] Chart.yaml: icon is recommended chart(s) linted, chart(s) failed

可以看到在进行校验的时候,需要回到chart的根目录,0 chart(s) failed显示这个chart的之前输入的value值应无问题,接下来可以执行打包操作了,如下所示,红色字体就是我们打包后的结果

[root@k8s-master helm]# helm package my-second-helm
Successfully packaged chart and saved it to: /home/James/zhanglei/helm/my-second-helm-0.1..tgz
[root@k8s-master helm]# ls
my-first-helm my-second-helm my-second-helm-0.1.0.tgz

这个就是我们所说的chart包,接下来终于可以执行安装的操作了

[root@k8s-master helm]# helm install my-second-helm-test my-second-helm-0.1..tgz
NAME: my-second-helm-test
LAST DEPLOYED: Sat Sep ::
NAMESPACE: default
STATUS: deployed # 状态
REVISION: 1
NOTES:
. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=my-second-helm,app.kubernetes.io/instance=my-second-helm-test" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME :
[root@k8s-master helm]# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
my-second-helm-test default -- ::18.480694046 + CST deployed my-second-helm-0.1. 1.16.

可以看到在install后面指定的就是部署名称,在helm list中可追溯到时通过哪个版本的chart包进行的安装,可以看到状态为deployed,我们之前设定了deployment的副本实例数为2,我们一起来验证下:

[root@k8s-master helm]# kubectl get pod -o wide |grep my-second-helm
my-second-helm-test-566f5d8757-x27zf 1/1 Running 0 5m25s 10.122.235.244 k8s-master <none> <none>
my-second-helm-test-566f5d8757-zdm47 1/1 Running 0 5m25s 10.122.235.247 k8s-master <none> <none>

可以看到2个Pod已经running了,我们测试这个nginx如下所示为正常了,也就是说我们通过helm install chart包的方式成功安装了NGINX的应用

[root@k8s-master helm]# curl 10.122.235.244:
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p> <p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p>
</body>

至此,我们演示了通过在本地目录里面新建了一个默认的chart目录,然后对value中的值进行修改,最后的再次打包,然后安装的全过程,有读者不免发问了,这个过程太麻烦了,我只需要类型像公有镜像,并不想制作chart,是否可以远程直接拉取chart包安装?答案是:可以!接下来我将介绍第二种创建helm 应用的方式。

2)远程拉取chart包

但是在拉取公有的chart包之前,需要先配置好chart repo,如下所示是我已经配置好的chart repo,里面提供常用的chart包

[root@k8s-master my-first-helm]# helm repo list
NAME URL
stable http://mirror.azure.cn/kubernetes/charts
incubator http://mirror.azure.cn/kubernetes/charts-incubator
svc-cat http://mirror.azure.cn/kubernetes/svc-catalog-charts

我们在正式拉取chart包之前,很多时候想在对应的仓库中先查找下有想要的chart包,可以通过如下操作进行查看下,比如我想查看下有无nginx的chart

[root@k8s-master my-first-helm]# helm search repo nginx
NAME CHART VERSION APP VERSION DESCRIPTION
stable/nginx-ingress 1.41. v0.34.1 DEPRECATED! An nginx Ingress controller that us...
stable/nginx-ldapauth-proxy 0.1. 1.13. nginx proxy with ldapauth
stable/nginx-lego 0.3. Chart for nginx-ingress-controller and kube-lego
stable/gcloud-endpoints 0.1. DEPRECATED Develop, deploy, protect and monitor...

可以看到,通过search命令,可查询到仓库中已有的NGINX的chart包,其中stable是repo的类型,CHART VERSION:chart包的版本,APP VERSION:应用版本,DESCRIPTION:针对此chart包的描述,看到这里是不是有印象,这正式是我们在上文提到Chart.yaml文件里面的信息,接下来我们尝试直接从远程仓库进行拉取并完成安装的操作

[root@k8s-master helm]# helm install nginx-test stable/nginx-ingress
WARNING: This chart is deprecated
NAME: nginx-test
LAST DEPLOYED: Sat Sep ::
NAMESPACE: default
STATUS: deployed
REVISION:
TEST SUITE: None
NOTES:
*******************************************************************************************************
* DEPRECATED, please use https://github.com/kubernetes/ingress-nginx/tree/master/charts/ingress-nginx *
******************************************************************************************************* The nginx-ingress controller has been installed.
It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace default get services -o wide -w nginx-test-nginx-ingress-controller' An example Ingress that makes use of the controller: apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
name: example
namespace: foo
spec:
rules:
- host: www.example.com
http:
paths:
- backend:
serviceName: exampleService
servicePort:
path: /
# This section is only required if TLS is to be enabled for the Ingress
tls:
- hosts:
- www.example.com
secretName: example-tls If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided: apiVersion: v1
kind: Secret
metadata:
name: example-tls
namespace: foo
data:
tls.crt: <base64 encoded cert>
tls.key: <base64 encoded key>
type: kubernetes.io/tls
[root@k8s-master helm]# helm list
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
my-second-helm-test default -- ::18.480694046 + CST deployed my-second-helm-0.1. 1.16.
nginx-test default -- ::59.084999904 + CST deployed nginx-ingress-1.41. v0.34.1

可以看到helm应用已经部署成功其应用名称为nginx-test。

2、升级

1)通过修改文件内容升级

可以针对chart目录的文件内容更新后再进行升级,如vim values.yaml文件,我们将之前replicaCount的值设置为4

[root@k8s-master my-second-helm]# vim values.yaml 

# Default values for my-second-helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates. replicaCount:
[root@k8s-master my-second-helm]# helm upgrade -f values.yaml my-second-helm-test ./
Release "my-second-helm-test" has been upgraded. Happy Helming! # 显示升级成功
NAME: my-second-helm-test
LAST DEPLOYED: Sun Sep ::
NAMESPACE: default
STATUS: deployed
REVISION: 5 # release的版本号为5
NOTES:
. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=my-second-helm,app.kubernetes.io/instance=my-second-helm-test" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME :
[root@k8s-master my-second-helm]# kubectl get pod |grep my-second
my-second-helm-test-566f5d8757-8v8wc / Running 6m32s
my-second-helm-test-566f5d8757-kfh5s / Running 11h
my-second-helm-test-566f5d8757-s4286 / Running 86s
my-second-helm-test-566f5d8757-t2hhx / Running 11h

如上看到4个pod实例已经正常Running了,升级成功。

2)通过--set参数升级

其格式为:helm upgrade -f 指定目录/指定文件 --set 指定文件参数=value  部署名称 chart目录

[root@k8s-master helm]# helm upgrade -f my-second-helm/values.yaml --set replicaCount= my-second-helm-test ./my-second-helm
Release "my-second-helm-test" has been upgraded. Happy Helming!
NAME: my-second-helm-test
LAST DEPLOYED: Sun Sep ::
NAMESPACE: default
STATUS: deployed
REVISION: 6 # 版本6
NOTES:
. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=my-second-helm,app.kubernetes.io/instance=my-second-helm-test" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace default port-forward $POD_NAME :
[root@k8s-master helm]# kubectl get pod | grep my-se
my-second-helm-test-566f5d8757-8v8wc / Running 32m
my-second-helm-test-566f5d8757-kfh5s / Running 12h
my-second-helm-test-566f5d8757-t2hhx / Running 12h

在上个版本5中我们在values.yaml修改replicaCount的值为4,版本6中通过--set的方式我们修改了replicaCount的值为3,这个是否会同步到values.yaml中呢?

[root@k8s-master my-second-helm]# cat values.yaml
# Default values for my-second-helm.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates. replicaCount:

通过查看,replicaCount的值任然是版本5的值,并未发生改变,也就是说通过--set的值并不会影响到chart目录下源文件的值,另外从这种方式的升级来看,我们得知helm应用的升级是针对已经部署后的应用进行升级,并非针对chart版本的版本进行升级,这些地方都需要注意下!

3、回滚

升级操作成功后,每升级一次版本都会加1,在上面的例子里版本号已经6了,若我们想回到版本5该如何进行操作呢?我们先看下整个release的部署历史:

[root@k8s-master helm]# helm history my-second-helm-test
REVISION UPDATED STATUS CHART APP VERSION DESCRIPTION
Sat Sep :: superseded my-second-helm-0.1. 1.16. Install complete
Sun Sep :: superseded my-second-helm-0.1. 1.16. Upgrade complete
Sun Sep :: superseded my-second-helm-0.1. 1.16. Upgrade complete
Sun Sep :: superseded my-second-helm-0.1. 1.16. Upgrade complete
Sun Sep :: superseded my-second-helm-0.1. 1.16. Upgrade complete
Sun Sep :: deployed my-second-helm-0.1. 1.16. Upgrade complete

可以看到针对同一个release来说,最终生效的只有一个版本,其状态为:deployed,其他版本为superseded的状态,接下来我们将版本6回滚到版本5

[root@k8s-master my-second-helm]# helm rollback my-second-helm-test
Rollback was a success! Happy Helming!
[root@k8s-master my-second-helm]# kubectl get pod |grep my-second-test
[root@k8s-master my-second-helm]# kubectl get pod |grep my-second
my-second-helm-test-566f5d8757-8v8wc / Running 51m
my-second-helm-test-566f5d8757-kfh5s / Running 12h
my-second-helm-test-566f5d8757-njqbn / Running 61s
my-second-helm-test-566f5d8757-t2hhx / Running 12h

版本5:4个Pod,版本6:3个Pod,可以看到命令执行完成之后立马就回滚且生效了,而回滚的操作命令也很简单,其格式为:helm rollback 部署名称 版本号

4、删除

若想删除已经部署成功的helm应用该如何操作呢?helm应用的删除其chart下的资源如Pod是否会保留?我们带着这些问题实践下:

[root@k8s-master my-second-helm]# helm delete my-second-helm-test
release "my-second-helm-test" uninstalled
[root@k8s-master my-second-helm]# kubectl get all |grep my-second-helm
[root@k8s-master my-second-helm]#

删除的格式为:helm delete 部署名称, 经验证,一旦删除helm的应用,其关联生成的所有资源会被全部删除掉,也就是说,helm提供给用户是一个集合了所需资源的整体应用,其新建和删除也都是以整体应用为维度。

四、总结

本文介绍了什么是Helm,在哪些场景下适用Helm,然后介绍了Helm应用的安装、部署、升级、回滚和删除等操作,Helm应用是一个资源的集合,以整体为用户提供服务,通过这个服务,可以大大简化用户部署的难度,另外还针对应用的版本进行了历史管理,升级和回滚的操作减少了用户自己重新部署和维护版本的成本,在产品设计中,我们可将整个部署helm的流程体现在UI化达到进一步降低部署应用的门槛,校验chart》安装chart-》部署-》升级-》回滚-》删除,设计的重点保证这个业务主流程信息可以清晰的传递给用户,针对重点的操作,需要在页面中重点凸显出来,且要方便用户实际进行操作。

作者简介:云计算容器\Docker\K8s\Serverless方向产品经理,学点技术,为更好地设计产品。

最新文章

  1. Java 内存管理
  2. 【Discuz】云平台服务:出了点小错,由于站点ID/通信KEY等关键信息丢失导致Discuz!云平台服务出现异常
  3. 每日Scrum(6)
  4. C# 匿名方法
  5. break continue return 区别
  6. node-mongodb-native的几种连接数据库的方式
  7. HTML5触摸屏touch事件使用实例1
  8. JavaScript必知的特性(继承)
  9. three.js的wave特效(ivew官网首页波浪特效实现)
  10. C#中异步调用示例与详解
  11. Lambda查询
  12. Python作业之分页显示内容
  13. ScriptManager 发送错误到客户端
  14. 性能测试day03_前端分析调优思路
  15. (98)Address already in use: make_sock: could not bind to address 0.0.0.0:80
  16. HDU1029(KB12-B)
  17. svn 连接超时,连接失败解决办法
  18. shell while-ssh
  19. Kafka系列三 java API操作
  20. 基于LumiSoft.Net.dll发、收、删邮件

热门文章

  1. C#LeetCode刷题之#232-用栈实现队列​​​​​​​​​​​​​​(Implement Queue using Stacks)
  2. C#LeetCode刷题之#172-阶乘后的零(Factorial Trailing Zeroes)
  3. ES6语法学习(一)-let和const
  4. 【NOIP必备攻略】 基本noilinux使用方法
  5. 源码解析JDK1.8-HashMap链表成环的问题解决方案
  6. Jmeter 常用函数(26)- 详解 __chooseRandom
  7. magento2 定时任务
  8. openstack vnc 报1006的错误
  9. selenium入门编程总结学习于龙腾)
  10. Redis取出中文乱码问题