helm3(二)

helm介绍

helm是一个简化安装和管理Kubernetes应用程序的工具,可以将其视为Kubernetes的apt/yum/homebrew

helm是用于管理charts的工具,charts是预先配置的Kubernetes资源的软件包。

官网:https://helm.sh,最新版本:v3.3.0

helm用途:

1. 查找并使用Helm Charts将应用程序部署在Kubernetes上

2. 通过Helm Charts将应用程序共享

3. 对Kubernetes应用程序实现可重复构建

4. 简便管理Kubernetes清单文件

5. 管理Helm包的发布

helm概念:

Chart:Helm应用(package),包括对资源的定义及相关镜像的引用,还有模板文件、values文件等

Repository:Chart仓库,http/https服务器,Chart的程序包放在这里

Release:Chart的部署实例,每个Chart可以部署一个或多个Release

helm版本:

在 Helm 2 中,Tiller 是作为一个 Deployment 部署在 kube-system 命名空间中,很多情况下,我们会为 Tiller 准备一个 ServiceAccount ,这个 ServiceAccount 通常拥有集群的所有权限。
用户可以使用本地 Helm 命令,自由地连接到 Tiller 中并通过 Tiller 创建、修改、删除任意命名空间下的任意资源。

在 Helm 3 中,Tiller 被移除了。新的 Helm 客户端会像 kubectl 命令一样,读取本地的 kubeconfig 文件,使用我们在 kubeconfig 中预先定义好的权限来进行一系列操作。

chart是包含至少两项内容的helm软件包:

软件包说明(Chart.yaml)

一个或多个模板,其中包含Kubernetes清单文件

chart介绍

chart是描述一组相关的Kubernetes资源的文件的集合。单个chart可能用于部署简单的内容(如memcached pod)或复杂的内容(如带有http servers,数据库,缓存等的完整Web应用程序堆栈)。

chart创建为放置在特定目录树中的文件,可以将它们打包到版本存档中进行部署。

如果要下载并查看已发布chart的文件而不安装它,则可以使用 helm pull / 进行操作。

  • 文件结构:

chart被组织为目录内文件的集合,目录名称就是chart的名称(不包含版本信息)。因此,描述WordPress的chart将存储在wordpress/目录中。

而在此目录中,helm将期望与以下内容匹配的结构:

wordpress/
  Chart.yaml            # 包含chart信息的YAML文件
  LICENSE               # 包含chart许可的纯文本文件(可选)
  README.md             # README自述文件(可选)
  values.yaml           # 此chart的默认配置值
  values.schema.json    # 用于在 values.yaml 上强加结构的JSON模式(可选)
  charts/               # 包含此chart所依赖的任何charts的目录
  crds/                 # 自定义资源定义(CRD)
  templates/            # 模板目录,与值结合时,将生成有效的Kubernetes清单文件
  templates/NOTES.txt   # 包含简短用法说明的纯文本文件(可选)

helm保留了charts/crds/templates/目录的使用,以及列出的文件名。其他文件将保持原样。

  • Chart.yaml:

Chart.yaml文件是chart所必需的。它包含以下字段:

apiVersion:                 # chart API版本 (必需)
name:                       # chart 名称 (必需)
version:                    # 版本 (必需, SemVer 2标准)
kubeVersion:                # 所有兼容的Kubernetes 版本 (可选, SemVer 2标准)
description:                # 项目单句描述 (可选)
type:                       # chart 类型,application 和 library (可选)
keywords:
  -                         # 关于项目的关键字列表 (可选)
home:                       # 项目主页的url (可选)
sources:
  -                         # 项目源码的url列表 (可选)
dependencies:               # chart 需求列表 (可选)
  - name:                   # chart 名称 (nginx)
    version:                # chart 版本 ("1.2.3")
    repository:             # repo url ("https://example.com/charts") 或 别名 ("@repo-name")
    condition:              # 一个解析为boolean的yaml路径,用于 启用/禁用 charts (如 subchart1.enabled ) (可选)
    tags:                   # (可选)
      -                     # Tags 可以用来对 charts 的 启用/禁用 分组 (可选)
    enabled:                # 使用 bool 参数决定是否应该加载 chart (可选)
    import-values:          # (可选)
      -                     # ImportValues 保存源值到要导入父键的映射。每一项可以是一个字符串或一对子/父子列表项 (可选)
    alias:                  # 用于 chart 的别名。多次添加相同的 chart 时很有用 (可选)
maintainers:                # (可选)
  - name:                   # 维护人员名称 (每个维护人员必需)
    email:                  # 维护人员email (每个维护人员可选)
    url:                    # 维护人员的url (每个维护人员可选)
icon:                       # 作为图标使用的 SVG 或 PNG 图片 的url (可选)
appVersion:                 # app 版本 (可选)
deprecated:                 # chart 是否已弃用 (可选, boolean)
annotations:
  example:                  # 按名称键入的注释列表 (可选)
  • chart依赖:

helm中,一个chart可能会依赖任意数量的其它chart。这些依赖项可以在Chart.yaml中通过dependencies字段进行动态配置,也可以导入charts/目录中并手动进行管理。

当前chart所依赖的chart在dependencies字段中定义为列表:

dependencies:
  - name: apache
    version: 1.2.3
    repository: https://example.com/charts
  - name: mysql
    version: 3.2.1
    repository: https://another.example.com/charts

repository字段是chart repo的完整url。需要注意的是,必须使用helm repo add 本地添加该repo。可以使用存储库的名称代替url。

helm repo add example-charts https://example.com/charts
dependencies:
  - name: apache
    version: 1.2.3
    repository: "@example-charts"

定义依赖项后,可以运行helm dependency update ,它将使用依赖项文件将所有指定的chart下载到您的charts/目录中。

  • 依赖项别名:

除上述字段外,每个依赖项都可以包含可选字段alias

为依赖的chart添加别名,将chart置于依赖关系中时将使用别名作为依赖项的名称。

dependencies:
  - name: subchart
    repository: http://localhost:10191
    version: 0.1.0
    alias: new-subchart-1
  - name: subchart
    repository: http://localhost:10191
    version: 0.1.0
    alias: new-subchart-2
  - name: subchart
    repository: http://localhost:10191
    version: 0.1.0

在上面的示例中,将获得3个依赖项:

subchart
new-subchart-1
new-subchart-2
  • 依赖项标签和条件:

除上述字段外,每个依赖项还可以包含可选字段tagscondition

默认情况下会加载所有chart。如果存在tagscondition字段,则它们将被用于控制应用它们的chart的加载。

condition字段包含一个或多个yaml路径(以逗号分隔)。如果此路径存在于父chart的Values中并解析为布尔值,则将基于该布尔值 启用/禁用 chart。仅列表中找到的第一个路径有效,如果不存在路径,则该条件无效。

tags字段是与该chart关联的yaml标签列表。在父chart的Values中,可以通过指定标签和布尔值来 启用/禁用 所有带有标签的chart。

dependencies:
  - name: subchart1
    repository: http://localhost:10191
    version: 0.1.0
    condition: subchart1.enabled, global.subchart1.enabled
    tags:
      - front-end
      - subchart1
  - name: subchart2
    repository: http://localhost:10191
    version: 0.1.0
    condition: subchart2.enabled,global.subchart2.enabled
    tags:
      - back-end
      - subchart2

values.yaml

subchart1:
  enabled: true
tags:
  front-end: false
  back-end: true

上面示例中,所有带有标签front-end都将被禁用,但是由于subchart1.enabled路径在父chart的Values中为true,因此条件将覆盖front-end标签并启用subchart1

由于subchart2带有标签back-end,且back-end为true,subchart2将被启用。另外,尽管subchart2指定了条件,但父chart的Values中没有相应的路径和值,因此该条件无效。

--set参数可以用于更改标签和条件值:

helm install --set tags.front-end=true --set subchart2.enabled=false

标签和条件解析:

- 条件(有设置时)始终会覆盖标签。存在的第一个条件路径获胜,后续条件路径将被忽略

- 如果chart的任何标签为true,则启用该chart

- 标签和条件值必须设置在父chart的 Values 中

- tags:父chart的 Values 中的键必须是顶级键;不支持全局和嵌套表

helm内置对象

对象从模板引擎传递到模板中。

对象可以很简单,只有一个值;或者可以包含其他对象或函数。例如,Release 对象包含多个对象(如 Release.Name)并且 Files 对象具有一些函数。

Release:此对象描述发行版本身。它里面有几个对象:
    
    Release.Name:release 名称
    
    Release.Namespace:release 的 namespace(如果清单未覆盖)
    
    Release.IsUpgrade:如果当前操作是upgrade或rollback,则设置为 true
    
    Release.IsInstall:如果当前操作是install,则设置为 true
    
    Release.Revision:release的版本号。初始部署时为1,并且每次升级或回滚时加1
    
    Release.Service:release 服务的名称。在Helm上,始终是Helm
 
Values:从 values.yaml 文件和用户提供的文件传入模板的值,默认情况下 Values 为空
 
Chart:Chart.yaml 文件的内容。Chart.yaml 中的任何数据都可以在此处访问

Files:提供对 chart 中所有非特殊文件的访问。不能使用它来访问模板,但是可以使用它来访问 chart 中的其他文件:

    Files.Get:是用于通过名称(.Files.Get config.ini)获取文件的函数
    
    Files.GetBytes:是将文件内容作为字节数组而不是字符串获取的函数
    
    Files.Glob:是一个函数,该函数返回名称与给定的Shell Glob模式匹配的文件列表
    
    Files.Lines:是逐行读取文件的函数,对于遍历文件很有用
    
    Files.AsSecrets:是将文件主体作为Base64编码的字符串返回的函数
    
    Files.AsConfig:是一个将文件正文作为YAML映射返回的函数

Capabilities:提供了有关Kubernetes集群支持哪些功能的信息:
    
    Capabilities.APIVersions:是一组版本
    
    Capabilities.APIVersions.Has $version:指示版本(例如 batch/v1)或资源(例如 apps/v1/Deployment)在集群上是否可用
    
    Capabilities.KubeVersion 和 Capabilities.KubeVersion.Version:是Kubernetes版本
    
    Capabilities.KubeVersion.Major:是Kubernetes的主要版本
    
    Capabilities.KubeVersion.Minor:是Kubernetes的次要版本
 

Template:包含有关正在执行的当前模板的信息:

    Template.Name:当前模板的命名空间文件路径(例如 mychart/templates/mytemplate.yaml)

    Template.BasePath:当前 chart 的模板目录的命名空间路径(例如 mychart/templates)

上⾯的值可用于任何顶级模板,要注意内置值始终以大写字母开头。


values.yaml

helm模板提供的内置对象之一是Values,该对象提供对传递到chart中的值的访问。其内容来自多种来源:

1. chart 中的 values.yaml 文件

2. 如果是子chart,则是父chart 中的 values.yaml 文件

3. helm install 或 helm upgrade 带的 -f 参数指定的yaml文件(如 helm install -f myvals.yaml ./mychart)

4. 通过 --set 参数传递的值(如 helm install --set foo=bar ./mychart)

上面按顺序排列:values.yaml 是默认值,可以被父chart的 values.yaml 覆盖,而后者可以由用户提供的yaml文件覆盖,而后者又可以由 --set 参数覆盖。

示例 values.yaml

favorite:
  drink: coffee
  food: pizza

根据示例 values.yaml,可以这样修改模板:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {
     {
      .Values.favorite.drink }}
  food: {
     {
      .Values.favorite.food }}

模板函数和管道

当将 .Values 对象中的字符串注入到模板时,可以通过调用模板函数 quote 来引用这些字符串:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {
     {
      quote .Values.favorite.drink }}
  food: {
     {
      quote .Values.favorite.food }}

模板函数遵循语法:functionName arg1 arg2...,在上面代码段中,quote .Values.favorite.drink 调用 quote 函数并将其传递给单个参数。

  • 管道 |

管道 | 是将一系列模板命令链接在一起的工具,以紧凑地表达一系列转换。管道 | 是按顺序完成多项工作的有效方式。

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {
     {
      .Values.favorite.drink | quote }}
  food: {
     {
      .Values.favorite.food | quote }}

上面示例中,没有调用,而是反转了顺序。使用管道 | 将参数“发送”到函数:.Values.favorite.food | quote

反转顺序是模板中的常见做法,.val | quotequote .val 更为常见。

使用管道,可以将多个功能链接在一起:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  drink: {
     {
      .Values.favorite.drink | quote }}
  food: {
     {
      .Values.favorite.food | upper | quote }}

该模板产生以下输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: trendsetting-p-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"

上面示例中,已经将 pizza 转换为 “PIZZA”。

  • default 函数:

default 函数允许在模板内部指定默认值,以防省略该值。

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 }}

values.yaml中可以注释drink,得到输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: fair-worm-configmap
data:
  myvalue: "Hello World"
  drink: "tea"
  food: "PIZZA"

在实际chart中,所有默认值都应该配置在 values.yaml 中,并且不应使用 default 函数重复。

  • lookup 函数:

lookup 函数可用于在运行中的集群中查找资源。

参数的组合:

kubectl get pod mypod -n mynamespace	→   lookup "v1" "Pod" "mynamespace" "mypod"

kubectl get pods -n mynamespace         →   lookup "v1" "Pod" "mynamespace" ""

kubectl get pods --all-namespaces       →   lookup "v1" "Pod" "" ""

kubectl get namespace mynamespace       →   lookup "v1" "Namespace" "" "mynamespace"

kubectl get namespaces                  →   lookup "v1" "Namespace" "" ""

lookup 返回一个对象时,它将返回一个字典,可以进一步从字典中提取特定值。

例如,返回该 mynamespace 对象存在的注释:

(lookup "v1" "Namespace" "" "mynamespace").metadata.annotations

lookep 返回一个对象列表时,可以通过items字段访问对象列表:

{
     {
      range $index, $service := (lookup "v1" "Service" "mynamespace" "").items }}
    {
     {
     /* do something with each service */}}
{
     {
      end }}

如果找不到对象,则返回一个空值。

lookup 函数使用Helm现有的Kubernetes连接配置来查询Kubernetes。如果在与调用API服务器进行交互时返回任何错误(例如缺乏访问资源的权限),则模板处理将失败。

需要注意的是,在 helm templatehelm install|update|delete|rollback --dry-run 期间,Helm不会与Kubernetes API Server联系,因此在这种情况下 lookup 函数将返回 nil

indent:从左到右指定空格个数

with:可以允许将当前范围 . 设置为特定的对象。例如 .Values.service,使用 with 可以将 .Values.service 改为 .

变量:在 Helm 模板中,变量是对另一个对象的命名引用。它遵循这个形式 $name。变量被赋予一个特殊的赋值操作符::=
  • .Capabilities.APIVersions.Has 函数:

.Capabilities.APIVersions.Has 函数返回API版本或资源在集群中是否可用。

.Capabilities.APIVersions.Has "apps/v1"

.Capabilities.APIVersions.Has "apps/v1/Deployment"
  • 其它常用函数:
and     返回两个参数的布尔值和

or      返回两个参数的布尔值或。它返回第一个非空参数或最后一个参数

not     返回其参数的布尔取反

eq      如果Arg1 = Arg2,则返回true,否则返回false

ne      如果Arg1 != Arg2,则返回true,否则返回false

lt      如果Arg1 < Arg2,则返回true,否则返回false

le      如果Arg1 <= Arg2,则返回true,否则返回false

gt      如果Arg1 > Arg2,则返回true,否则返回false

ge      如果Arg1 >= Arg2,则返回true,否则返回false

lower       将整个字符串转换为小写

upper       将整个字符串转换为大写

repeat      重复给定字符串多次

substr      从字符串获取子字符串

nospace     从字符串中删除所有空格

indent      indent 函数将给定字符串中的每一行缩进到指定的缩进宽度

nindent     nindent 函数与 indent 函数相同,但是在字符串的开头添加了新行

replace     执行简单的字符串替换

reverse     用给定列表的元素,生成一个新列表,顺序与原列表相反

uniq        生成一个列表,删除所有重复项

has     测试列表是否具有特定元素,返回true,否则返回false

slice       获取列表部分元素,列表切片

until       生成一个顺序的整数列表

untilStep       和 until 一样,生成一个顺序的整数列表,但 untilStep 允许定义开始、结束和步长

seq     类似 seq 命令,生成参数之间的所有整数,默认步长为1或-1,单调递增或递减

add     相加

add1    加1

sub     相减

div     相除

mul     相乘

max     最大值

min     最小值

floor       返回 <= 输入值的最大浮点数

ceil        返回 >= 输入值的最大浮点数

round       四舍五入,返回一个浮点数

len     以整数形式返回参数的长度

base        返回路径的最后一个元素

dir     返回目录,去除路径的最后一部分

clean       清理路径,只保留路径开头和结尾

ext     返回文件扩展名

isAbs       检查文件路径是否是绝对路径

Helm包含许多模板函数,可以在模板中使用它们。常用函数:https://helm.sh/docs/chart_template_guide/function_list/


流程控制

控制结构(在模板中被称为“动作”)提供了控制模板生成流程的能力。helm的模板语言提供以下控制结构:

if/else     用于创建条件块

with        指定范围

range       提供“针对每个”样式的循环

除此之外,helm还提供了一些声明和使用命名模板段的操作:

define      在模板中声明一个新的命名模板

template    导入命名模板

block       声明一种特殊的可填充模板区域
  • if/else:

基础结构:

{
     {
      if PIPELINE }}
  # Do something
{
     {
      else if OTHER PIPELINE }}
  # Do something else
{
     {
      else }}
  # Default case
{
     {
      end }}

如果值为以下内容,pipeline 为false:

布尔值false

数字0

空字符串

nil(empty或null)

空集合(map,slice,tuple,dict,array)

在其他条件下,pipeline 为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 }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: eyewitness-elk-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  mug: true
  • with:

with控制变量作用域。. 是对当前范围的引用,而 .Values 告诉模板 Values 在当前范围内查找对象。

with的语法类似于一个简单的 if 语句:

{
     {
      with PIPELINE }}
  # restricted scope
{
     {
      end }}

with可以将当前范围 . 设置为特定对象:

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

但是需要注意,在受限范围内,将无法使用 . 从父chart范围访问其他对象:

  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  release: {
     {
      .Release.Name }}
  {
     {
     - end }}

由于 Release.Name 不在 . 的限制范围内,因此会报错。但是可以使用 { { end }}重置作用域:

  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  {
     {
     - end }}
  release: {
     {
      .Release.Name }}

还可以用 $ 从父chart范围访问对象 Release.name。模板执行开始时将 $ 映射到根作用域,并且在模板执行期间不会更改。以下内容也可以工作:

  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  release: {
     {
      $.Release.Name }}
  {
     {
     - end }}
  • range

在helm的模板语言中,迭代集合的方法是使用 range 运算符。

示例:

values.yaml

favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions
apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  {
     {
     - end }}
  toppings: |-
    {
     {
     - range .Values.pizzaToppings }}
    - {
     {
      . | title | quote }}
    {
     {
     - end }}

以下内容也可以工作:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  toppings: |-
    {
     {
     - range $.Values.pizzaToppings }}
    - {
     {
      . | title | quote }}
    {
     {
     - end }}
  {
     {
     - end }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: edgy-dragonfly-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  toppings: |-
    - "Mushrooms"
    - "Cheese"
    - "Peppers"
    - "Onions"

变量

在helm模板中,变量是对另一个对象的命名引用。它遵循以下形式:$name,变量使用特殊的赋值运算符::=

在前面的示例中,此代码会失败:

  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  release: {
     {
      .Release.Name }}
  {
     {
     - end }}

Release.Name 不在该代码with块限制的范围之内。可以将上面代码重写为对变量使用Release.Name

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {
     {
     - $relname := .Release.Name -}}
  {
     {
     - with .Values.favorite }}
  drink: {
     {
      .drink | default "tea" | quote }}
  food: {
     {
      .food | upper | quote }}
  release: {
     {
      $relname }}
  {
     {
     - end }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: viable-badger-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "PIZZA"
  release: viable-badger

变量在 range 循环中特别有用。它们可以用于类似列表的对象,以同时捕获索引和值:

toppings: |-
    {
     {
     - range $index, $topping := .Values.pizzaToppings }}
      {
     {
      $index }}: {
     {
      $topping }}
    {
     {
     - end }}

注意,range 首先跟的是变量,然后是赋值运算符,然后是列表。这会将整数索引(从零开始)分配给 $index,并将值分配给$topping

输出:

  toppings: |-
      0: mushrooms
      1: cheese
      2: peppers
      3: onions

对于同时具有键和值的数据结构,可以使用range两者来获取。

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  myvalue: "Hello World"
  {
     {
     - range $key, $val := .Values.favorite }}
  {
     {
      $key }}: {
     {
      $val | quote }}
  {
     {
     - end }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: eager-rabbit-configmap
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"

变量通常不是“全局”的,它们的作用域仅限于声明它们的块。$ 变量是全局变量,该变量始终指向根上下文。


命名模板

命名模板也称为部分模板或子模板,是一个简单的文件中定义的、并且给定名称的模板。_helpers.tpl 文件是命名模板的默认位置。

命名模板需要注意的是,模板名称是全局的,如果声明了两个相同名称的模板,则以最后加载的那个为准。

通常的命名约定是在每个定义的模板前添加chart名称:{ { define "mychart.labels" }}。通过使用特定的chart名称作为前缀,可以避免由于模板名称相同而引起的任何冲突。

  • define

define 操作可以在模板文件内部创建命名模板,语法如下:

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

定义一个模板来封装Kubernetes标签块,示例:

{
     {
     - define "mychart.labels" }}
  labels:
    generator: helm
    date: {
     {
      now | htmlDate }}
{
     {
     - end }}

将此模板嵌入到现有的ConfigMap中,然后将其包含在 template 操作中:

{
     {
     - define "mychart.labels" }}
  labels:
    generator: helm
    date: {
     {
      now | htmlDate }}
{
     {
     - end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
  {
     {
     - template "mychart.labels" }}
data:
  myvalue: "Hello World"
  {
     {
     - range $key, $val := .Values.favorite }}
  {
     {
      $key }}: {
     {
      $val | quote }}
  {
     {
     - end }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: running-panda-configmap
  labels:
    generator: helm
    date: 2016-11-02
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"

helm chart通常将这些模板放在 _helpers.tpl 文件中,然后可以在ConfigMap中调用:

_helpers.tpl

{
     {
     /* Generate basic labels */}}
{
     {
     - define "mychart.labels" }}
  labels:
    generator: helm
    date: {
     {
      now | htmlDate }}
{
     {
     - end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
  {
     {
     - template "mychart.labels" }}
data:
  myvalue: "Hello World"
  {
     {
     - range $key, $val := .Values.favorite }}
  {
     {
      $key }}: {
     {
      $val | quote }}
  {
     {
     - end }}
  • 模板范围:

_helpers.tpl

{
     {
     /* Generate basic labels */}}
{
     {
     - define "mychart.labels" }}
  labels:
    generator: helm
    date: {
     {
      now | htmlDate }}
    chart: {
     {
      .Chart.Name }}
    version: {
     {
      .Chart.Version }}
{
     {
     - end }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
  {
     {
     - template "mychart.labels" . }}
helm install --dry-run --debug plinking-anaco ./mychart

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: plinking-anaco-configmap
  labels:
    generator: helm
    date: 2016-11-02
    chart: mychart
    version: 0.1.0

当命名模板(使用 define 创建的模板)被渲染时,它将接收 template 调用传递的范围。

  • include 函数:

示例:

{
     {
     - define "mychart.app" -}}
app_name: {
     {
      .Chart.Name }}
app_version: "{
     { .Chart.Version }}"
{
     {
     - end -}}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
  labels:
    {
     {
      template "mychart.app" . }}
data:
  myvalue: "Hello World"
  {
     {
     - range $key, $val := .Values.favorite }}
  {
     {
      $key }}: {
     {
      $val | quote }}
  {
     {
     - end }}
{
     {
      template "mychart.app" . }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: measly-whippet-configmap
  labels:
    app_name: mychart
app_version: "0.1.0+1478129847"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
  app_name: mychart
app_version: "0.1.0+1478129847"

可以看到,app_version 的缩进是错误的,因为 template 是操作而不是函数,所以无法将template调用的输出传递给其他函数。

helm提供了一种替代方法,include 可以将模板的内容导入到当前pipeline中,然后可以将其传递给pipeline中的其它函数。

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
  labels:
{
     {
      include "mychart.app" . | indent 4 }}
data:
  myvalue: "Hello World"
  {
     {
     - range $key, $val := .Values.favorite }}
  {
     {
      $key }}: {
     {
      $val | quote }}
  {
     {
     - end }}
{
     {
      include "mychart.app" . | indent 2 }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: edgy-mole-configmap
  labels:
    app_name: mychart
    app_version: "0.1.0+1478129987"
data:
  myvalue: "Hello World"
  drink: "coffee"
  food: "pizza"
  app_name: mychart
  app_version: "0.1.0+1478129987"

访问模板内的文件

有时要导入文件,而不是模板,可以通过 .Files 描述的对象访问文件来实现。

helm提供了通过 .Files 对象访问文件的权限。有几点需要注意:

1. 在chart中可以添加其他文件。但由于Kubernetes对象的存储限制,chart必须小于1M

2. .Files 因为安全原因,某些文件无法通过该对象访问:

    无法访问 templates/ 中的文件

    无法访问使用 .helmignore 排除的文件
    
3. chart不保留 unix模式信息,因此文件级权限限制对 .Files 对象的文件可用性没有影响
  • 示例:

编写一个模板,将三个文件读入ConfigMap。首先向chart添加三个文件,将三个文件放入 mychart/ 目录中。

config1.toml

message = Hello from config 1

config1.toml

message = Hello from config 2

config3.toml

message = Hello from config 3

使用 range 函数来遍历它们,并将其内容注入到ConfigMap中:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {
     {
      .Release.Name }}-configmap
data:
  {
     {
     - $files := .Files }}
  {
     {
     - range tuple "config1.toml" "config2.toml" "config3.toml" }}
  {
     {
      . }}: |-
    {
     {
      $files.Get . }}
  {
     {
     - end }}

输出:

apiVersion: v1
kind: ConfigMap
metadata:
  name: quieting-giraf-configmap
data:
  config1.toml: |-
    message = Hello from config 1

  config2.toml: |-
    message = This is config 2

  config3.toml: |-
    message = Goodbye from config 3
  • 文件路径处理:

在处理文件时,对文件路径本身执行一些标准操作会非常有用。相关函数有:

base        返回路径的最后一个元素

dir     返回目录,去除路径的最后一部分

clean       清理路径,只保留路径开头和结尾

ext     返回文件扩展名

isAbs       检查文件路径是否是绝对路径
  • glob模式:

随着chart的增长,可能会更需要组织文件。helm提供了 Files.Glob(pattern string) 方法,用来以glob模式灵活地提取某些文件。

例如,目录结构如下:

foo/:
  foo.txt foo.yaml

bar/:
  bar.go bar.conf baz.yaml

globs有多种选择:

{
     {
      $currentScope := .}}
{
     {
      range $path, $_ :=  .Files.Glob  "**.yaml" }}
    {
     {
     - with $currentScope}}
        {
     {
      .Files.Get $path }}
    {
     {
     - end }}
{
     {
      end }}

{
     {
      range $path, $_ :=  .Files.Glob  "**.yaml" }}
      {
     {
      $.Files.Get $path }}
{
     {
      end }}
  • ConfigMap 和 Secrets 实用函数:

想要将文件内容同时放入ConfigMap和Secrets中,以便在运行时安装到pod中。

结合glob模式,从上面的glob示例给出目录结构:

apiVersion: v1
kind: ConfigMap
metadata:
  name: conf
data:
{
     {
      (.Files.Glob "foo/*").AsConfig | indent 2 }}
---
apiVersion: v1
kind: Secret
metadata:
  name: very-secret
type: Opaque
data:
{
     {
      (.Files.Glob "bar/*").AsSecrets | indent 2 }}
  • 编码方式:

可以导入文件并使用base-64模板对其进行编码,以确保成功传输:

apiVersion: v1
kind: Secret
metadata:
  name: {
     {
      .Release.Name }}-secret
type: Opaque
data:
  token: |-
    {
     {
      .Files.Get "config1.toml" | b64enc }}

输出:

apiVersion: v1
kind: Secret
metadata:
  name: lucky-turkey-secret
type: Opaque
data:
  token: |-
    bWVzc2FnZSA9IEhlbGxvIGZyb20gY29uZmlnIDEK
  • Lines

有时,需要访问模板中文件的每一行。

为此helm提供了 Lines 方法,Lines可以使用 range 函数循环遍历:

data:
  some-file.txt: {
     {
      range .Files.Lines "foo/bar.txt" }}
    {
     {
      . }}{
     {
      end }}

helm install 期间,无法将外部文件传递给chart。因此,必须使用 helm install -fhelm install --set 加载数据。


子chart和全局Values

chart可以具有依赖项,称为子chart,子chart也有自己的values和templates。

关于子chart,有几点主要注意:

1. 子chart被看作“独立的”,它不能显式依赖其父chart,子chart无法访问其父chart的values

2. 父chart可以覆盖子chart的values

3. helm可以设置能被所有chart访问的全局values
  • 创建子chart:
helm create mychart

cd mychart/charts

helm create mysubchart

当子chart中values的key与父chart中values的key相同时,父chart的values会覆盖子chart的values。

  • 全局values:

全局values是可以从任何chart或子chart中以完全相同的名称访问的values。全局values需要显式声明。

Values.global可以用来设置全局values,例如:

values.yaml

favorite:
  drink: coffee
  food: pizza
pizzaToppings:
  - mushrooms
  - cheese
  - peppers
  - onions

mysubchart:
  dessert: ice cream

global:
  salad: caesar             #全局values
  • 共享模板:

父chart可以与子chart共享模板。任何chart中任何已定义的模板块都可以用于其它chart。

定义一个简单的模板,例如:

{
     {
     - define "labels" }}from: mychart{
     {
      end }}

includetemplate 函数都可以引用模板,但 include 可以动态引用,而 template 仅接受字符串。

{
     {
      include $mytemplate }}

更多

  • .helmignore 文件:

.helmignore 文件用于指定不想包含在helm chart中的文件。

如果存在 .helmignore 文件,helm package 命令将忽略该文件中匹配到的所有文件。

.helmignore 文件支持unix shell全局匹配、相对路径匹配和否定(以 ! 前缀)。每行仅支持一种模式。

示例:

# comment
.git
*/temp*
*/*/temp*
temp?
  • 调试:
helm lint       验证chart是否遵循语法

helm install --dry-run --debug      渲染模板,然后返回生成的kubernetes清单文件

helm template --debug       渲染模板,然后返回生成的kubernetes清单文件

helm get manifest       查看服务器上安装了哪些模板

当yaml无法解析、但想查看生成内容时,可以先在模板中注释掉问题部分,然后重新运行 helm install --dry-run --debug

apiVersion: v2
# some: problem section
# {
     { .Values.foo | quote }}

上面的内容将渲染并返回完整的注释:

apiVersion: v2
# some: problem section
#  "bar"

你可能感兴趣的:(Kubernetes,kubernetes,helm)