天天看點

Helm開發/調試的最佳實踐

本文的目标不限于對Helm官方文檔的翻譯或解釋,更在于幫助開發者能夠快速編寫出一個标準且合理的helm chart。

Helm簡介

一句話描述:Helm是Kubernetes的包管理工具

Helm vs Operator

Helm 和 Operator都可以實作在k8s上安裝應用。但二者有着不同的适用場景。

Helm适用于:

  • 開發者群體
  • 門檻低:熟悉k8s即可
  • 重點在于實作應用的“安裝-更新-删除”

Operator适用于:

  • 運維或SRE團隊
  • 門檻高:對k8s精通,并能結合k8s編寫自運維腳本,實作複雜且定制化的配置
  • 重點在于實作應用的自運維、高可靠。

Helm2 or Helm3

Helm2和Helm3,從開發者的視角有如下差别:

  • 增加了JSON格式的校驗,可以輸出更容易讓人了解的錯誤報告
  • Release name從可選變成必選
  • Release name作用域從全局被限制到了namespace級别
  • Namespaces不再自動建立。如果chart中的namespace不存在,需要手動建立namespace
  • 将requirements.yaml,requirements.lock的内容合并到Chart.yaml,Chart.lock
  • Chart.yaml的apiVersion從v1到v2

其實對開發者來說,helm2 與helm3差異不大,就是helm3對于helm編寫體驗更加友好。

Heml的安裝

Helm的github位址:

https://github.com/helm/helm

可以選擇安裝最新的Helm3,也可以使用Helm2,通過tag找到2.x的最新版本:2.17. 在release中有編譯好的mac二進制程式可以下載下傳直接使用。

Helm 開發技巧

命名模闆(named templates)

命名模闆(named templates)也可以成為子模闆,但他是有個名稱的,可以結合include使用。

我們可以友善把一個模闆檔案中,公共或通用的部分,提取出來,放到一個新的檔案中,并給其命名,這樣就可以帶其他地方使用

通過

define

定義模闆

{{ define "MY.NAME" }}
  # body of template here
{{ end }}           

include

記住标準用法

{{ include "named template" . }}

解釋: . 表示的是scope。 這裡也可以改成 .Values

空格

注意:換行也算空格

{{- 表示左邊的空格和換行會移除

-}} 表示右邊的空格和換行會移除

執行個體:

food: {{ .Values.favorite.food | upper | quote }}
  {{ if eq .Values.favorite.drink "coffee" -}}
  mug: "true"
  {{ end }}           

會渲染出

food: "PIZZA"

mug: "true"

           
food: {{ .Values.favorite.food | upper | quote }}
  {{- if eq .Values.favorite.drink "coffee" -}}
  mug: "true"
  {{- end -}}           
food: "PIZZA"mug: "true"           

正确的寫法是

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {{ .Values.favorite.drink | default "tea" | quote }}
  food: {{ .Values.favorite.food | upper | quote }}
  {{- if eq .Values.favorite.drink "coffee" }}
  mug: "true"
  {{- end }}
           

Helm 本地測試技巧

格式化校驗

helm lint Path [flag]           
  • Path: a path of chart

本地渲染

helm template path [flag]           

helm template指令來自于開源的

https://github.com/technosophos/helm-template

Helm chart最佳實踐

基本規約

Chart命名

必須是小寫字母,分割符用

-

版本規範

版本号遵循SemVer2的規範

Yaml縮進

使用兩個空格縮進,不能用tab

Values 自定義變量

values.yaml編寫的最佳實踐

命名規範

首字母小寫的駝峰式命名

反例:

Chicken: true  # initial caps may conflict with built-ins
chicken-noodle-soup: true # do not use hyphens in the name           

所有Helm内置的變量都是大寫開頭(如.Chart.Name, .Capabilities.KubeVersion),這樣可以和使用者自定義的變量區分開

變量平鋪 Or 層疊

Yaml格式靈活,裡面的變量既可以平鋪也可以層疊編寫

層疊:

server:
  name: nginx
  port: 80           

平鋪:

serverName: nginx
serverPort: 80           

通常:平鋪更好,因為簡單

當相關的一些變量是可選的,為了安全起見,使用層疊方式,并在每個層級中都對變量進行校驗。

{{ if .Values.server }}
  {{ default "none" .Values.server.name }}
{{ end }}           

類型清醒

Yaml的類型轉化的規則有時是反直覺的。比如

foo: false

foo: "false"

不一樣。 大數

foo:1234567

在某些場景下會變成科學計數法表達。

最簡單,清醒的做法:所有變量都用 ""引号 表達成字元串。

在需要使用數字時,用

{{ int $value }}

進行變量轉換

使用字典而不是數組

由于values.yaml的變量是可以支援被指令行的參數

--set

--set-string

改寫,而參數的寫法有限。

是以values.yaml變量的寫法盡可能使用map,而不是數組

servers:
  - name: foo
    port: 80
  - name: bar
    port: 81           

如何用

--set

改寫端口, Helm2.4之前不支援, 2.5之後可以用

--set servers[0].port=80

。 但表意不明确,萬一values裡的順序改變了,就糟糕了。

正例:

servers:
  foo:
    port: 80
  bar:
    port: 81           

改foo的端口

--set servers.foo.port=80

注釋

每個變量都應該注釋。

注釋必須以變量名開頭

正例

# serverHost is the host name for the webserver
serverHost: example
# serverPort is the HTTP listener port for the webserver
serverPort: 9191           

變量名開頭的注釋有利于在grep時,可以快速抓取變量及其文檔說明

Templates 模闆

templates

的結構化規範:

  • 所有的yaml模闆必須有

    .yaml

    字尾, 非格式化内容的模闆使用

    .tpl

    字尾
  • 模闆檔案的命名使用小寫,

    -

    虛線表示法。如(my-example-configmap.yaml)
  • 每種資源的定義必須單獨的模闆檔案
  • 模闆檔案名必須反應出其表示的資源。如:

    foo-pod.yaml

    ,

    bar-svc.yaml

命名模闆

{{ define }}

建立出命名模闆是全局可見的,為了避免名稱沖突,命名中應該帶上命名空間。

{{- define "nginx.fullname" }}
{{/* ... */}}
{{ end -}}           

反例

{{- define "fullname" -}}
{{/* ... */}}
{{ end -}}           

推薦使用

helm create

建立新的chart,它會自動循序最佳實踐

模闆指令

{{ }}

表示模闆指令。在

{{

後和

}}

前需要用一個空格隔開

{{ .foo }}
{{ print "foo" }}
{{- print "bar" -}}           
{{.foo}}
{{print "foo"}}
{{-print "bar"-}}           

Yaml注釋: 常用注釋,而且在

helm install --debug

調試時可見

# This is a comment
type: sprocket           

模闆注釋:多行注釋,常用于對子產品、方法的說明

{{- /*
This is a comment.
*/}}
type: frobnitz
           

Lable和Anonotation

二者都是中繼資料,有着各自的适用場景。

Label

  • 被k8s用來辨別資源
  • 被運維用來查詢

上述兩個目的外的場景,都應該使用Annonation

标準标簽

Name Status Description
app.kubernetes.io/name 推薦 {{ .Chart.Name }}
helm.sh/chart {{ .Chart.Name }}-{{ .Chart.Version replace "+" "_" }}
app.kubernetes.io/managed-by {{ .Release.Service }}, 可用來找Helm托管的應用
app.kubernetes.io/instance {{ .Release.Name }}
app.kubernetes.io/version 可選 {{ .Chart.AppVersion }}
app.kubernetes.io/component 标記應用在系統的角色。如app.kubernetes.io/component: frontend
app.kubernetes.io/part-of 标記所屬的整體

Pod 容器

Image

鏡像需要用固定的标簽或鏡像的sha值,不能用

latest

head

canary

這些“引用”性質标簽

ImagePullPolicy

deployment.yaml

imagePullPolicy: {{ .Values.image.pullPolicy }}           

values.yaml

image:
  pullPolicy: IfNotPresent           

PodTemplates

必須定義一個selector

selector:
  matchLabels:
      app.kubernetes.io/name: MyName
template:
  metadata:
    labels:
      app.kubernetes.io/name: MyName           

一個标準的Helm Chart

待補充

引用

https://helm.sh/docs https://cloudblogs.microsoft.com/opensource/2020/04/02/when-to-use-helm-operators-kubernetes-ops/ https://searchitoperations.techtarget.com/tip/When-to-use-Kubernetes-operators-vs-Helm-charts