Helm开发/调试的最佳实践

简介: 本文的目标不限于对Helm官方文档的翻译或解释,更在于帮助开发者能够快速编写出一个标准且合理的helm chart。## Helm简介一句话描述:Helm是Kubernetes的包管理工具### Helm vs OperatorHelm 和 Operator都可以实现在k8s上安装应用。但二者有着不同的适用场景。Helm适用于:- 开发者群体- 门槛低:熟悉k8s即可-

本文的目标不限于对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: falsefoo: "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

相关实践学习
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。     相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
域名解析 Kubernetes 网络协议
k8s教程(service篇)-pod的dns域名
k8s教程(service篇)-pod的dns域名
3213 0
|
NoSQL MongoDB SQL
MongoShake最佳实践
mongoshake最佳实践,到底该怎么玩?
21888 0
|
JavaScript 前端开发 Java
liteflow规则引擎 执行Javascript脚本
liteflow规则引擎 执行Javascript脚本
423 1
|
jenkins Java Shell
使用 Docker 安装 Jenkins 并实现项目自动化部署
Jenkins 是一款开源的持续集成(DI)工具,广泛用于项目开发,能提供自动构建,测试,部署等功能。作为领先的开源自动化服务器,Jenkins 提供了数百个插件来支持构建、部署和自动化任何项目。
36176 3
使用 Docker 安装 Jenkins 并实现项目自动化部署
|
SQL 关系型数据库 MySQL
如何解决mysql警告:“ InnoDB:page_cleaner:1000毫秒的预期循环用了XXX毫秒设置可能不是最佳的”?
如何解决mysql警告:“ InnoDB:page_cleaner:1000毫秒的预期循环用了XXX毫秒设置可能不是最佳的”?
3523 0
|
前端开发 Java 数据库连接
35个项目,开源,开源!
35个项目,开源,开源!
1486 0
35个项目,开源,开源!
|
JSON Kubernetes 数据格式
crictl 常见的命令大全
crictl(Container Runtime Interface Command Line Interface)是一个命令行工具,用于与符合Kubernetes容器运行时接口(CRI)规范的容器运行时进行交互。它提供了一系列命令来查看和管理容器、镜像、Pod等资源。以下是crictl的一些常见命令及其功能概述: ### 1. 镜像管理 * **查看镜像**: - `crictl images`:列出所有镜像。 - `crictl images | grep <image-name>`:查看特定镜像。 * **拉取镜像**: - `crictl pull <image_na
5560 8
|
JSON 前端开发 JavaScript
Go怎么解析不定JSON数据?
在Go中处理不确定结构的JSON数据,可以使用`map[string]interface{}`来解析,它能适应各种JSON键值对,但需要类型检查。另一种方法是使用`json.RawMessage`保存原始JSON,之后按需解析。此外,`json.Number`用于处理任意精度的数字。当JSON字段类型未知时,可以先解码到`interface{}`并做类型断言。第三方库如gjson和jsonparser提供更灵活的解析选项。
553 1
|
存储 NoSQL 分布式数据库
数据库的演进之路:从传统到现代,技术的飞跃与应用
一、引言 数据库作为数据存储和管理的核心工具,随着信息技术的快速发展,经历了从简单到复杂、从单机到分布式的演进过程
|
缓存 Java 数据库连接
【Mybatis】说一下 mybatis 的一级缓存和二级缓存
【Mybatis】说一下 mybatis 的一级缓存和二级缓存