- 在 Dev 和 QA 中,您可能只需要一个副本。
- 在预生产和生产中,您将拥有更多具有 Pod 自动缩放的副本。
- 每个环境中的入口路由规则都不同。
- 每个环境的配置和机密都不同。
由于每个环境的配置和部署参数发生了变化,您需要为每个环境维护不同的 Nginx 部署文件。或者,您将有一个部署文件,并且需要编写自定义 shell 或 python 脚本来替换基于环境的值。但是,它不是一种可扩展的方法。
Helm 图表是 Kubernetes YAML 清单模板和特定于 helm 的文件的组合。你可以称它为 helm 包。由于 Kubernetes YAML 清单可以模板化,因此您不必维护不同环境的多个 helm 图表。Helm 使用 go 模板引擎来实现模板功能。
您只需要有一个 helm 图表,只需更改一个值文件即可修改每个环境的部署参数。Helm 将负责将这些值应用于模板。我们将在下一节中实际了解有关它的更多信息。
在较高层次上,Helm Chart 降低了复杂性,而 kubernetes 仅使用一个模板就体现了每个环境的冗余。(dev, uat, cug, prod)
Helm 图表结构
为了理解 Helm 图表,我们以 Nginx 部署为例。若要在 Kubernetes 上部署 Nginx,通常需要以下 YAML 文件。
nginx-deployment
├── configmap.yaml
├── deployment.yaml
├── ingress.yaml
└── service.yaml
现在,如果我们为上述 Nginx 部署创建一个 Helm Chart,它将具有以下目录结构。
nginx-chart/
|-- Chart.yaml
|-- charts
|-- templates
| |-- NOTES.txt
| |-- _helpers.tpl
| |-- deployment.yaml
| |-- configmap.yaml
| |-- ingress.yaml
| |-- service.yaml
| `-- tests
| `-- test-connection.yaml
`-- values.yaml
如您所见,部署 YAML 文件是模板目录的一部分(以粗体突出显示),并且有特定于 helm 的文件和文件夹。让我们看一下 helm chart 中的每个文件和目录,并了解它们的重要性。
- **.helmignore:**它用于定义我们不想包含在 helm 图表中的所有文件。它的工作方式与
.gitignore
文件类似。 - **Chart.yaml:**它包含有关 helm chart 的信息,如版本、名称、描述等。
- values.yaml:在此文件中,我们定义 YAML 模板的值。例如,映像名称、副本计数、HPA 值等。正如我们之前所解释的,每个环境中只有文件会更改。此外,您可以动态覆盖这些值,也可以在安装 chart 时使用命令覆盖这些值。
values.yaml``--values``--set
- **charts:**如果我们的主图表对其他图表有一定的依赖性,我们可以在此目录中添加另一个图表的结构。默认情况下,此目录为空。
- **templates:**此目录包含构成应用程序的所有 Kubernetes 清单文件。可以将这些清单文件模板化,以访问 values.yaml 文件中的值。Helm 为 Kubernetes 对象创建了一些默认模板,如 deployment.yaml、service.yaml 等,我们可以直接使用、修改或覆盖我们的文件。
- **templates/NOTES.txt:**这是一个纯文本文件,在成功部署图表后打印出来。
- **templates/_helpers.tpl:**该文件包含多个方法和子模板。这些文件不会呈现给 Kubernetes 对象定义,但在其他图表模板中的任何地方都可以使用。
- **emplates/tests/:**我们可以在图表中定义测试,以验证您的图表在安装时是否按预期工作。
Helm Chart 教程 GitHub 存储库
本 Helm Chart 教程中使用的示例 helm chart 和清单托管在 Helm Chart Github 存储库中。您可以克隆它并使用它来遵循指南。
git clone https://github.com/techiescamp/helm-tutorial.git
从头开始创建 Helm 图表
为了亲身体验 helm chart 的创建,让我们从头开始创建一个 Nginx helm chart。
执行以下命令以创建图表样板。它创建一个具有默认文件和文件夹名称的图表。nginx-chart
helm create nginx-chart
如果检查创建的图表,它将包含以下文件和目录。
nginx-chart
│ ├── Chart.yaml
│ ├── charts
│ ├── templates
│ │ ├── NOTES.txt
│ │ ├── _helpers.tpl
│ │ ├── deployment.yaml
│ │ ├── hpa.yaml
│ │ ├── ingress.yaml
│ │ ├── service.yaml
│ │ ├── serviceaccount.yaml
│ │ └── tests
│ │ └── test-connection.yaml
│ └── values.yaml
cd 进入生成的图表目录。
cd nginx-chart
我们将根据部署要求逐个编辑文件。
Chart.yaml
如上所述,我们将图表的详细信息存档。将 的默认内容替换为以下内容。Chart.yaml``chart.yaml
apiVersion: v2
name: nginx-chart
description: My First Helm Chart
type: application
version: 0.1.0
appVersion: "1.0.0"
maintainers:
- email: contact@devopscube.com
name: devopscube
- apiVersion:这表示图表 API 版本。v2 用于 Helm 3,v1 用于以前的版本。
- **name:**表示图表的名称。
- **description:**表示 helm 图表的描述。
- Type:图表类型可以是“应用程序”或“库”。应用程序图表是您在 Kubernetes 上部署的内容。库图表是可重复使用的图表,可与其他图表一起使用。编程中类似的库概念。
- version:图表版本。
- appVersion:这表示我们应用程序(Nginx)的版本号。
- maintainers**:**有关图表所有者的信息。
每次对应用程序进行更改时,version``appVersion
应该递增。还有一些其他字段,如dependencies,icons 等。
templates
Helm 创建的目录中有多个文件。在我们的例子中,我们将进行简单的 Kubernetes Nginx 部署。templates
从模板目录中删除所有默认文件。
rm -rf templates/*
我们将添加我们的 Nginx YAML 文件并将它们更改为模板,以便更好地理解。
创建一个文件并复制以下内容。deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: "nginx:1.16.0"
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
上面的 YAML 文件,则值是静态的。helm chart 的想法是将 YAML 文件模板化,以便我们可以通过动态地为它们分配值来在多个环境中重用它们。
要对值进行模板化,只需在大括号内添加 object 参数,如下所示。它被称为模板指令,语法特定于 Go 模板
{{ .Object.Parameter }}
首先,让我们了解什么是对象。以下是我们将在此示例中使用的三个对象。
- 发布:每个 helm 图表都将使用发布名称进行部署。如果要使用发布名称或访问模板中与发布相关的动态值,可以使用发布对象。
- 图表:如果要使用 chart.yaml 中提到的任何值,可以使用图表对象。
- 值:values.yaml 文件中的所有参数都可以使用 Values 对象进行访问。
要了解有关支持的对象的更多信息,请查看 Helm 内置对象文档。
下图显示了如何在模板中替换内置对象。
首先,您需要弄清楚哪些值可以更改或要模板化哪些值。我正在选择名称、副本、容器名称、图像和 imagePullPolicy,我在 YAML 文件中以粗体突出显示了它们。
- **name: :**我们每次都需要更改部署名称,因为 Helm 不允许我们安装具有相同名称的版本。因此,我们将使用发布名称模板化部署名称,并随之插值 -nginx。现在,如果我们使用名称 frontend 创建发布,则部署名称将为 frontend-nginx。这样,我们将有保证的唯一名称。
name: {{ .Release.Name }}-nginx
- container name: :对于容器名称,我们将使用 Chart 对象,并使用 chart.yaml 中的图表名称作为容器名称。
{{ .Chart.Name }}
- **Replicas:**我们将从 values.yaml文件中访问副本值。
{{ .Values.replicaCount }}
- image: 在这里,我们在一行中使用多个模板指令,并从 Values 文件中访问映像键下的存储库和标记信息。
"{{ .Values.image.repository }}:{{ .Values.image.tag }}"
同样,您可以在 YAML 文件中模板化所需的值。
这是应用模板后的最终 deployment.yaml
文件。模板化部分以粗体突出显示。将部署文件内容替换为以下内容。
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Release.Name }}-nginx
labels:
app: nginx
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
创建文件并复制以下内容。**service.yaml**
apiVersion: v1
kind: Service
metadata:
name: {{ .Release.Name }}-service
spec:
selector:
app.kubernetes.io/instance: {{ .Release.Name }}
type: {{ .Values.service.type }}
ports:
- protocol: {{ .Values.service.protocol | default "TCP" }}
port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
在协议模板指令中,您可以看到一个管道。它用于将协议的默认值定义为 TCP。因此,这意味着我们不会在 **values.yaml
**文件中定义协议值,或者如果它为空,它将采用 TCP 作为协议的值。( | )
创建一个**configmap.yaml
**,并在其中添加以下内容。在这里,我们将默认的 Nginx index.html 页面替换为自定义 HTML 页面。此外,我们还添加了一个模板指令来替换 HTML 中的环境名称。
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Release.Name }}-index-html-configmap
namespace: default
data:
index.html: |
<html>
<h1>Welcome</h1>
</br>
<h1>Hi! I got deployed in {{ .Values.env.name }} Environment using Helm Chart </h1>
</html
values.yaml
该文件包含我们在模板中使用的模板指令中需要替换的所有值。例如,template 包含一个模板指令,用于从 values.yaml
文件中获取映像存储库、标记和 pullPolicy。如果检查以下 values.yaml
文件,则在映像键下嵌套了 repository、tag 和 pullPolicy 键值对。这就是我们使用 Values.image.repository
的原因values.yaml``deployment.yaml
现在,将默认值 values.yaml
内容替换为以下内容。
replicaCount: 2
image:
repository: nginx
tag: "1.16.0"
pullPolicy: IfNotPresent
service:
name: nginx-service
type: ClusterIP
port: 80
targetPort: 9000
env:
name: dev
现在我们已经准备好了 Nginx helm chart,最终的 helm chart 结构如下所示。
nginx-chart
├── Chart.yaml
├── charts
├── templates
│ ├── configmap.yaml
│ ├── deployment.yaml
│ └── service.yaml
└── values.yaml
验证 Helm Chart
现在,为了确保我们的图表有效并且所有缩进都很好,我们可以运行以下命令。确保您位于图表目录中。
helm lint .
如果您从 nginx-chart 目录外部执行它,请提供 **nginx-chart
**的完整路径
helm lint /path/to/nginx-chart
如果没有错误或问题,它将显示此结果
==> Linting ./nginx
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, 0 chart(s) failed
若要验证模板中的值是否被替换,可以使用以下命令呈现具有值的模板化 YAML 文件。它将生成并显示所有带有替换值的清单文件。
helm template .
我们也可以使用命令来检查。这将假装将图表安装到集群中,如果存在问题,它将显示错误。--dry-run
helm install --dry-run my-release nginx-chart
如果一切正常,您将看到将部署到群集中的清单输出。
部署 Helm Chart
部署图表时,Helm 将从文件中读取图表和配置值,并生成清单文件。然后它会将这些文件发送到 Kubernetes API 服务器,Kubernetes 将在集群中创建请求的资源。values.yaml
现在我们准备安装图表了。
执行以下命令,其中 is release name 和 is the chart name。它将 nginx-chart
安装在默认命名空间中
helm install frontend nginx-chart
您将看到如下所示的输出。
NAME: frontend
LAST DEPLOYED: Tue Dec 13 10:15:56 2022
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
现在,您可以使用以下命令检查版本列表:
helm list
执行kubectl命令,查看部署、服务和Pod。
kubectl get deployment
kubectl get services
kubectl get configmap
kubectl get pods
我们可以看到部署 frontend-nginx、nginx-service
和 pod 已启动并运行,如下所示。
我们讨论了如何使用不同的 **values.yaml
**文件将单个 helm 图表用于多个环境。若要使用外部文件安装 helm 图表,可以将以下命令与值文件的标志和路径一起使用。**values.yaml**``--values
helm install frontend nginx-chart --values env/prod-values.yaml
将 Helm 作为 CI/CD 管道的一部分时,可以编写自定义逻辑,以根据环境传递所需的值文件。
Helm 升级和回滚
现在假设您要修改图表并安装更新版本,我们可以使用以下命令:
helm upgrade frontend nginx-chart
例如,我们将副本从 2 更改为 1。您可以看到修订号为 2,并且只有 1 个 pod 在运行。
现在,如果我们想回滚刚刚完成的更改并再次部署上一个更改,我们可以使用 rollback 命令来执行此操作。
helm rollback frontend
上面的命令会将 helm 版本回滚到上一个版本。
回滚后,我们可以看到 2 个 pod 再次运行。请注意,Helm 将回滚作为新修订版,这就是我们将修订版作为 3 的原因。
如果我们想回滚到特定版本,我们可以像这样输入修订号。