查看原文
其他

从基础到高级:Helm 指南

Sandor Guba K8sMeetup社区 2019-04-06


编辑:bot

技术校对:星空下的文仔、小君君

如果你熟悉 apt / yum / Homebrew 及其在不同操作系统中的作用,你应该明白软件包管理器的重要性。随着 Kubernetes 奠定了自己在容器编排上的地位,它也亟需一种包管理器来提高开发人员工作效率、降低应用部署复杂性、加快云原生应用程序的采用。 这就是我们今天的要介绍的工具——Helm。

入门 Helm,首先要了解它是什么,有什么用。

Helm 能帮你管理 Kubernetes 应用程序:Helm Chart 可帮你定义、安装和升级最复杂的 Kubernetes 应用程序。—— https://helm.sh/

2018 年 6 月,云原生计算基金会(CNCF)技术监督委员会(TOC)投票决定接受 Helm 作为孵化级托管项目,标志着 Helm 已经成为 Kubernetes 包管理的 de facto。

Helm 简介

众所周知,Kubernetes 是一个功能强大且流行的容器编排系统,但把应用程序部署到上面并不简单。哪怕只是部署单个应用程序,它也会涉及创建多个相互依赖的 Kubernetes 资源,如 Pod、Service、Deployment 和 ReplicaSet 等。每个资源都要求编写详细的 YAML 清单文件。

这意味着我们在实践中会面临诸多挑战:

  • 如何管理、编辑和更新这些分散的 Kubernetes 应用配置文件;

  • 如何把一套相关的配置文件作为一个应用进行管理;

  • 如何分发和重用 Kubernetes 的应用配置。

Helm 就是为解决这些问题而生的。

Helm 的操作基于两个主要组件的协作:一个名为 helm 的命令行工具和一个名为 tiller 的服务端组件(必须在它管理的集群上运行)。

Helm 部署的基本构建块是 Helm Chart,它负责封装 Kubernetes 原生应用程序的 YAML 文件,可以本地存储,也可以从远程 Chart 仓库中获取。

 安装 Helm 

要安装命令行工具 helm,我们可以用受支持的软件包管理器,或者只需下载预编译的二进制文件:

# Brew $ brew install kubernetes-helm # Choco $ choco install kubernetes-helm # Gofish $ gofish install helm

安装完成后,输入 helm init,我们就能在 Kubernetes 群集上安装 Tiller:

# Select the Kubernetes context you want to use $ kubectl config use-context docker-for-desktop $ helm init

注:在集群上启用 RBAC 后,我们可能要为 tiller Pod 设置适当的权限。

 Helm repo 

安装完 Helm 后,我们不需要本地就有可用的 Chart,因为 Helm 可以进行远程仓库管理,它提供一个默认仓库  stable,但你也可以视情况添加、删除仓库。

$ helm repo add banzaicloud-stable https://kubernetes-charts.banzaicloud.com/branch/master $ helm repo list NAME                        URL stable                      https://kubernetes-charts.storage.googleapis.com banzaicloud-stable          https://kubernetes-charts.banzaicloud.com/branch/master/

注:上面有一个国内不存在的 URL,记得先搭好梯子。

如果要把 Chart 安装到集群,只需指定 Chart 的名称和可选的自定义配置值:

# Install with default values $ helm install banzaicloud-stable/logging-operator # Install with custom yaml file $ helm install banzaicloud-stable/logging-operator -f example.yaml # Install with value overrides $ helm install banzaicloud-stable/logging-operator --set rbac.enabled=false


创建新 Chart

使用 Helm 包非常简单,但编写 Helm Chart 也不难,只是稍微复杂一些。

有时,如果找不到要部署软件的现有 Chart,我们可能得自己创建一个。要创建新 Chart,我们应该使用内置的 helm create 命令。如下所示,它包含一些基本模板和示例:

$ helm create my-app Creating my-app $ tree -d my-app my-app ├── Chart.yaml ├── charts ├── templates │   ├── NOTES.txt │   ├── _helpers.tpl │   ├── deployment.yaml │   ├── ingress.yaml │   └── service.yaml └── values.yaml

在这个名为 my-app 的 Chart 的目录中:

  • Chart.yaml 包含 Chart 的元数据,包括名称、描述信息以及版本等;

  • templates 是 Kubernetes 清单文件目录,用于描述我们希望在集群上拥有的资源,它默认使用 Go Template 语法;

  • values.yaml 常见于大多数 Chart,提供 Chart 的默认配置值。

 有用的功能 

Helm 之所以好用,它的核心竞争力在于模板。Golang 模板的阅读体验一开始其实不太好,但它通过一些有用的功能弥补了这一点。

伪随机

刚开始接触 Helm 的工程师可能都有这样的疑问:“为什么 Helm 连生成随机字符串这么简单的事都不会?”

这个问题的关键在于,如果我们为每次安装(升级)都生成一个随机字符串,那么该字符串每次都会覆盖现有值,这会导致不必要的噪声和其他问题。

为了避免这些,我们可以使用 derivePassword。它基于多个输入源,能为为每次运行生成相同的稳定输出:

sharedKey = "{{ .Values.tls.sharedKey | default (derivePassword 1 "long" (.Release.Time | toString) .Release.Name .Chart.Name ) }}"

生成 TLS 证书

使用加密通道是组件之间通信的标准方法,但是对于测试和开发,我们可能不希望用完整的 PKI 来发布测试证书。对此,一种解决方案是对预先生成的证书进行硬编码,但它既不易维护也不优雅。所以我们可以用 Sprig,它提供开箱即用的自签名证书支持。

注:建议不要在生产环境中使用自签名服务器证书。

以下是我们的 Logging Operator Helm Chart 中的示例:

{{- if and .Values.tls.enabled (not .Values.tls.secretName) }} {{ $ca := genCA "svc-cat-ca" 3650 }} {{ $cn := printf "fluentd.%s.svc.cluster.local" .Release.Namespace }} {{ $server := genSignedCert $cn nil nil 365 $ca }} {{ $client := genSignedCert "" nil nil 365 $ca }} apiVersion: v1 kind: Secret metadata:  name: {{ template "logging-operator.fullname" . }}  labels:    app: {{ template "logging-operator.name" . }}    chart: {{ .Chart.Name }}-{{ .Chart.Version }}    heritage: {{ .Release.Service }}    release: {{ .Release.Name }} data:  caCert: {{ b64enc $ca.Cert }}  clientCert: {{ b64enc $client.Key }}  clientKey: {{ b64enc $client.Cert }}  serverCert: {{ b64enc $server.Cert }}  serverKey: {{ b64enc $server.Key }} {{ end }}

标签、注释和其他属性

无论是用过的还是没用过的,我们应该尽可能记住 Kubernetes 的功能,以此辅助自定义部署。而为了更便捷地做到这一点,我们可以用标签,注释等。你可以用自己的属性,但也要确保终端用户能用他们的属性。运行时覆盖对象(如注释和标签)的最佳方法是将值呈现为 YAML 或 JSON 。

空值示例:

nodeSelector: {} tolerations: [] affinity: {}

Pod 描述文件中的示例模板:

{{- with .Values.nodeSelector }}      nodeSelector: {{ toYaml . | indent 8 }} {{- end }} {{- with .Values.affinity }}      affinity: {{ toYaml . | indent 8 }} {{- end }} {{- with .Values.tolerations }}      tolerations: {{ toYaml . | indent 8 }} {{- end }}

唯一的资源名称

_helpers.yaml 文件中包含着一些有用的功能,通过使用这些功能来构建资源名称,我们能轻松创建可以部署在多个实例中的 Chart。

注:但是,对于不同的单独部署,用不同的资源名称还是更好一些。

 创建自定义的 Chart 

要创建灵活的 Helm Chart,我们需要为用户提供覆盖生成和默认值的机会。这有助于将 Chart 部署到不同的环境,并有助于在 Chart 顶部构建 umbrella Chart。

官方 Chart 仓库中的许多 Chart 都是用于创建更高级应用程序的“构建块”。但 Chart 也可被用于创建大型应用程序的实例。在这种情况下,单个 umbrella Chart 可能有多个子 Chart,每个子 Chart 都是整体的一部分。

示例:用 _configMapOverrideName 值处理自定义配置:

- name: config-volume  configMap:    name: {{ if .Values.configMapOverrideName }}{{ .Release.Name }}-{{ .Values.configMapOverrideName }}{{- else }}{{ template "my-app.fullname" . }}{{- end }}

 创建 umbrella Chart 

要创建由一个或多个其他 Chart 构建的 Chart,请参阅 requirements.yaml 文件中明确定义的从属 Chart 版本。

例如,如果要在应用程序中安装 MySQL Chart,我们应该创建这样一个requirements.yaml

dependencies: - name: mysql  version: 0.7.1  repository: alias:banzaicloud-stable  condition: mysql.enabled

 mysql.enabled 值为 TRUE 时,上述代码会把固定版本的 MySQL Chart 安装到自定义仓库。

你也可以覆盖 values.yaml 文件中的默认值。

mysql:  enabled: true  nameOverride: my-example-db  mysqlDatabase: example

 使用长文件作为配置映射 

有时,我们可能不想用模板,而是希望将长文件用作 Kubernetes configmap。这时我们可以用 Files.Get,把这些文件包含在一个或多个 configmap 清单中。

{{- if .Values.grafana.dashboard.enabled }} apiVersion: v1 kind: ConfigMap metadata:  name: {{ template "logging-operator.fullname" . }}-grafana-dashboard-logging  labels:    pipeline_grafana_dashboard: "1" data:  logging.json: |-2 {{.Files.Get "grafana-dashboards/logging-dashboard_rev1.json"| indent 4}} {{- end }}

注:路径是 Chart 根目录中的相对路径。

设计原则

这一节我们要介绍的不是功能要求,而是设计指南。如果我们不能保证 Helm Chart 的一致和整洁,它们很容易变得既笨拙又复杂。

 值 

值是任何 Helm 部署的主要定制点,它必须易于定制,且易于部署。所以在实践中,我们通常应该遵循以下规则:

  • 用尽可能少的层次结构,避免冗余;

  • 使用层次结构,而不是前缀/后缀;

  • 命名一致。

 用功能切换条件 

深入了解 Helm 功能时,我们会发现有很多东西是捆绑在一起的。一个很好的例子就是用 TLS 证书进行集群内通信,这时我们必须改变几个相辅相成的属性:

service:  tls:    enabled: true  ...

这一小段代码完全改变了以下这些组件的行为:

  • Ingress 的前端、后端 Scheme 和 Probe;

ports: - port: {{ .Values.service.externalPort }}  targetPort: {{ .Values.service.internalPort }}  protocol: TCP {{- if .Values.service.tls  }}  name: "https-{{ .Values.service.name }}" {{- else }}
  • Service Scheme 和 Probe;

type: {{ .Values.service.type }} ports: - port: {{ .Values.service.externalPort }}  targetPort: {{ .Values.service.internalPort }}  protocol: TCP {{- if .Values.service.tls  }}  name: "https-{{ .Values.service.name }}" {{- else }}  name: "{{ .Values.service.name }}" {{ end }}
  • Readiness 和 Liveness Probe;

livenessProbe:  httpGet:    path: {{ .Values.pipelineBasepath }}/api    port: {{ .Values.service.internalPort }}  {{- if .Values.service.tls  }}    scheme: HTTPS  {{ end }}  initialDelaySeconds: 15 readinessProbe:  httpGet:    path: {{ .Values.global.pipelineBasepath }}/api    port: {{ .Values.service.internalPort }}  {{- if .Values.service.tls  }}    scheme: HTTPS  {{ end }}  initialDelaySeconds: 10
  • Mount Secret。

{{- if .Values.service.tls  }}  - name: tls-certificate    mountPath: /tls {{ end }}

 使用 NOTE.txt 

NOTES.txt 的作用是为部署 Chart 的用户提供信息,它也是模板化的,所以我们可以为它们提供一些有用的信息,以帮助它们开始使用已部署的应用程序。通常,我们应该以用户最可能需要的格式输出创建的端点。

下面是允许用户访问已创建服务的示例代码:

POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "prometheus.name" . }},component={{ .Values.pushgateway.name }}" -o jsonpath="{.items[0].metadata.name}") kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 9091

 README 

当我们编写 README 文件的时候,Chart 应该已经创建好了。一篇好的 README 通常包括 Chart 的简要说明、一些示例以及有关安装选项的一些详细信息。

 检查你的 Chart 

到这里,不要忘了检查 Chart 是否存在语法错误,这时检查比部署后再检查容易得多。

$ helm lint my-chart ==> Linting my-chart Lint OK 1 chart(s) linted, no failures

 调试 

最后就是调试。要了解 Helm 渲染模板后会发生什么,我们可以使用 --debug 和 --dry-run 。

$ helm install chart-name --debug --dry-run

 我安装了什么 

要看自己干了什么,获取正在运行的部署使用的值可能会派上用场。

$ helm get values release-name

到这里,文章就结束了。读罢这篇关于 Helm 的短文,希望你能觉得有用、有趣,并愿意亲自动手去试一试。

参考文献

1.https://banzaicloud.com/blog/creating-helm-charts/

2.http://www.10tiao.com/html/357/201808/2247486154/1.html

3.https://www.digitalocean.com/community/tutorials/an-introduction-to-helm-the-package-manager-for-kubernetes



END


推荐阅读:

3 小时入门 Kubernetes,容器编排详细指南(上)

K8S 网络插件(CNI)超过 10Gbit/s 的基准测试结果

KubeCon 直击:etcd 正式成为 CNCF 孵化项目

K8S 1.13 重磅发布|全面解读 20 个重大功能更新

Envoy 成为 CNCF 第三个毕业项目

网易云不同场景 K8S 网络实践方案

KubeCon 中国首秀|全面解读 7 大 Keynote 带你看穿 K8S 新时代

当当网专家详述如何利用 K8S 构建自主可控的 FaaS 平台

深入理解 K8S APIServer 运行时及代码重构


文章已于修改

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存