【原創】Kuberneters-HelmV3.3.1入門介紹及實踐

lightinglei發表於2020-09-13

一、為什麼需要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

3 directories, 10 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.0

# 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.0

可以看到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 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
{{- end }}
  selector:
    matchLabels:
      {{- include "my-second-helm.selectorLabels" . | nindent 6 }}
  template:
    metadata:
    {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
    {{- end }}
      labels:
        {{- include "my-second-helm.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "my-second-helm.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- 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: 1

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: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: ClusterIP
  port: 80

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: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

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: 1 chart(s) linted, 1 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

1 chart(s) linted, 0 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.0.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.0.tgz
NAME: my-second-helm-test 
LAST DEPLOYED: Sat Sep 12 21:48:18 2020
NAMESPACE: default
STATUS: deployed                # 狀態
REVISION: 1                      
NOTES:
1. 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 8080:80
[root@k8s-master helm]# helm list
NAME                   NAMESPACE    REVISION    UPDATED                                    STATUS    CHART                   APP VERSION
my-second-helm-test    default      1           2020-09-12 21:48:18.480694046 +0800 CST    deployed  my-second-helm-0.1.0    1.16.0 

可以看到在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:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 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.3           v0.34.1        DEPRECATED! An nginx Ingress controller that us...
stable/nginx-ldapauth-proxy    0.1.4            1.13.5         nginx proxy with ldapauth                         
stable/nginx-lego              0.3.1                           Chart for nginx-ingress-controller and kube-lego  
stable/gcloud-endpoints        0.1.2            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 12 23:47:59 2020
NAMESPACE: default
STATUS: deployed
REVISION: 1
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: 80
              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      1           2020-09-12 21:48:18.480694046 +0800 CST    deployed  my-second-helm-0.1.0    1.16.0     
nginx-test             default      1           2020-09-12 23:47:59.084999904 +0800 CST    deployed  nginx-ingress-1.41.3    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: 4
[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 13 10:41:27 2020
NAMESPACE: default
STATUS: deployed
REVISION: 5                # release的版本號為5
NOTES:
1. 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 8080:80
[root@k8s-master my-second-helm]# kubectl get pod |grep my-second
my-second-helm-test-566f5d8757-8v8wc        1/1     Running   0          6m32s
my-second-helm-test-566f5d8757-kfh5s        1/1     Running   0          11h
my-second-helm-test-566f5d8757-s4286        1/1     Running   0          86s
my-second-helm-test-566f5d8757-t2hhx        1/1     Running   0          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=3 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 13 11:08:30 2020
NAMESPACE: default
STATUS: deployed
REVISION: 6              #  版本6
NOTES:
1. 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 8080:80
[root@k8s-master helm]# kubectl get pod | grep my-se
my-second-helm-test-566f5d8757-8v8wc        1/1     Running   0          32m
my-second-helm-test-566f5d8757-kfh5s        1/1     Running   0          12h
my-second-helm-test-566f5d8757-t2hhx        1/1     Running   0          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: 4

通過檢視,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     
1           Sat Sep 12 21:48:18 2020    superseded    my-second-helm-0.1.0    1.16.0         Install complete
2           Sun Sep 13 00:07:17 2020    superseded    my-second-helm-0.1.0    1.16.0         Upgrade complete
3           Sun Sep 13 10:30:36 2020    superseded    my-second-helm-0.1.0    1.16.0         Upgrade complete
4           Sun Sep 13 10:36:21 2020    superseded    my-second-helm-0.1.0    1.16.0         Upgrade complete
5           Sun Sep 13 10:41:27 2020    superseded    my-second-helm-0.1.0    1.16.0         Upgrade complete
6           Sun Sep 13 11:08:30 2020    deployed      my-second-helm-0.1.0    1.16.0         Upgrade complete

可以看到針對同一個release來說,最終生效的只有一個版本,其狀態為:deployed,其他版本為superseded的狀態,接下來我們將版本6回滾到版本5

[root@k8s-master my-second-helm]# helm rollback my-second-helm-test 5
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        1/1     Running   0          51m
my-second-helm-test-566f5d8757-kfh5s        1/1     Running   0          12h
my-second-helm-test-566f5d8757-njqbn        1/1     Running   0          61s
my-second-helm-test-566f5d8757-t2hhx        1/1     Running   0          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方向產品經理,學點技術,為更好地設計產品。

 

 

                                     

相關文章