From 274cbfff127bf935e71de69bc3a09bd111253d79 Mon Sep 17 00:00:00 2001 From: mouuii <1730114644@qq.com> Date: Sat, 23 Nov 2024 10:31:24 +0800 Subject: [PATCH] helm --- SUMMARY.md | 7 +- helm-jiao-cheng/01.md | 97 ++- helm-jiao-cheng/02.md | 372 +++++++++++ helm-jiao-cheng/03.md | 288 +++++++++ helm-jiao-cheng/04.md | 356 +++++++++++ helm-jiao-cheng/05.md | 140 +++++ helm-jiao-cheng/06.md | 1400 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2657 insertions(+), 3 deletions(-) create mode 100644 helm-jiao-cheng/02.md create mode 100644 helm-jiao-cheng/03.md create mode 100644 helm-jiao-cheng/04.md create mode 100644 helm-jiao-cheng/05.md create mode 100644 helm-jiao-cheng/06.md diff --git a/SUMMARY.md b/SUMMARY.md index 965c1cf..2bc99a7 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -79,7 +79,12 @@ *** * [helm 教程](helm-jiao-cheng/README.md) - * [01](helm-jiao-cheng/01.md) + * [01-快速入门](helm-jiao-cheng/01.md) + * [02-如何使用](helm-jiao-cheng/02.md) + * [03-制作chart](helm-jiao-cheng/03.md) + * [04-chart学习](helm-jiao-cheng/04.md) + * [05-chart hook](helm-jiao-cheng/05.md) + * [06-chart 指南](helm-jiao-cheng/06.md) ## jenkins 教程 diff --git a/helm-jiao-cheng/01.md b/helm-jiao-cheng/01.md index bec0531..68ce1f4 100644 --- a/helm-jiao-cheng/01.md +++ b/helm-jiao-cheng/01.md @@ -1,3 +1,96 @@ -# 01 +# 1. 概述 -xxxx +**[Helm](https://helm.sh/) 是 Kubernetes 应用程序的包管理器**。它帮助我们为最复杂的 Kubernetes 应用程序创建包、安装、配置、部署和升级。由于 Helm 提供了一种简单且可重复的方法来打包和分发[Kubernetes 应用程序](https://middleware.io/blog/kubernetes-monitoring/),因此可以轻松简化工作负载的[CI/CD 管道](https://middleware.io/blog/what-is-a-ci-cd-pipeline/)。 + +在过去的几年里,Kubernetes 取得了巨大的发展,支持它的生态系统也是如此。近日,Helm 获得了[云原生计算基金会(CNCF)](https://www.cncf.io/)的毕业资格,这表明它在 Kubernetes 用户中的受欢迎程度越来越高。 + +# 2. helm 架构 + +![image](https://github.com/user-attachments/assets/05750704-38cb-4d8d-9eb8-bc38e2c4e3f1) + +Helm 3 相比于 Helm2 已**转向完全仅客户端的架构**,**直接与 Kubernetes API 服务器而不是 Tiller 服务器交互**。这一举措简化了 Helm 的架构,并使其能够利用 Kubernetes 用户集群的安全性。 + +# 3. Helm Chart 是什么 + +Helm 使用 “chart” 来打包应用程序的所有必要资源和配置。 Helm chart 就像在 Kubernetes 上部署任何应用程序的蓝图。 + +它包含运行我们的应用程序所需的所有 Kubernetes 资源 YAML 清单文件以及组织在特定目录结构中的一些与 helm 相关的文件。它使用基于 Go 模板的模板系统从图表中呈现 Kubernetes 清单。 + +简而言之,Helm 有一些预定义的 k8s 模板,它传递我们在文件中定义的值并将资源部署到集群上。 + +![image](https://github.com/user-attachments/assets/121991fc-cd91-4c26-a0e5-fcb09c1ce261) + +# 4.安装 + +下载 Helm 客户端的二进制版本。您可以使用像`homebrew`这样的工具,或者查看[官方发布页面](https://github.com/helm/helm/releases)。有关更多详细信息或其他选项,请参阅[安装指南](https://helm.sh/docs/intro/install/)。 + +# 5.先决条件 + +1. 一个 Kubernetes 集群 +2. 决定将哪些安全配置应用于您的安装(如果有) +3. 安装和配置 Helm。 + +# 6. 初始化 helm chart repository + +准备好 Helm 后,您可以添加图表存储库。检查[Artifact Hub](https://artifacthub.io/packages/search?kind=0)以获得可用的 Helm 图表存储库。 + +```shell +$ helm repo add bitnami https://charts.bitnami.com/bitnami +``` + +安装后,您将能够列出可以安装的 chart: + +```shell +$ helm search repo bitnami +NAME CHART VERSION APP VERSION DESCRIPTION +bitnami/bitnami-common 0.0.9 0.0.9 DEPRECATED Chart with custom templates used in ... +bitnami/airflow 8.0.2 2.0.0 Apache Airflow is a platform to programmaticall... +bitnami/apache 8.2.3 2.4.46 Chart for Apache HTTP Server +bitnami/aspnet-core 1.2.3 3.1.9 ASP.NET Core is an open-source framework create... +# ... and many more +``` + +# 7. 安装示例 chart + +要安装 chart,您可以运行`helm install`命令。 Helm 有多种查找和安装 chart 的方法,但最简单的是使用`bitnami` chart。 + +```shell +$ helm repo update # Make sure we get the latest list of charts +$ helm install bitnami/mysql --generate-name +NAME: mysql-1612624192 +LAST DEPLOYED: Sat Feb 6 16:09:56 2021 +NAMESPACE: default +STATUS: deployed +REVISION: 1 +TEST SUITE: None +NOTES: ... +``` + +在上面的示例中, `bitnami/mysql` chart已发布,我们新版本的名称是`mysql-1612624192` 。 + +通过运行`helm show chart bitnami/mysql`您可以简单了解此 MySQL chart 的功能。或者您可以运行`helm show all bitnami/mysql`来获取有关 chart 的所有信息。 + +每当您安装 chart 时,都会创建一个新版本。因此,一个 chart 可以多次安装到同一个集群中。并且每个都可以独立管理和升级。 + +`helm install`命令是一个非常强大的命令,具有许多功能。要了解更多信息,请查看[Helm 使用指南](https://helm.sh/docs/intro/using_helm/) + +# 8. release + +使用 Helm 可以轻松查看已发布的内容: + +```shell +$ helm list +NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION +mysql-1612624192 default 1 2021-02-06 16:09:56.283059 +0100 CET deployed mysql-8.3.0 8.0.23 +``` + +# 9. 卸载 release + +要卸载版本,请使用`helm uninstall`命令: + +```shell +$ helm uninstall mysql-1612624192 +release "mysql-1612624192" uninstalled +``` + +这将从 Kubernetes 中卸载`mysql-1612624192` ,这将删除与该版本相关的所有资源以及发布历史记录。 \ No newline at end of file diff --git a/helm-jiao-cheng/02.md b/helm-jiao-cheng/02.md new file mode 100644 index 0000000..b2919e0 --- /dev/null +++ b/helm-jiao-cheng/02.md @@ -0,0 +1,372 @@ +本指南介绍了使用 Helm 管理 Kubernetes 集群上的包的基础知识。它假设您已经[安装了](https://helm.sh/docs/intro/install/)Helm 客户端。 + +# 三大概念 + +**Chart** 是一个 Helm 包。它包含在 Kubernetes 集群内运行应用程序、工具或服务所需的所有资源定义。可以将其视为 Kubernetes 中的 Homebrew ,apt 或者 yum。 + +***Repository* ** 是可以收集和共享 charts 的地方。 + +**Release** 是在 Kubernetes 集群中运行的 chart 实例。一个 chart 通常可以多次安装到同一个集群中。每次安装时,都会创建一个新*版本*。比如一个 MySQL chart。如果您希望在集群中运行两个数据库,则可以安装该 chart 两次。每个 chart 都有自己的版本。 + +# Helm search + +• `helm search hub` 从 Artifact Hub(`https://artifacthub.io/`) 中查找并列出 helm charts。Artifact Hub中存放了大量不同的仓库。 + +• `helm search repo` 从你添加(使用 `helm repo add`)到本地 helm 客户端中的仓库中进行查找。该命令基于本地数据进行搜索,无需连接互联网。 + +您可以通过运行`helm search hub`来查找公开可用的 charts: + +```shell +$ helm search hub wordpress +URL CHART VERSION APP VERSION DESCRIPTION +https://hub.helm.sh/charts/bitnami/wordpress 7.6.7 5.2.4 Web publishing platform for building blogs and ... +https://hub.helm.sh/charts/presslabs/wordpress-... v0.6.3 v0.6.3 Presslabs WordPress Operator Helm Chart +https://hub.helm.sh/charts/presslabs/wordpress-... v0.7.1 v0.7.1 A Helm chart for deploying a WordPress site on ... +``` + +上面的内容搜索 Artifact Hub 上的所有`wordpress` charts。 + +在没有过滤的情况下, `helm search hub`会向您显示所有可用的 charts 。 + +`helm search hub` 公开了[artifacthub.io](https://artifacthub.io/)上位置的 URL,但不是实际的 Helm 存储库。 + +`helm search hub --list-repo-url` 公开实际的 Helm 存储库 URL,当您希望添加新存储库时,该 URL 会派上用场: `helm repo add [NAME] [URL]` 。 + +使用`helm search repo` ,您可以在已添加的存储库中找到 chart 的名称: + +```shell +$ helm repo add brigade https://brigadecore.github.io/charts +"brigade" has been added to your repositories +$ helm search repo brigade +NAME CHART VERSION APP VERSION DESCRIPTION +brigade/brigade 1.3.2 v1.2.1 Brigade provides event-driven scripting of Kube... +brigade/brigade-github-app 0.4.1 v0.2.1 The Brigade GitHub App, an advanced gateway for... +brigade/brigade-github-oauth 0.2.0 v0.20.0 The legacy OAuth GitHub Gateway for Brigade +brigade/brigade-k8s-gateway 0.1.0 A Helm chart for Kubernetes +brigade/brigade-project 1.0.0 v1.0.0 Create a Brigade project +brigade/kashti 0.4.0 v0.4.0 A Helm chart for Kubernetes +``` + +搜索是查找可用软件包的好方法。找到要安装的包后,可以使用`helm install`来安装它。 + +# Helm install + +要安装新包,请使用`helm install`命令。最简单的是,它需要两个参数:您选择的版本名称和您要安装的 chart 的名称。 + +```shell +$ helm install happy-panda bitnami/wordpress +NAME: happy-panda +LAST DEPLOYED: Tue Jan 26 10:27:17 2021 +NAMESPACE: default +STATUS: deployed +REVISION: 1 +NOTES: +** Please be patient while the chart is being deployed ** + +Your WordPress site can be accessed through the following DNS name from within your cluster: + + happy-panda-wordpress.default.svc.cluster.local (port 80) + +To access your WordPress site from outside the cluster follow the steps below: + +1. Get the WordPress URL by running these commands: + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace default -w happy-panda-wordpress' + + export SERVICE_IP=$(kubectl get svc --namespace default happy-panda-wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}") + echo "WordPress URL: http://$SERVICE_IP/" + echo "WordPress Admin URL: http://$SERVICE_IP/admin" + +2. Open a browser and access WordPress using the obtained URL. + +3. Login with the following credentials below to see your blog: + + echo Username: user + echo Password: $(kubectl get secret --namespace default happy-panda-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode) +``` + +现在`wordpress` chart 已安装。请注意,安装 chart 会创建一个新的*发布*对象。上面的版本被命名为`happy-panda` 。 (如果您希望 Helm 为您生成名称,请省略版本名称并使用`--generate-name` 。 + +要跟踪版本的状态或重新读取配置信息,您可以使用`helm status` : + +```shell +$ helm status happy-panda +NAME: happy-panda +LAST DEPLOYED: Tue Jan 26 10:27:17 2021 +NAMESPACE: default +STATUS: deployed +REVISION: 1 +NOTES: +** Please be patient while the chart is being deployed ** + +Your WordPress site can be accessed through the following DNS name from within your cluster: + + happy-panda-wordpress.default.svc.cluster.local (port 80) + +To access your WordPress site from outside the cluster follow the steps below: + +1. Get the WordPress URL by running these commands: + + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + Watch the status with: 'kubectl get svc --namespace default -w happy-panda-wordpress' + + export SERVICE_IP=$(kubectl get svc --namespace default happy-panda-wordpress --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}") + echo "WordPress URL: http://$SERVICE_IP/" + echo "WordPress Admin URL: http://$SERVICE_IP/admin" + +2. Open a browser and access WordPress using the obtained URL. + +3. Login with the following credentials below to see your blog: + + echo Username: user + echo Password: $(kubectl get secret --namespace default happy-panda-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode) +``` + +## 安装前自定义 chart + +我们这里的安装方式将仅使用此 chart 的默认配置选项。很多时候,您会想要自定义 chart 以使用您喜欢的配置。 + +要查看 chart 上可配置的选项,请使用`helm show values` : + +```shell +$ helm show values bitnami/wordpress +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry and imagePullSecrets +## +# global: +# imageRegistry: myRegistryName +# imagePullSecrets: +# - myRegistryKeySecretName +# storageClass: myStorageClass + +## Bitnami WordPress image version +## ref: https://hub.docker.com/r/bitnami/wordpress/tags/ +## +image: + registry: docker.io + repository: bitnami/wordpress + tag: 5.6.0-debian-10-r35 + [..] +``` + +然后,您可以在 YAML 格式的文件中覆盖任何这些设置,然后在安装过程中传递该文件。 + +```shell +$ echo '{mariadb.auth.database: user0db, mariadb.auth.username: user0}' > values.yaml +$ helm install -f values.yaml bitnami/wordpress --generate-name +``` + +安装过程中有两种传递配置数据的方法: + +- `--values` (或`-f` ):指定具有覆盖的 YAML 文件。可以多次指定,最右边的文件优先 + +- `--set` :在命令行上指定覆盖。 + +如果同时使用两者, `--set`值将合并到具有更高优先级的`--values`中。使用`--set`指定的覆盖将保留在 Secret 中。可以使用以下命令查看给定版本的已`--set`值 `helm get values ` 。可以通过运行`helm upgrade`并指定`--reset-values`来清除已`--set`值。 + +## 更多安装方式 + +`helm install`命令可以从多个源进行安装: + +- chart 存储库(如我们上面所见) +- 本地 chart 存档( `helm install foo foo-0.1.1.tgz` ) +- 解压后的 chart 目录( `helm install foo path/to/foo` ) +- 完整的网址( `helm install foo https://example.com/charts/foo-1.2.3.tgz` ) + +# helm upgrade 和 helm rollback + +当发布新版本的 chart 时,或者当您想要更改版本的配置时,可以使用`helm upgrade`命令。 + +升级采用现有版本并根据您提供的信息进行升级。由于 Kubernetes chart 可能庞大且复杂,Helm 尝试执行侵入性最小的升级。它只会更新自上次版本以来发生更改的内容。 + +```shell +$ helm upgrade -f panda.yaml happy-panda bitnami/wordpress (--version 不填默认最新) +``` + +在上述情况下, `happy-panda`版本使用相同的 chart 进行了升级,但使用了新的 YAML 文件: + +```shell +mariadb.auth.username: user1 +``` + +我们可以使用`helm get values`来查看新设置是否生效。 + +```shell +$ helm get values happy-panda +mariadb: + auth: + username: user1 +``` + +如果在发布过程中出现某些情况未按计划进行,则可以使用以下命令轻松回滚到以前的版本 `helm rollback [RELEASE] [REVISION]` 。 + +```shell +$ helm rollback happy-panda 1 +``` + +上面的内容将我们的 happy-panda 回滚到其第一个发行版本。发布版本是增量修订版。每次发生安装、升级或回滚时,修订号都会增加 1。第一个修订号始终为 1。我们可以使用`helm history [RELEASE]`查看某个版本的修订号。 + +# helm uninstall + +当需要从集群中卸载版本时,请使用`helm uninstall`命令: + +```shell +$ helm uninstall happy-panda +``` + +这将从集群中删除该版本。您可以使用`helm list`命令查看当前部署的所有版本: + +```shell +$ helm list +NAME VERSION UPDATED STATUS CHART +inky-cat 1 Wed Sep 28 12:59:46 2016 DEPLOYED alpine-0.1.0 +``` + +# helm repo + +您可以使用`helm repo list`查看配置了哪些存储库: + +```shell +$ helm repo list +NAME URL +stable https://charts.helm.sh/stable +mumoshu https://mumoshu.github.io/charts +``` + +可以使用`helm repo add [NAME] [URL]`添加新存储库: + +```shell +$ helm repo add dev https://example.com/dev-charts +``` + +由于chart 存储库经常更改,因此您可以随时通过运行`helm repo update`来确保您的 Helm 客户端是最新的。 + +可以使用`helm repo remove`删除存储库。 + +# 创建您自己的chart + +[chart开发指南](https://helm.sh/docs/topics/charts/)解释了如何开发您自己的chart。但您可以使用`helm create`命令快速入门: + +现在`./deis-workflow`中有一个chart。您可以编辑它并创建您自己的 templates + +当需要打包chart进行分发时,您可以运行`helm package`命令: + +```shell +$ helm package deis-workflow +deis-workflow-0.1.0.tgz +``` + +现在可以通过`helm install`轻松安装该chart: + +```shell +$ helm install deis-workflow ./deis-workflow-0.1.0.tgz +... +``` + +# 上传 chart 到 repo 库 + +和镜像推送差不多,你可以使用公有仓库或者自建仓库,下面以公有仓库百度云为例: + +```shell +helm repo add –username ${username} --password ${password} ${myrepo} https://registry.baidubce.com/chartrepo/{project} +helm push mychart ${myrepo} +``` + + +# 备忘录 + +## chart 管理 + +```bash +helm create # Creates a chart directory along with the common files and directories used in a chart. +helm package # Packages a chart into a versioned chart archive file. +helm lint # Run tests to examine a chart and identify possible issues: +helm show all # Inspect a chart and list its contents: +helm show values # Displays the contents of the values.yaml file +helm pull # Download/pull chart +helm pull --untar=true # If set to true, will untar the chart after downloading it +helm pull --verify # Verify the package before using it +helm pull --version # Default-latest is used, specify a version constraint for the chart version to use +helm dependency list # Display a list of a chart’s dependencies: +``` + +## 安装和卸载 app + +```bash +helm install # Install the chart with a name +helm install --namespace # Install the chart in a specific namespace +helm install --set key1=val1,key2=val2 # Set values on the command line (can specify multiple or separate values with commas) +helm install --values # Install the chart with your specified values +helm install --dry-run --debug # Run a test installation to validate chart (p) +helm install --verify # Verify the package before using it +helm install --dependency-update # update dependencies if they are missing before installing the chart +helm uninstall # Uninstall a release +``` + +## 执行应用程序升级和回滚 + +```bash +helm upgrade # Upgrade a release +helm upgrade --atomic # If set, upgrade process rolls back changes made in case of failed upgrade. +helm upgrade --dependency-update # update dependencies if they are missing before installing the chart +helm upgrade --version # specify a version constraint for the chart version to use +helm upgrade --values # specify values in a YAML file or a URL (can specify multiple) +helm upgrade --set key1=val1,key2=val2 # Set values on the command line (can specify multiple or separate valuese) +helm upgrade --force # Force resource updates through a replacement strategy +helm rollback # Roll back a release to a specific revision +helm rollback --cleanup-on-fail # Allow deletion of new resources created in this rollback when rollback fails +``` + +## 列出、添加、删除和更新存储库 + +```bash +helm repo add # Add a repository from the internet: +helm repo list # List added chart repositories +helm repo update # Update information of available charts locally from chart repositories +helm repo remove # Remove one or more chart repositories +helm repo index # Read the current directory and generate an index file based on the charts found. +helm repo index --merge # Merge the generated index with an existing index file +helm search repo # Search repositories for a keyword in charts +helm search hub # Search for charts in the Artifact Hub or your own hub instance +``` + +## 发布查看 helm + +```bash +helm list # Lists all of the releases for a specified namespace, uses current namespace context if namespace not specified +helm list --all # Show all releases without any filter applied, can use -a +helm list --all-namespaces # List releases across all namespaces, we can use -A +helm list -l key1=value1,key2=value2 # Selector (label query) to filter on, supports '=', '==', and '!=' +helm list --date # Sort by release date +helm list --deployed # Show deployed releases. If no other is specified, this will be automatically enabled +helm list --pending # Show pending releases +helm list --failed # Show failed releases +helm list --uninstalled # Show uninstalled releases (if 'helm uninstall --keep-history' was used) +helm list --superseded # Show superseded releases +helm list -o yaml # Prints the output in the specified format. Allowed values: table, json, yaml (default table) +helm status # This command shows the status of a named release. +helm status --revision # if set, display the status of the named release with revision +helm history # Historical revisions for a given release. +helm env # Env prints out all the environment information in use by Helm. +``` + +## 下载发布信息 + +```bash +helm get all # A human readable collection of information about the notes, hooks, supplied values, and generated manifest file of the given release. +helm get hooks # This command downloads hooks for a given release. Hooks are formatted in YAML and separated by the YAML '---\n' separator. +helm get manifest # A manifest is a YAML-encoded representation of the Kubernetes resources that were generated from this release's chart(s). If a chart is dependent on other charts, those resources will also be included in the manifest. +helm get notes # Shows notes provided by the chart of a named release. +helm get values # Downloads a values file for a given release. use -o to format output +``` + +## 插件管理 + +```bash +helm plugin install # Install plugins +helm plugin list # View a list of all installed plugins +helm plugin update # Update plugins +helm plugin uninstall # Uninstall a plugin +``` \ No newline at end of file diff --git a/helm-jiao-cheng/03.md b/helm-jiao-cheng/03.md new file mode 100644 index 0000000..c4937c2 --- /dev/null +++ b/helm-jiao-cheng/03.md @@ -0,0 +1,288 @@ +# 如何创建 Helm chart + +使用 Helm CLI 生成 charts 目录。输入以下命令创建新 chart: + +```shell +helm create phoenixnap +``` + +![image](https://github.com/user-attachments/assets/de0a74cc-0a35-4f75-945b-4fee6882a65b) + +使用 ls 命令列出文件结构: + +![image](https://github.com/user-attachments/assets/16dbcf13-0a6d-4fea-ad4a-5b2a9ad3e176) + +Helm chart 目录包含以下内容: + +- ***charts*** - 存储相关 charts 的目录 +- ***templates*** - 配置文件的目录 +- ***Chart.yaml*** - 包含 charts 元数据的文件 +- ***values.yaml*** - 包含默认参数值的文件 + +# 如何配置 Helm Chart + +配置 Helm Chart 涉及自定义参数,例如**镜像拉取策略**、**名称覆盖**、**服务帐户**和**服务类型**。请按照以下步骤了解如何在*values.yaml*文件中编辑这些参数。 + +## 配置镜像拉取策略 + +镜像拉取策略决定如何从注册表中拉取容器镜像。默认策略值为**`IfNotPresent`** ,这意味着 Kubernetes 仅当系统上尚不存在映像时才拉取该映像,下面我们尝试将策略改变为 Always: + +1. 打开*value.yaml*文件: +2. 修改 image.pullPolicy 为 Always + +![image](https://github.com/user-attachments/assets/cad336eb-39ed-4a60-8cf4-ee986f91f513) + +![image](https://github.com/user-attachments/assets/a40229ab-01e9-4774-97eb-a0ea32a88787) + +## chart 名称覆盖 + +要覆盖*value.yaml*文件中的chart名称,请将值添加到 *nameOverride *和 *fullnameOverride* 字段。以下示例添加 *phoenix-app* 作为 *nameOverride* 值,并将*phoenix-chart*n 添加为 *fullnameOverride*。 + +![image](https://github.com/user-attachments/assets/b4622cdc-0d0c-49b9-97e3-becbbe749e83) + +## 指定 service account名称 + +Helm chart 的 service account 名称是在运行集群时生成的。但是,最好手动设置它并确保应用程序直接与chart 中的受控用户关联。 + +![image](https://github.com/user-attachments/assets/69917499-7551-4591-b7c9-e7b9a5412fab) + +## 更改网络服务类型 + +根据集群的不同,部署可能需要不同的网络服务类型。例如,使用[Minikube](https://phoenixnap.com/kb/install-minikube-on-ubuntu)进行测试时,推荐的网络服务类型为*NodePort* 。 + +要更改网络服务类型,请找到*服务*部分并更改*类型*字段中的值。下面的示例显示了设置为新服务类型的*NodePort* 。 + +![image](https://github.com/user-attachments/assets/8e8a441a-e67a-43bd-b54c-6d57aa503d67) + +# 如何在 Kubernetes 上部署新的 Helm Chart + +配置*values.yaml*文件后,使用[Helm命令](https://phoenixnap.com/kb/helm-commands-cheat-sheet)部署应用程序。继续执行以下步骤来完成此操作。 + +## 第 1 步:安装 Helm Chart + +```shell +helm install phoenix-chart phoenixnap/ --values phoenixnap/values.yaml +``` + +![image](https://github.com/user-attachments/assets/bdee469a-43ed-4671-9df2-e8e2b80a56d3) + +### 步骤2:导出节点端口和IP地址 + +```shell +export NODE_PORT=$(kubectl get --namespace default -o jsonpath="{.spec.ports[0].nodePort}" services phoenix-chart) +export NODE_IP=$(kubectl get nodes --namespace default -o jsonpath="{.items[0].status.addresses[0].address}") +``` + +### 步骤3:查看已部署的应用程序 + +```shell +echo http://$NODE_IP:$NODE_PORT +``` + +![image](https://github.com/user-attachments/assets/4611063d-9686-4e57-b315-6711eb7688e4) + +输出显示已部署应用程序的完整地址,复制地址并将其粘贴到网络浏览器中。出现应用程序屏幕。 + +![image](https://github.com/user-attachments/assets/87e45dfc-e4e1-474d-826f-6a72a5665b4d) + +# 从头开始创建(选读) + +## templates + +你也可以不仅仅只是修改,你可以重新创建这个样例 + +```shell +rm -rf templates/* +``` + +创建`deployment.yaml`文件并复制以下内容。 + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: release-name-nginx + labels: + app: nginx +spec: + replicas: 1 + selector: + matchLabels: + app: nginx + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx-chart + image: "nginx:1.16.0" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 80 + protocol: TCP + volumeMounts: + - name: nginx-index-file + mountPath: /usr/share/nginx/html/ + volumes: + - name: nginx-index-file + configMap: + name: index-html-configmap +``` + +如果您看到上面的 YAML 文件,则这些值是静态的。 Helm Chart 的想法是对 YAML 文件进行模板化,以便我们可以通过动态地为它们分配值**来在多个环境中重用它们**。 + +要模板化一个值,您所需要做的就是在大括号内添加**对象参数**,如下所示。它称为**模板指令**,语法特定于**Go 模板** + +![image](https://github.com/user-attachments/assets/e3cccb92-3b55-4d1c-bb90-6625e2bcabc3) + +首先,您需要弄清楚哪些值可以改变或者您想要模板化哪些值。我正在选择**name** 、 **replicas 、容器名称、image、** **imagePullPolicy**和**configMap Name** ,我在 YAML 文件中以粗体突出显示了这些名称。 + +- name:`{{ .Release.Name }}-nginx` :我们每次都需要更改部署名称,因为 Helm 不允许我们安装同名的版本。因此,我们将使用版本名称模板化部署名称,并随之插入**-nginx** 。现在,如果我们使用名称**frontend**创建一个版本,则部署名称将为**frontend-nginx** 。这样,我们就能保证名称的唯一性。 +- container name :`{{ .Chart.Name }}` :对于容器名称,我们将使用 Chart 对象并使用**Chart.yaml**中的chart名称作为容器名称。 +- replicas :` {{ .Values.replicaCount }}`我们将从**values.yaml**文件中访问副本值。 +- image: **`"{{ .Values.image.repository }}:{{ .Values.image.tag }}"` 在这里,我们在一行中使用多个模板指令,并从 Values 文件中访问图像键下的存储库和标签信息。** +- configmap name: `{{ .Release.Name }}-index-html-configmap.` 这里我们将发布名称添加到配置映射中。 + +这是应用模板后的最终**`deployment.yaml`**文件。模板化部分以粗体突出显示。将部署文件内容替换为以下内容。 + +```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 + volumeMounts: + - name: nginx-index-file + mountPath: /usr/share/nginx/html/ + volumes: + - name: nginx-index-file + configMap: + name: {{ .Release.Name }}-index-html-configmap +``` + +```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 中的环境名称。 + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-index-html-configmap + namespace: default +data: + index.html: | + +

Welcome

+
+

Hi! I got deployed in {{ .Values.env.name }} Environment using Helm Chart

+ Linting ./nginx +[INFO] Chart.yaml: icon is recommended + +1 chart(s) linted, 0 chart(s) failed +``` + +要验证模板中的值是否被替换,您可以使用以下命令呈现带有值的模板化 YAML 文件。它将生成并显示带有替换值的所有清单文件。 + +```shell +helm template . +``` + +我们还可以使用`--dry-run`命令来检查。这将假装将chart安装到集群中,如果出现问题,它将显示错误。 + +```shell +helm install --dry-run my-release nginx-chart +``` + +xxxxxxxxxx helm plugin install     # Install pluginshelm plugin list                    # View a list of all installed pluginshelm plugin update         # Update pluginshelm plugin uninstall      # Uninstall a pluginbash \ No newline at end of file diff --git a/helm-jiao-cheng/04.md b/helm-jiao-cheng/04.md new file mode 100644 index 0000000..5b317ef --- /dev/null +++ b/helm-jiao-cheng/04.md @@ -0,0 +1,356 @@ +Helm使用的包格式称为 *chart*。 chart就是一个描述Kubernetes相关资源的文件集合。单个chart可以用来部署一些某些复杂的HTTP服务器以及web全栈应用、数据库、缓存等等。 + +如果你想下载和查看一个发布的chart,但不安装它,你可以用这个命令: `helm pull chartrepo/chartname`。 + +本文档解释说明了chart格式,并提供了用Helm构建chart的基本指导。 + +# Chart 文件结构 + +chart 是一组文件的集合。目录名称就是chart名称(没有版本信息)。因而描述WordPress的chart可以存储在`wordpress/`目录中。 + +在这个目录中,Helm 期望可以匹配以下结构: + +```shell +wordpress/ + Chart.yaml # 包含了chart信息的YAML文件 + LICENSE # 可选: 包含chart许可证的纯文本文件 + README.md # 可选: 可读的README文件 + values.yaml # chart 默认的配置值 + values.schema.json # 可选: 一个使用JSON结构的values.yaml文件 + charts/ # 包含chart依赖的其他chart + crds/ # 自定义资源的定义 + templates/ # 模板目录, 当和values 结合时,可生成有效的Kubernetes manifest文件 + templates/NOTES.txt # 可选: 包含简要使用说明的纯文本文件 +``` + +Helm保留使用 `charts/`,`crds/`, `templates/`目录,以及列举出的文件名。其他文件保持原样。 + +# Chart.yaml 文件 + +`Chart.yaml`文件是chart必需的。包含了以下字段: + +```yaml +apiVersion: chart API 版本 (必需) +name: chart名称 (必需) +version: 语义化2 版本(必需) +kubeVersion: 兼容Kubernetes版本的语义化版本(可选) +description: 一句话对这个项目的描述(可选) +type: chart类型 (可选) +keywords: + - 关于项目的一组关键字(可选) +home: 项目home页面的URL (可选) +sources: + - 项目源码的URL列表(可选) +dependencies: # chart 必要条件列表 (可选) + - name: chart名称 (nginx) + version: chart版本 ("1.2.3") + repository: (可选)仓库URL ("https://example.com/charts") 或别名 ("@repo-name") + condition: (可选) 解析为布尔值的yaml路径,用于启用/禁用chart (e.g. subchart1.enabled ) + tags: # (可选) + - 用于一次启用/禁用 一组chart的tag + import-values: # (可选) + - ImportValue 保存源值到导入父键的映射。每项可以是字符串或者一对子/父列表项 + alias: (可选) chart中使用的别名。当你要多次添加相同的chart时会很有用 +maintainers: # (可选) + - name: 维护者名字 (每个维护者都需要) + email: 维护者邮箱 (每个维护者可选) + url: 维护者URL (每个维护者可选) +icon: 用做icon的SVG或PNG图片URL (可选) +appVersion: 包含的应用版本(可选)。不需要是语义化,建议使用引号 +deprecated: 不被推荐的chart (可选,布尔值) +annotations: + example: 按名称输入的批注列表 (可选). +``` + +## `appVersion` 字段 + +如果你使用 helm 3,`apiVersion` 字段应该是 `v2`。 + +## `kubeVersion` 字段 + +可选的 `kubeVersion` 字段可以在支持的Kubernetes版本上定义语义化版本约束,Helm 在安装chart时会验证这个版本约束, 并在集群运行不支持的Kubernetes版本时显示失败。 + +```shell +\>= 1.13.0 < 1.15.0 +\>= 1.13.0 < 1.14.0 || >= 1.14.1 < 1.15.0 +``` + +### Chart Types + +`type`字段定义了chart的类型。有两种类型: `application` 和 `library`。 应用是默认类型,是可以完全操作的标准chart。 [库类型 chart](http://helm.sh/zh/docs/topics/library_charts) 提供针对chart构建的实用程序和功能。 库类型chart与应用类型chart不同,因为它不能安装,通常不包含任何资源对象。 + +## Chart dependency + +Helm 中,chart可能会依赖其他任意个chart。 这些依赖可以使用`Chart.yaml`文件中的`dependencies` 字段动态链接,或者被带入到`charts/` 目录并手动配置。 + +当前chart依赖的其他chart会在`dependencies`字段定义为一个列表。 + +```yaml +dependencies: + - name: apache + version: 1.2.3 + repository: https://example.com/charts + - name: mysql + version: 3.2.1 + repository: https://another.example.com/charts +``` + +- `name`字段是你需要的chart的名称 +- `version`字段是你需要的chart的版本 +- `repository`字段是chart仓库的完整URL。注意你必须使用`helm repo add`在本地添加仓库 + +一旦你定义好了依赖,运行 `helm dependency update` 就会使用你的依赖文件下载所有你指定的chart到你的`charts/`目录。 + +```console +$ helm dep up foochart +Hang tight while we grab the latest from your chart repositories... +...Successfully got an update from the "local" chart repository +...Successfully got an update from the "stable" chart repository +...Successfully got an update from the "example" chart repository +...Successfully got an update from the "another" chart repository +Update Complete. Happy Helming! +Saving 2 charts +Downloading apache from repo https://example.com/charts +Downloading mysql from repo https://another.example.com/charts +``` + +当 `helm dependency update` 拉取chart时,会在`charts/`目录中形成一个chart包。因此对于上面的示例,会在chart目录中期望看到以下文件: + +```text +charts/ + apache-1.2.3.tgz + mysql-3.2.1.tgz +``` + +## Templates and Values + +所有模板文件存储在chart的 `templates/` 文件夹。 当Helm渲染chart时,它会通过模板引擎遍历目录中的每个文件。 + +模板的Value通过两种方式提供: + +- Chart开发者可以在chart中提供一个命名为 `values.yaml` 的文件。这个文件包含了默认值。 +- Chart用户可以提供一个包含了value的YAML文件。可以在命令行使用 `helm install`命令时提供。 + +当用户提供自定义value时,这些value会覆盖chart的`values.yaml`文件中value。 + +```shell +apiVersion: v1 +kind: ReplicationController +metadata: + name: deis-database + namespace: deis + labels: + app.kubernetes.io/managed-by: deis +spec: + replicas: 1 + selector: + app.kubernetes.io/name: deis-database + template: + metadata: + labels: + app.kubernetes.io/name: deis-database + spec: + serviceAccount: deis-database + containers: + - name: deis-database + image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }} + imagePullPolicy: {{ .Values.pullPolicy }} + ports: + - containerPort: 5432 + env: + - name: DATABASE_STORAGE + value: {{ default "minio" .Values.storage }} +``` + +上面的例子是一个Kubernetes副本控制器的模板。可以使用下面四种模板值(一般被定义在`values.yaml`文件): + +- `imageRegistry`: Docker镜像的源注册表 +- `dockerTag`: Docker镜像的tag +- `pullPolicy`: Kubernetes的拉取策略 +- `storage`: 后台存储,默认设置为`"minio"` + +### 预定义的Values + +Values通过模板中`.Values`对象可访问的`values.yaml`文件(或者通过 `--set` 参数)提供, 但可以模板中访问其他预定义的数据片段。 + +以下值是预定义的,对每个模板都有效,并且可以被覆盖。和所有值一样,名称 *区分大小写*。 + +- `Release.Name`: 版本名称(非chart的) +- `Release.Namespace`: 发布的chart版本的命名空间 +- `Release.Service`: 组织版本的服务 +- `Release.IsUpgrade`: 如果当前操作是升级或回滚,设置为true +- `Release.IsInstall`: 如果当前操作是安装,设置为true +- `Chart`: `Chart.yaml`的内容。因此,chart的版本可以从 `Chart.Version` 获得, 并且维护者在`Chart.Maintainers`里。 +- `Files`: chart中的包含了非特殊文件的类图对象。这将不允许您访问模板, 但是可以访问现有的其他文件(除非被`.helmignore`排除在外)。 使用`{{ index .Files "file.name" }}`可以访问文件或者使用`{{.Files.Get name }}`功能。 您也可以使用`{{ .Files.GetBytes }}`作为`[]byte`访问文件内容。 +- `Capabilities`: 包含了Kubernetes版本信息的类图对象。(`{{ .Capabilities.KubeVersion }}`) 和支持的Kubernetes API 版本(`{{ .Capabilities.APIVersions.Has "batch/v1" }}`) + +### Values文件 + +考虑到前面部分的模板,`values.yaml`文件提供的必要值如下: + +```yaml +imageRegistry: "quay.io/deis" +dockerTag: "latest" +pullPolicy: "Always" +storage: "s3" +``` + +values文件被定义为YAML格式。chart会包含一个默认的`values.yaml`文件。 Helm安装命令允许用户使用附加的YAML values覆盖这个values: + +```shell +$ helm install --generate-name --values=myvals.yaml wordpress +``` + +以这种方式传递值时,它们会合并到默认的values文件中。比如,`myvals.yaml`文件如下: + +```shell +storage: "gcs" +``` + +当在chart中这个值被合并到`values.yaml`文件中时,生成的内容是这样: + +```yaml +imageRegistry: "quay.io/deis" +dockerTag: "latest" +pullPolicy: "Always" +storage: "gcs" +``` + +注意只有最后一个字段会覆盖。 + +**注意:** chart包含的默认values文件 *必须* 被命名为`values.yaml`。不过在命令行指定的文件可以是其他名称。 + +**注意:** 如果`helm install`或`helm upgrade`使用了`--set`参数,这些值在客户端会被简单地转换为YAML。 + +**注意:** 如果values 文件存在任何必需的条目,它们会在chart模板中使用 ['required' 函数](https://helm.sh/zh/docs/howto/charts_tips_and_tricks) 声明为必需的。 + +然后使用模板中的`.Values`对象就可以任意访问这些值了: + +```yaml +apiVersion: v1 +kind: ReplicationController +metadata: + name: deis-database + namespace: deis + labels: + app.kubernetes.io/managed-by: deis +spec: + replicas: 1 + selector: + app.kubernetes.io/name: deis-database + template: + metadata: + labels: + app.kubernetes.io/name: deis-database + spec: + serviceAccount: deis-database + containers: + - name: deis-database + image: {{ .Values.imageRegistry }}/postgres:{{ .Values.dockerTag }} + imagePullPolicy: {{ .Values.pullPolicy }} + ports: + - containerPort: 5432 + env: + - name: DATABASE_STORAGE + value: {{ default "minio" .Values.storage }} +``` + +Values文件可以声明顶级chart的值,以及`charts/`目录中包含的其他任意chart。 或者换个说法,values文件可以为chart及其任何依赖项提供值。比如,上面示范的WordPress chart同时有 `mysql` 和 `apache` 作为依赖。values文件可以为以下所有这些组件提供依赖: + +```yaml +title: "My WordPress Site" # Sent to the WordPress template + +mysql: + max_connections: 100 # Sent to MySQL + password: "secret" + +apache: + port: 8080 # Passed to Apache +``` + +更高阶的chart可以访问下面定义的所有变量。因此WordPress chart可以用`.Values.mysql.password`访问MySQL密码。 但是低阶的chart不能访问父级chart,所以MySQL无法访问`title`属性。同样也无法访问`apache.port`。 + +Values 被限制在命名空间中,但是命名空间被删减了。因此对于WordPress chart, 它可以用`.Values.mysql.password`访问MySQL的密码字段。但是对于MySQL chart,值的范围被缩减了且命名空间前缀被移除了, 因此它把密码字段简单地看作`.Values.password`。 + +#### 全局Values + +从2.0.0-Alpha.2开始,Helm 支持特殊的"global"值。设想一下前面的示例中的修改版本: + +```yaml +title: "My WordPress Site" # Sent to the WordPress template + +global: + app: MyWordPress + +mysql: + max_connections: 100 # Sent to MySQL + password: "secret" + +apache: + port: 8080 # Passed to Apache +``` + +上面添加了`global`部分和一个值`app: MyWordPress`。这个值以`.Values.global.app`在 *所有* chart中有效。 + +比如,`mysql`模板可以以`{{.Values.global.app}}`访问`app`,同样`apache`chart也可以访问。 实际上,上面的values文件会重新生成为这样: + +```yaml +title: "My WordPress Site" # Sent to the WordPress template + +global: + app: MyWordPress + +mysql: + global: + app: MyWordPress + max_connections: 100 # Sent to MySQL + password: "secret" + +apache: + global: + app: MyWordPress + port: 8080 # Passed to Apache +``` + +这提供了一种和所有的子chart共享顶级变量的方式,这在类似label设置`metadata`属性时会很有用。 + +如果子chart声明了一个全局变量,那这个变量会 *向下* 传递(到子chart的子chart),但不会 *向上* 传递到父级chart。 子chart无法影响父chart的值。 + +并且,父chart的全局变量优先于子chart中的全局变量。 + + + +## 使用Helm管理Chart + +`helm`工具有一些命令用来处理chart。 + +它可以为您创建一个新chart: + +```console +$ helm create mychart +Created mychart/ +``` + +编辑了chart之后,`helm`能为您把它打包成一个chart存档: + +```console +$ helm package mychart +Archived mychart-0.1.-.tgz +``` + +您也可以使用`helm` 帮您找到chart的格式或信息的问题: + +```console +$ helm lint mychart +No issues found +``` + +## Chart仓库 + +*chart仓库* 是一个HTTP服务器,包含了一个或多个打包的chart。当`helm`用来管理本地chart目录时, 共享chart时,首选的机制就是使用chart仓库。 + +任何可以服务于YAML文件和tar文件并可以响应GET请求的HTTP服务器都可以用做仓库服务器。 Helm 团队已经测试了一些服务器,包括激活websit模组的Google Cloud 存储,以及使用website的S3。 + +仓库的主要特征存在一个名为 `index.yaml` 的特殊文件,文件中包含仓库提供的包的完整列表, 以及允许检索和验证这些包的元数据。 + +在客户端,仓库使用`helm repo`命令管理。然而,Helm不提供上传chart到远程仓库的工具。 这是因为这样做会给执行服务器增加大量的必要条件,也就增加了设置仓库的障碍。 \ No newline at end of file diff --git a/helm-jiao-cheng/05.md b/helm-jiao-cheng/05.md new file mode 100644 index 0000000..f95dbc2 --- /dev/null +++ b/helm-jiao-cheng/05.md @@ -0,0 +1,140 @@ +Helm 提供了一个 _hook_ 机制允许chart开发者在发布生命周期的某些点进行干预。比如你可以使用hook用于: + +- 安装时在加载其他chart之前加载配置映射或密钥 +- 安装新chart之前执行备份数据库的任务,然后在升级之后执行第二个任务用于存储数据。 +- 在删除发布之前执行一个任务以便在删除服务之前退出滚动。 + +钩子的工作方式与常规模板类似,但因为Helm对其不同的使用方式,会有一些特殊的注释。这部分会讲述钩子的基本使用模式。 + +## 可用的钩子 + +定义了以下钩子: + +| 注释值 | 描述 | +| --------------- | ------------------------------------------------------------ | +| `pre-install` | 在模板渲染之后,Kubernetes资源创建之前执行 | +| `post-install` | 在所有资源加载到Kubernetes之后执行 | +| `pre-delete` | 在Kubernetes删除之前,执行删除请求 | +| `post-delete` | 在所有的版本资源删除之后执行删除请求 | +| `pre-upgrade` | 在模板渲染之后,资源更新之前执行一个升级请求 | +| `post-upgrade` | 所有资源升级之后执行一个升级请求 | +| `pre-rollback` | 在模板渲染之后,资源回滚之前,执行一个回滚请求 | +| `post-rollback` | 在所有资源被修改之后执行一个回滚请求 | +| `test` | 调用Helm test子命令时执行 ( [test文档](https://helm.sh/zh/docs/topics/chart_tests/)) | + +## 钩子和发布生命周期 + +钩子允许你在发布生命周期的关键节点上有机会执行操作。比如,考虑`helm install`的生命周期。默认的,生命周期看起来是这样: + +1. 用户执行`helm install foo` +2. Helm库调用安装API +3. 在一些验证之后,库会渲染`foo`模板 +4. 库会加载结果资源到Kubernetes +5. 库会返回发布对象(和其他数据)给客户端 +6. 客户端退出 + +Helm 为`install`周期定义了两个钩子:`pre-install`和`post-install`。如果`foo` chart的开发者两个钩子都执行, 周期会被修改为这样: + +1. 用户返回 `helm install foo` +2. Helm库调用安装API +3. 在 `crds/`目录中的CRD会被安装 +4. 在一些验证之后,库会渲染`foo`模板 +5. 库准备执行`pre-install`钩子(将hook资源加载到Kubernetes中) +6. 库按照权重对钩子排序(默认将权重指定为0),然后在资源种类排序,最后按名称正序排列。 +7. 库先加载最小权重的钩子(从负到正) +8. 库会等到钩子是 "Ready"状态(CRD除外) +9. 库将生成的资源加载到Kubernetes中。注意如果设置了`--wait`参数,库会等所有资源是ready状态, 且所有资源准备就绪后才会执行`post-install`钩子。 +10. 库执行`post-install`钩子(加载钩子资源)。 +11. 库会等到钩子是"Ready"状态 +12. 库会返回发布对象(和其他数据)给客户端 +13. 客户端退出 + +  等钩子准备好是什么意思? 这取决于钩子声明的资源。如果资源是 `Job` 或 `Pod`类型,Helm会等到直到他成功运行完成。 如果钩子失败,发布就会失败。这是一个 _阻塞操作_,所以Helm客户端会在这个任务执行时暂停。 + +  针对其他种类,一旦Kubernetes将资源标记为已加载(已添加或已更新),资源会被认为是"Ready"。 当一个钩子中声明了很多资源时, 资源会串行执行。如果有钩子权重,会按照权重顺序执行。从Helm 3.2.0开始,具有相同权重的钩子资源会和普通非钩子资源以相同的顺序安装。 否则,顺序就无法保证。(Helm 2.3.0及之后,它们按照字母排序。不过该行为并不会绑定,将来可能会改变。)增加钩子权重被认为是很好的做法, 如果权重不重要,可以设置为`0`。 + +### 钩子资源不使用对应版本管理 + +钩子创建的资源无法作为发布的一部分进行跟踪和管理。一旦Helm验证hook达到ready状态,将不使用钩子资源。 当对应发布删除后,钩子资源的垃圾回收会在将来添加到Helm 3中,因此不能被删除的钩子资源应该添加注释: `helm.sh/resource-policy: keep`。 + +实际上,如果你在钩子中创建了资源,不能依靠`helm uninstall`去删除资源。要删除这些资源,要么在钩子模板文件中 [添加一个自定义的`helm.sh/hook-delete-policy` 注释](https://helm.sh/zh/docs/topics/charts_hooks/#hook-deletion-policies),要么 [设置任务资源的生存时间(TTL)字段](https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/)。 + +## 编写一个钩子 + +钩子就是在`metadata`部分指定了特殊注释的Kubernetes清单文件。因为是模板文件,你可以使用所有的普通模板特性,包括读取 `.Values`, `.Release`,和 `.Template`。 + +比如这个模板,存储在`templates/post-install-job.yaml`,声明了一个要运行在`post-install`上的任务: + +```yaml +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ .Release.Name }}" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + annotations: + # This is what defines this resource as a hook. Without this line, the + # job is considered part of the release. + "helm.sh/hook": post-install + "helm.sh/hook-weight": "-5" + "helm.sh/hook-delete-policy": hook-succeeded +spec: + template: + metadata: + name: "{{ .Release.Name }}" + labels: + app.kubernetes.io/managed-by: {{ .Release.Service | quote }} + app.kubernetes.io/instance: {{ .Release.Name | quote }} + helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + spec: + restartPolicy: Never + containers: + - name: post-install-job + image: "alpine:3.3" + command: ["/bin/sleep","{{ default "10" .Values.sleepyTime }}"] +``` + +使模板称为钩子的是注释: + +```yaml +annotations: "helm.sh/hook": post-install +``` + +一个资源可以实现多个钩子: + +```yaml +annotations: "helm.sh/hook": post-install,post-upgrade +``` + +类似的,执行一个给定钩子的不同资源的数量也没有限制。比如,一个pre-install钩子可以同时声明密钥和配置映射。 + +当子chart声明钩子时,这些也会被评估。顶级chart无法禁用子chart声明的钩子。 + +可以为钩子定义权重,这有助于建立一个确定性的执行顺序。权重使用以下注释定义: + +```yaml +annotations: "helm.sh/hook-weight": "5" +``` + +钩子权重可以正数也可以是负数,但一定要是字符串。Helm开始执行特定种类的钩子时,会正序排列这些钩子。 + +### Hook deletion policies + +可以定义策略来决定何时删除对应的钩子资源。钩子的删除策略使用以下注释定义: + +```yaml +annotations: "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +``` + +可以选择一个或多个定义的注释值: + +| 注释值 | 描述 | +| ---------------------- | --------------------------------- | +| `before-hook-creation` | 新钩子启动前删除之前的资源 (默认) | +| `hook-succeeded` | 钩子成功执行之后删除资源 | +| `hook-failed` | 如果钩子执行失败,删除资源 | + +如果没有指定钩子删除策略的注释,默认使用`before-hook-creation`。 \ No newline at end of file diff --git a/helm-jiao-cheng/06.md b/helm-jiao-cheng/06.md new file mode 100644 index 0000000..8cc798d --- /dev/null +++ b/helm-jiao-cheng/06.md @@ -0,0 +1,1400 @@ +# 从这里开始吧 + +我们会创建一个chart并添加第一个模板。创建的chart会在后续指南中用到。 + +接下来,让我们简单看一下Helm chart。 + +## Charts + +如 [Charts 指南](https://helm.sh/zh/docs/topics/charts)所述, Helm chart的结构如下: + +```shell +mychart/ + Chart.yaml + values.yaml + charts/ + templates/ + ... +``` + +`templates/` 目录包括了模板文件。当Helm评估chart时,会通过模板渲染引擎将所有文件发送到`templates/`目录中。 然后收集模板的结果并发送给Kubernetes。 + +`values.yaml` 文件也导入到了模板。这个文件包含了chart的 _默认值_ 。这些值会在用户执行`helm install` 或 `helm upgrade`时被覆盖。 + +`Chart.yaml` 文件包含了该chart的描述。你可以从模板中访问它。`charts/`目录 _可以_ 包含其他的chart(称之为 _子chart_)。 指南稍后我们会看到当涉及模板渲染时这些是如何工作的。 + +## 入门 Chart + +在本指南中我们会创建一个名为`mychart`的chart,然后会在chart中创建一些模板。 + +```console +$ helm create mychart Creating mychart +``` + +**快速查看 `mychart/templates/`** + +如果你看看 `mychart/templates/` 目录,会注意到一些文件已经存在了: + +- `NOTES.txt`: chart的"帮助文本"。这会在你的用户执行`helm install`时展示给他们。 +- `deployment.yaml`: 创建Kubernetes [工作负载](https://kubernetes.io/docs/user-guide/deployments/)的基本清单 +- `service.yaml`: 为你的工作负载创建一个 [service终端](https://kubernetes.io/docs/user-guide/services/)基本清单。 +- `_helpers.tpl`: 放置可以通过chart复用的模板辅助对象 + +然后我们要做的是... _把它们全部删掉!_ 这样我们就可以从头开始学习我们的教程。我们在开始时会创造自己的`NOTES.txt`和`_helpers.tpl`。 + +```console +$ rm -rf mychart/templates/* +``` + +编制生产环境级别的chart时,有这些chart的基础版本会很有用。因此在日常编写中,你可能不想删除它们。 + +## 第一个模板 + +第一个创建的模板是`ConfigMap`。Kubernetes中,配置映射只是用于存储配置数据的对象。其他组件,比如pod,可以访问配置映射中的数据。 + +因为配置映射是基础资源,对我们来说是很好的起点。 + +让我们以创建一个名为 `mychart/templates/configmap.yaml`的文件开始: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: mychart-configmap +data: + myvalue: "Hello World" +``` + +**提示:** 模板名称不遵循严格的命名模式。但是建议以`.yaml`作为YAML文件的后缀,以`.tpl`作为helper文件的后缀。 + +上述YAML文件是一个简单的配置映射,构成了最小的必需字段。因为文件在 `mychart/templates/`目录中,它会通过模板引擎传递。 + +像这样将一个普通YAML文件放在`mychart/templates/`目录中是没问题的。当Helm读取这个模板时会按照原样传递给Kubernetes。 + +有了这个简单的模板,现在有一个可安装的chart了。现在安装如下: + +```console +$ helm install full-coral ./mychart +NAME: full-coral +LAST DEPLOYED: Tue Nov 1 17:36:01 2016 +NAMESPACE: default +STATUS: DEPLOYED +REVISION: 1 +TEST SUITE: None +``` + +我们可以使用Helm检索版本并查看实际加载的模板。 + +```console +$ helm get manifest full-coral + +--- +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: mychart-configmap +data: + myvalue: "Hello World" +``` + +`helm get manifest` 命令后跟一个发布名称(`full-coral`)然后打印出了所有已经上传到server的Kubernetes资源。 每个文件以`---`开头表示YAML文件的开头,然后是自动生成的注释行,表示哪个模板文件生成了这个YAML文档。 + +从这个地方开始,我们看到的YAML数据确实是`configmap.yaml`文件中的内容。 + +现在卸载发布: `helm uninstall full-coral`。 + +**添加一个简单的模板调用** + +将`name:`硬编码到一个资源中不是很好的方式。名称应该是唯一的。因此我们可能希望通过插入发布名称来生成名称字段。 + +**提示:** 由于DNS系统的限制,`name:`字段长度限制为63个字符。因此发布名称限制为53个字符。 Kubernetes 1.3及更早版本限制为24个字符 (名称长度是14个字符)。 + +对应改变一下`configmap.yaml`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" +``` + +大的变化是`name:`字段的值,现在是`{{ .Release.Name }}-configmap`。 + +> 模板命令要括在 `{{` 和 `}}` 之间。 + +模板命令 `{{ .Release.Name }}` 将发布名称注入了模板。值作为一个 _命名空间对象_ 传给了模板,用点(`.`)分隔每个命名空间的元素。 + +`Release`前面的点表示从作用域最顶层的命名空间开始(稍后会谈作用域)。这样`.Release.Name`就可解读为“通顶层命名空间开始查找 Release对象,然后在其中找Name对象”。 + +`Release`是一个Helm的内置对象。稍后会更深入地讨论。但现在足够说明它可以显示从库中赋值的发布名称。 + +现在安装资源,可以立即看到模板命令的结果: + +```console +$ helm install clunky-serval ./mychart +NAME: clunky-serval +LAST DEPLOYED: Tue Nov 1 17:45:37 2016 +NAMESPACE: default +STATUS: DEPLOYED +REVISION: 1 +TEST SUITE: None +``` + +可以运行`helm get manifest clunky-serval`查看生成的完整的YAML。 + +注意在kubernetes内的配置映射名称是 `clunky-serval-configmap`,而不是之前的 `mychart-configmap`。 + +由此我们已经看到了最基本的模板:YAML文件有嵌入在`{{` 和 `}}`之间的模板命令。下一部分,会深入了解模板, 但在这之前,有个快捷的技巧可以加快模板的构建速度:当你想测试模板渲染的内容但又不想安装任何实际应用时,可以使用`helm install --debug --dry-run goodly-guppy ./mychart`。这样不会安装应用(chart)到你的kubenetes集群中,只会渲染模板内容到控制台(用于测试)。渲染后的模板如下: + +```console +$ helm install --debug --dry-run goodly-guppy ./mychart +install.go:149: [debug] Original chart version: "" +install.go:166: [debug] CHART PATH: /Users/ninja/mychart + +NAME: goodly-guppy +LAST DEPLOYED: Thu Dec 26 17:24:13 2019 +NAMESPACE: default +STATUS: pending-install +REVISION: 1 +TEST SUITE: None +USER-SUPPLIED VALUES: +{} + +COMPUTED VALUES: +affinity: {} +fullnameOverride: "" +image: + pullPolicy: IfNotPresent + repository: nginx +imagePullSecrets: [] +ingress: + annotations: {} + enabled: false + hosts: + - host: chart-example.local + paths: [] + tls: [] +nameOverride: "" +nodeSelector: {} +podSecurityContext: {} +replicaCount: 1 +resources: {} +securityContext: {} +service: + port: 80 + type: ClusterIP +serviceAccount: + create: true + name: null +tolerations: [] + +HOOKS: +MANIFEST: +--- +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: goodly-guppy-configmap +data: + myvalue: "Hello World" +``` + +使用`--dry-run`会让你变得更容易测试,但不能保证Kubernetes会接受你生成的模板。 最好不要仅仅因为`--dry-run`可以正常运行就觉得chart可以安装。 + +在 [Chart模板指南](https://helm.sh/zh/docs/chart_template_guide/)中,我们以这里定义的chart基本模板为例详细讨论Helm模板语言。 然后开始讨论内置对象。 + +# 内置对象 + +对象可以通过模板引擎传递到模板中。 当然你的代码也可以传递对象。(我们在使用`with`和`range`语句时,会看到示例)。有几种方式可以在模板中创建新对象,比如说我们后面会看到的`tuple`功能。 + +对象可以是非常简单的:仅有一个值。或者可以包含其他对象或方法。比如,`Release`对象可以包含其他对象(比如:`Release.Name`)和`Files`对象有一组方法。 + +在上一部分中,我们用`{{ .Release.Name }}`在模板中插入版本名称。`Release`是你可以在模板中访问的顶层对象之一。 + +- `Release`: `Release`对象描述了版本发布本身。包含了以下对象: + - `Release.Name`: release名称 + - `Release.Namespace`: 版本中包含的命名空间(如果manifest没有覆盖的话) + - `Release.IsUpgrade`: 如果当前操作是升级或回滚的话,该值将被设置为`true` + - `Release.IsInstall`: 如果当前操作是安装的话,该值将被设置为`true` + - `Release.Revision`: 此次修订的版本号。安装时是1,每次升级或回滚都会自增 + - `Release.Service`: 该service用来渲染当前模板。Helm里始终`Helm` +- `Values`: `Values`对象是从`values.yaml`文件和用户提供的文件传进模板的。默认为空 +- `Chart`: `Chart.yaml`文件内容。 `Chart.yaml`里的所有数据在这里都可以可访问的。比如 `{{ .Chart.Name }}-{{ .Chart.Version }}` 会打印出 `mychart-0.1.0` + - 在 [Chart 指南](https://helm.sh/zh/docs/topics/charts#Chart-yaml-%e6%96%87%e4%bb%b6) 中列出了可获得属性 +- `Files`: 在chart中提供访问所有的非特殊文件的对象。你不能使用它访问`Template`对象,只能访问其他文件。 请查看这个 [文件访问](https://helm.sh/zh/docs/chart_template_guide/accessing_files)部分了解更多信息 + - `Files.Get` 通过文件名获取文件的方法。 (`.Files.Getconfig.ini`) + - `Files.GetBytes` 用字节数组代替字符串获取文件内容的方法。 对图片之类的文件很有用 + - `Files.Glob` 用给定的shell glob模式匹配文件名返回文件列表的方法 + - `Files.Lines` 逐行读取文件内容的方法。迭代文件中每一行时很有用 + - `Files.AsSecrets` 使用Base 64编码字符串返回文件体的方法 + - `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的次版本 + - `Capabilities.HelmVersion` 包含Helm版本详细信息的对象,和 `helm version` 的输出一致 + - `Capabilities.HelmVersion.Version` 是当前Helm语义格式的版本 + - `Capabilities.HelmVersion.GitCommit` Helm的git sha1值 + - `Capabilities.HelmVersion.GitTreeState` 是Helm git树的状态 + - `Capabilities.HelmVersion.GoVersion` 是使用的Go编译器版本 +- `Template`: 包含当前被执行的当前模板信息 + - `Template.Name`: 当前模板的命名空间文件路径 (e.g. `mychart/templates/mytemplate.yaml`) + - `Template.BasePath`: 当前chart模板目录的路径 (e.g. `mychart/templates`) + +内置的值都是以大写字母开始。 这是符合Go的命名惯例。当你创建自己的名称时,可以按照团队约定自由设置。 就像很多你在 [Artifact Hub](https://artifacthub.io/packages/search?kind=0) 中看到的chart,其团队选择使用首字母小写将本地名称与内置对象区分开,本指南中我们也遵循该惯例。 + + + +# Values 文件 + +在上一部分我们了解了Helm模板提供的内置对象。其中一个是`Values`对象。该对象提供了传递值到chart的方法, + +其内容来自于多个位置: + +- chart中的`values.yaml`文件 +- 如果是子chart,就是父chart中的`values.yaml`文件 +- 使用`-f`参数(`helm install -f myvals.yaml ./mychart`)传递到 `helm install` 或 `helm upgrade`的values文件 +- 使用`--set` (比如`helm install --set foo=bar ./mychart`)传递的单个参数 + +以上列表有明确顺序:默认使用`values.yaml`,可以被父chart的`values.yaml`覆盖,继而被用户提供values文件覆盖, 最后会被`--set`参数覆盖,优先级为`values.yaml`最低,`--set`参数最高。 + +values文件是普通的YAML文件。现在编辑`mychart/values.yaml`然后编辑配置映射ConfigMap模板。 + +删除`values.yaml`中的默认内容,仅设置一个参数: + +现在可以在模板中使用它: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" + drink: {{ .Values.favoriteDrink }} +``` + +注意最后一行,`favoriteDrink`是`Values`的一个属性: `{{ .Values.favoriteDrink }}`。 + +看看是如何渲染的: + +```console +$ helm install geared-marsupi ./mychart --dry-run --debug +install.go:158: [debug] Original chart version: "" +install.go:175: [debug] CHART PATH: /home/bagratte/src/playground/mychart + +NAME: geared-marsupi +LAST DEPLOYED: Wed Feb 19 23:21:13 2020 +NAMESPACE: default +STATUS: pending-install +REVISION: 1 +TEST SUITE: None +USER-SUPPLIED VALUES: +{} + +COMPUTED VALUES: +favoriteDrink: coffee + +HOOKS: +MANIFEST: +--- +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: geared-marsupi-configmap +data: + myvalue: "Hello World" + drink: coffee +``` + +由于默认的`values.yaml`文件中设置了`favoriteDrink`的值为`coffee`,则这个显示在了模板中。 可以在调用`helm install`时设置`--set`,很容易就能覆盖这个值。 + +```console +$ helm install solid-vulture ./mychart --dry-run --debug --set favoriteDrink=slurm +install.go:158: [debug] Original chart version: "" +install.go:175: [debug] CHART PATH: /home/bagratte/src/playground/mychart + +NAME: solid-vulture +LAST DEPLOYED: Wed Feb 19 23:25:54 2020 +NAMESPACE: default +STATUS: pending-install +REVISION: 1 +TEST SUITE: None +USER-SUPPLIED VALUES: +favoriteDrink: slurm + +COMPUTED VALUES: +favoriteDrink: slurm + +HOOKS: +MANIFEST: +--- +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: solid-vulture-configmap +data: + myvalue: "Hello World" + drink: slurm +``` + +由于`--set`比默认的`values.yaml`文件优先级更高,模板就生成了`drink: slurm`。 + +values文件也可以包含更多结构化的内容。比如我们可以在`values.yaml`文件中创建一个`favorite`项,然后添加一些key: + +```yaml +favorite: + drink: coffee + food: pizza +``` + +现在需要稍微修改一些模板: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" + drink: {{ .Values.favorite.drink }} + food: {{ .Values.favorite.food }} +``` + +虽然可以这样构造数据,但还是建议构建更加平坦的浅层树。以后想要给子chart赋值时,会看到如何使用树结构给value命名。 + +# 模板函数和流水线 + +到目前为止,我们已经知道了如何将信息传到模板中。 但是传入的信息并不能被修改。 有时我们希望以一种更有用的方式来转换所提供的数据。 + +让我们从一个最佳实践开始:可以通过调用模板指令中的`quote`函数把`.Values`对象中的字符串属性用引号引起来,然后放到模板中。 + +```yaml +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`函数并传递了一个参数(`.Values.favorite.drink`)。 + +Helm 有超过60个可用函数。其中有些通过 [Go模板语言](https://godoc.org/text/template)本身定义。其他大部分都是 [Sprig 模板库](https://masterminds.github.io/sprig/)。我们可以在示例看到其中很多函数。 + +> 当我们讨论"Helm模板语言"时,感觉它是Helm专属的,实际上他是Go模板语言、一些额外的函数和用于 向模板暴露某些对象的装饰器组合而成的。很多Go模板的资料也有助于你学习模板。 + +## 管道符 + +模板语言其中一个强大功能是 **管道** 概念。借鉴UNIX中的概念,管道符是将一系列的模板语言紧凑地将多个流式处理结果合并的工具。换句话说,管道符是按顺序完成一系列任务的方式。 现在用管道符重写上述示例: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" + drink: {{ .Values.favorite.drink | quote }} + food: {{ .Values.favorite.food | quote }} +``` + +在这个示例中,并不是调用`quote 参数`,而是倒置了命令。使用管道符(`|`)将参数“发送”给函数: `.Values.favorite.drink | quote`。使用管道符可以将很多函数链接在一起: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" + drink: {{ .Values.favorite.drink | quote }} + food: {{ .Values.favorite.food | upper | quote }} +``` + +> 倒置命令是模板中的常见做法。可以经常看到 `.val | quote` 而不是 `quote .val`。实际上两种操作都是可以的。 + +模板会生成以下内容: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: trendsetting-p-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" +``` + +注意原有的`pizza`现在已经被转换成了`"PIZZA"`。当管道符参数类似这样的时候,第一个表达式的结果(`.Values.favorite.drink | upper` 的结果) 作为了`quote`的最后一个参数。也可以修改上述示例,用两个参数的函数来阐述: `repeat COUNT STRING`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + myvalue: "Hello World" + drink: {{ .Values.favorite.drink | repeat 5 | quote }} + food: {{ .Values.favorite.food | upper | quote }} +``` + +`repeat`函数会返回给定参数特定的次数,则可以得到以下结果: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: melting-porcup-configmap +data: + myvalue: "Hello World" + drink: "coffeecoffeecoffeecoffeecoffee" + food: "PIZZA" +``` + +## 使用`default`函数 + +模板中频繁使用的一个函数是`default`: `default DEFAULT_VALUE GIVEN_VALUE`。 这个函数允许你在模板中指定一个默认值,以防这个值被忽略。现在使用它修改上述示例: + +```yaml +drink: {{ .Values.favorite.drink | default "tea" | quote }} +``` + +如果运行,会得到 `coffee`: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: virtuous-mink-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" +``` + +现在,从`values.yaml`中移除设置: + +```yaml +favorite: + #drink: coffee + food: pizza +``` + +现在重新运行 `helm install --dry-run --debug fair-worm ./mychart` 会生成如下内容: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: fair-worm-configmap +data: + myvalue: "Hello World" + drink: "tea" + food: "PIZZA" +``` + +在实际的chart中,所有的静态默认值应该设置在 `values.yaml` 文件中,且不应该重复使用 `default` 命令 (否则会出现冗余)。然而这个`default` 命令很适合计算值,其不能声明在`values.yaml`文件中,比如: + +```yaml +drink: {{ .Values.favorite.drink | default (printf "%s-tea" (include "fullname" .)) }} +``` + +有些场景,`if`条件比`default`更加适合。在下一章节我们就会看到。 + +模板函数和管道符是转换信息然后将其插入到YAML中的强有力方式。但是有些时候我们需要插入一些内容之前进行一些逻辑判断,而不仅仅是插入一个字符串。 下一章节,我们会看到模板语言提供的控制结构。 + +## 使用`lookup`函数 + +`lookup` 函数可以用于在运行的集群中 _查找_ 资源。lookup函数简述为查找 `apiVersion, kind, namespace,name -> 资源或者资源列表`。 + +| parameter | type | +| ---------- | ------ | +| apiVersion | string | +| kind | string | +| namespace | string | +| name | string | + +`name` 和 `namespace` 都是选填的,且可以传空字符串(`""`)作为空。 + +以下是可能的参数组合: + +| 命令 | 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`对象的annotations属性: + +```go +(lookup "v1" "Namespace" "" "mynamespace").metadata.annotations +``` + +当`lookup`返回一个对象列表时,可以通过`items`字段访问对象列表: + +```go +{{ range $index, $service := (lookup "v1" "Service" "mynamespace" "").items }} + {{/* do something with each service */}} +{{ end }} +``` + +当对象未找到时,会返回空值。可以用来检测对象是否存在。 + +`lookup`函数使用Helm已有的Kubernetes连接配置查询Kubernetes。当与调用API服务交互时返回了错误 (比如缺少资源访问的权限),helm 的模板操作会失败。 + +请记住,Helm在`helm template`或者`helm install|upgrade|delete|rollback --dry-run`时, 不应该请求Kubernetes API服务。由此,`lookup`函数在该案例中会返回空列表(即字典)。 + +## 运算符也是函数 + +对于模板来说,运算符(`eq`, `ne`, `lt`, `gt`, `and`, `or`等等) 都是作为函数来实现的。 在管道符中,操作可以按照圆括号分组。 + +现在我们可以从函数和管道符返回到条件控制流,循环和范围修饰符。 + +# 流控制 + +控制结构(在模板语言中称为"actions")提供给你和模板作者控制模板迭代流的能力。 Helm的模板语言提供了以下控制结构: + +- `if`/`else`, 用来创建条件语句 +- `with`, 用来指定范围 +- `range`, 提供"for each"类型的循环 + +除了这些之外,还提供了一些声明和使用命名模板的关键字: + +- `define` 在模板中声明一个新的命名模板 +- `template` 导入一个命名模板 +- `block` 声明一种特殊的可填充的模板块 + +该部分,我们会讨论关于`if`,`with`,和 `range`。其他部分会在该指南的“命名模板”部分说明。 + +## If/Else + +第一个控制结构是在按照条件在一个模板中包含一个块文本。即`if`/`else`块。 + +基本的条件结构看起来像这样: + +```yaml +{{ if PIPELINE }} + # Do something +{{ else if OTHER PIPELINE }} + # Do something else +{{ else }} + # Default case +{{ end }} +``` + +注意我们讨论的是 _管道_ 而不是值。这样做的原因是要清楚地说明控制结构可以执行整个管道,而不仅仅是计算一个值。 + +如果是以下值时,管道会被设置为 _false_: + +- 布尔false +- 数字0 +- 空字符串 +- `nil` (空或null) +- 空集合(`map`, `slice`, `tuple`, `dict`, `array`) + +在所有其他条件下,条件都为true。 + +让我们先在配置映射中添加一个简单的条件。如果饮品是coffee会添加另一个配置: + +```yaml +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 }} +``` + +由于我们在最后一个例子中注释了`drink: coffee`,输出中就不会包含`mug: "true"`标识。但如果将这行添加到`values.yaml` 文件中,输入就会是这样: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: eyewitness-elk-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" + mug: "true" +``` + +## 控制空格 + +查看条件时,我们需要快速了解一下模板中控制空白的方式,格式化之前的例子,使其更易于阅读: + +```yaml +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 }} +``` + +初始情况下,看起来没问题。但是如果通过模板引擎运行时,我们将得到一个不幸的结果: + +```console +$ helm install --dry-run --debug ./mychart +SERVER: "localhost:44134" +CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart +Error: YAML parse error on mychart/templates/configmap.yaml: error converting YAML to JSON: yaml: line 9: did not find expected key +``` + +发生了啥?因为空格导致生成了错误的YAML。 + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: eyewitness-elk-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" + mug: "true" +``` + +`mug`的缩进是不对的。取消缩进重新执行一下: + +```yaml +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 }} +``` + +这个就得到了合法的YAML,但是看起来还是有点滑稽: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: telling-chimp-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" + + mug: "true" +``` + +注意在YAML中有一个空行,为什么?当模板引擎运行时,它 _移除了_ `{{` 和 `}}` 里面的内容,但是留下的空白完全保持原样。 + +YAML认为空白是有意义的,因此管理空白变得很重要。幸运的是,Helm模板有些工具可以处理此类问题。 + +首先,模板声明的大括号语法可以通过特殊的字符修改,并通知模板引擎取消空白。`{{-` (包括添加的横杠和空格)表示向左删除空白, 而 `-}}`表示右边的空格应该被去掉。 _一定注意空格就是换行_ + +> 要确保`-`和其他命令之间有一个空格。 `{{- 3 }}` 表示“删除左边空格并打印3”,而`{{-3 }}`表示“打印-3”。 + +使用这个语法,我们就可修改我们的模板,去掉新加的空白行: + +```yaml +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 }} +``` + +只是为了把这一点搞清楚,我们来调整上述内容,用一个`*`来代替每个遵循此规则被删除的空白, 在行尾的`*`表示删除新行的字符: + +```yaml +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运行模板并查看结果: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: clunky-cat-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" + mug: "true" +``` + +要注意这个删除字符的更改,很容易意外地出现情况: + +```yaml + food: {{ .Values.favorite.food | upper | quote }} + {{- if eq .Values.favorite.drink "coffee" -}} + mug: "true" + {{- end -}} +``` + +这样会变成`food: "PIZZA"mug:"true"`,因为这把两边的新行都删除了。 + +> 关于模板中的空白控制,请查看 [官方Go模板文档](https://godoc.org/text/template) + +最终,有时这更容易告诉模板系统如何缩进,而不是试图控制模板指令间的间距。因此,您有时会发现使用`indent`方法(`{{ indent 2 "mug:true" }}`)会很有用。 + +## 修改使用`with`的范围 + +下一个控制结构是`with`操作。这个用来控制变量范围。回想一下,`.`是对 _当前作用域_ 的引用。因此 `.Values`就是告诉模板在当前作用域查找`Values`对象。 + +`with`的语法与`if`语句类似: + +```yaml +{{ with PIPELINE }} + # restricted scope +{{ end }} +``` + +作用域可以被改变。`with`允许你为特定对象设定当前作用域(`.`)。比如,我们已经在使用`.Values.favorite`。 修改配置映射中的`.`的作用域指向`.Values.favorite`: + +```yaml +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 }} +``` + +注意我们从之前的练习中移除了`if`条件,因为现在不需要了——`with`后面的块只有在 `PIPELINE` 的值不为空时才会执行。 + +注意现在我们可以引用`.drink`和`.food`了,而不必限定他们。因为`with`语句设置了`.`指向`.Values.favorite`。 `.`被重置为`{{ end }}`之后的上一个作用域。 + +但是这里有个注意事项,在限定的作用域内,无法使用`.`访问父作用域的对象。错误示例如下: + +```yaml + {{- with .Values.favorite }} + drink: {{ .drink | default "tea" | quote }} + food: {{ .food | upper | quote }} + release: {{ .Release.Name }} + {{- end }} +``` + +这样会报错因为`Release.Name`不在`.`限定的作用域内。但是如果对调最后两行就是正常的, 因为在`{{ end }}`之后作用域被重置了。 + +```yaml + {{- with .Values.favorite }} + drink: {{ .drink | default "tea" | quote }} + food: {{ .food | upper | quote }} + {{- end }} + release: {{ .Release.Name }} +``` + +或者,我们可以使用`$`从父作用域中访问`Release.Name`对象。当模板开始执行后`$`会被映射到根作用域,且执行过程中不会更改。 下面这种方式也可以正常工作: + +```yaml + {{- with .Values.favorite }} + drink: {{ .drink | default "tea" | quote }} + food: {{ .food | upper | quote }} + release: {{ $.Release.Name }} + {{- end }} +``` + +在介绍了`range`之后,我们会看看模板变量,提供了上述作用域问题的另一种解决方案。 + +## 使用`range`操作循环 + +很多编程语言支持使用`for`循环,`foreach`循环,或者类似的方法机制。 在Helm的模板语言中,在一个集合中迭代的方式是使用`range`操作符。 + +开始之前,我们先在`values.yaml`文件添加一个披萨的配料列表: + +```yaml +favorite: + drink: coffee + food: pizza +pizzaToppings: + - mushrooms + - cheese + - peppers + - onions +``` + +现在我们有了一个`pizzaToppings`列表(模板中称为切片)。修改模板把这个列表打印到配置映射中: + +```yaml +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 }} +``` + +我可以使用`$`从父作用域访问`Values.pizzaToppings`列表。当模板开始执行后`$`会被映射到根作用域, 且执行过程中不会更改。下面这种方式也可以正常工作: + +```yaml +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 }} +``` + +让我们仔细看看`toppings:`列表。`range`方法“涵盖”(迭代)`pizzaToppings`列表。但现在发生了有意思的事情。 就像`with`设置了`.`的作用域,`range`操作符也做了同样的事。每一次循环,`.`都会设置为当前的披萨配料。 也就是说,第一次`.`设置成了`mushrooms`,第二次迭代设置成了`cheese`,等等。 + +我们可以直接发送`.`的值给管道,因此当我们执行`{{ . | title | quote }}`时,它会发送`.`到`title`然后发送到`quote`。 如果执行这个模板,输出是这样的: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: edgy-dragonfly-configmap +data: + myvalue: "Hello World" + drink: "coffee" + food: "PIZZA" + toppings: |- + - "Mushrooms" + - "Cheese" + - "Peppers" + - "Onions" +``` + +现在,我们已经处理了一些棘手的事情。`toppings: |-`行是声明的多行字符串。所以这个配料列表实际上不是YAML列表, 是个大字符串。为什么要这样做?因为在配置映射`data`中的数据是由键值对组成,key和value都是简单的字符串。 要理解这个示例,请查看 [Kubernetes ConfigMap 文档](https://kubernetes.io/docs/user-guide/configmap/)。 但对于我们来说,这个细节并不重要。 + +> 正如例子中所示,`|-`标识在YAML中是指多行字符串。这在清单列表中嵌入大块数据是很有用的技术。 + +有时能在模板中快速创建列表然后迭代很有用,Helm模板的`tuple`可以很容易实现该功能。在计算机科学中, 元组表示一个有固定大小的类似列表的集合,但可以是任意数据类型。这大致表达了`tuple`的用法。 + +```yaml + sizes: |- + {{- range tuple "small" "medium" "large" }} + - {{ . }} + {{- end }} +``` + +上述模板会生成以下内容: + +```yaml + sizes: |- + - small + - medium + - large +``` + +除了列表和元组,`range`可被用于迭代有键值对的集合(像`map`或`dict`)。我们会在下一部分介绍模板变量是看到它是如何应用的。 + +# include 和 template + +`define`操作允许我们在模板文件中创建一个命名模板,语法如下: + +```yaml +{{- define "MY.NAME" }} + # body of template here +{{- end }} +``` + +比如我们可以定义一个模板封装Kubernetes的标签: + +```yaml +{{- define "mychart.labels" }} + labels: + generator: helm + date: {{ now | htmlDate }} +{{- end }} +``` + +现在我们将模板嵌入到了已有的配置映射中,然后使用`template`包含进来: + +```yaml +{{- 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 }} +``` + +当模板引擎读取该文件时,它会存储`mychart.labels`的引用直到`template "mychart.labels"`被调用。 然后会按行渲染模板,因此结果类似这样: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: running-panda-configmap + labels: + generator: helm + date: 2016-11-02 +data: + myvalue: "Hello World" + drink: "coffee" + food: "pizza" +``` + +注意:`define`不会有输出,除非像本示例一样用模板调用它。 + +按照惯例,Helm chart将这些模板放置在局部文件中,一般是`_helpers.tpl`。把这个方法移到那里: + +```yaml +{{/* Generate basic labels */}} +{{- define "mychart.labels" }} + labels: + generator: helm + date: {{ now | htmlDate }} +{{- end }} +``` + +按照惯例`define`方法会有个简单的文档块(`{{/* ... */}}`)来描述要做的事。 + +尽管这个定义是在`_helpers.tpl`中,但它仍能在 `configmap.yaml` 中访问: + +```yaml +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 }} +``` + +如上所述,**模板名称是全局的**。因此,如果两个模板使用相同名字声明,会使用最后出现的那个。由于子chart中的模板和顶层模板一起编译, 最好用 _chart特定名称_ 命名你的模板。常用的命名规则是用chart的名字作为模板的前缀: `{{ define "mychart.labels" }}`。 + +## 设置模板范围 + +在上面定义的模板中,我们没有使用任何对象,仅仅使用了方法。修改定义好的模板让其包含chart名称和版本号: + +```yaml +{{/* Generate basic labels */}} +{{- define "mychart.labels" }} + labels: + generator: helm + date: {{ now | htmlDate }} + chart: {{ .Chart.Name }} + version: {{ .Chart.Version }} +{{- end }} +``` + +如果渲染这个,会得到以下错误: + +```console +$ helm install --dry-run moldy-jaguar ./mychart +Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [unknown object type "nil" in ConfigMap.metadata.labels.chart, unknown object type "nil" in ConfigMap.metadata.labels.version] +``` + +要查看渲染了什么,可以用`--disable-openapi-validation`参数重新执行: `helm install --dry-run --disable-openapi-validation moldy-jaguar ./mychart`。 结果并不是我们想要的: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: moldy-jaguar-configmap + labels: + generator: helm + date: 2021-03-06 + chart: + version: +``` + +名字和版本号怎么了?没有出现在我们定义的模板中。当一个(使用`define`创建的)命名模板被渲染时,会接收被`template`调用传入的内容。 在我们的示例中,包含模板如下: + +```yaml +{{- template "mychart.labels" }} +``` + +没有内容传入,所以模板中无法用`.`访问任何内容。但这个很容易解决,只需要传递一个范围给模板: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap + {{- template "mychart.labels" . }} +``` + +注意这个在`template`调用末尾传入的`.`,我们可以简单传入`.Values`或`.Values.favorite`或其他需要的范围。但一定要是顶层范围。 + +现在我们可以用`helm install --dry-run --debug plinking-anaco ./mychart`执行模板,然后得到: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: plinking-anaco-configmap + labels: + generator: helm + date: 2021-03-06 + chart: mychart + version: 0.1.0 +``` + +现在`{{ .Chart.Name }}`解析为`mychart`,`{{ .Chart.Version }}`解析为`0.1.0`。 + +## `include`方法 + +假设定义了一个简单模板如下: + +```yaml +{{- define "mychart.app" -}} +app_name: {{ .Chart.Name }} +app_version: "{{ .Chart.Version }}" +{{- end -}} +``` + +现在假设我想把这个插入到模板的`labels:`部分和`data:`部分: + +```yaml +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" . }} +``` + +如果渲染这个,会得到以下错误: + +```console +$ helm install --dry-run measly-whippet ./mychart +Error: unable to build kubernetes objects from release manifest: error validating "": error validating data: [ValidationError(ConfigMap): unknown field "app_name" in io.k8s.api.core.v1.ConfigMap, ValidationError(ConfigMap): unknown field "app_version" in io.k8s.api.core.v1.ConfigMap] +``` + +要查看渲染了什么,可以用`--disable-openapi-validation`参数重新执行: `helm install --dry-run --disable-openapi-validation measly-whippet ./mychart`。 输入不是我们想要的: + +```yaml +# Source: mychart/templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: measly-whippet-configmap labels: app_name: mychart app_version: "0.1.0" data: myvalue: "Hello World" drink: "coffee" food: "pizza" app_name: mychart app_version: "0.1.0" +``` + +注意两处的`app_version`缩进都不对,为啥?因为被替换的模板中文本是左对齐的。由于`template`是一个行为,不是方法,无法将 `template`调用的输出传给其他方法,数据只是简单地按行插入。 + +为了处理这个问题,Helm提供了一个`template`的可选项,可以将模板内容导入当前管道,然后传递给管道中的其他方法。 + +下面这个示例,使用`indent`正确地缩进了`mychart.app`模板: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: measly-whippet-configmap + labels: + app_name: mychart +app_version: "0.1.0" +data: + myvalue: "Hello World" + drink: "coffee" + food: "pizza" +app_name: mychart +app_version: "0.1.0" +``` + +现在生成的YAML每一部分都可以正确缩进了: + +```yaml +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 }} +``` + +> 相较于使用`template`,在helm中使用`include`被认为是更好的方式 只是为了更好地处理YAML文档的输出格式 + +有时我们需要导入内容,但不是作为模板,也就是按字面意义导入文件内容,可以通过使用`.Files`对象访问文件来实现, 这将在下一部分展开描述。 + +# 子 chart 和全局值 + +到目前为止,我们只使用了一个chart。但chart可以使用依赖,称为 _子chart_,且有自己的值和模板。 该章节我们会创建一个子chart并能看到访问模板中的值的不同方式。 + +在深入研究代码之前,需要了解一些应用的子chart的重要细节: + +1. 子chart被认为是“独立的”,意味着子chart从来不会显示依赖它的父chart。 +2. 因此,子chart无法访问父chart的值。 +3. 父chart可以覆盖子chart的值。 +4. Helm有一个 _全局值_ 的概念,所有的chart都可以访问。 + +> 这些限制不一定都适用于提供标准化辅助功能的 [library charts](https://helm.sh/zh/docs/topics/library_charts)。 + +浏览本节的示例之后,这些概念会变得更加清晰。 + +## 创建子chart + +为了做这些练习,我们可以从本指南开始时创建的`mychart/`开始,并在其中添加一个新的chart。 + +```console +$ cd mychart/charts +$ helm create mysubchart +Creating mysubchart +$ rm -rf mysubchart/templates/* +``` + +注意,和以前一样,我们删除了所有的基本模板,然后从头开始,在这个指南中,我们聚焦于模板如何工作,而不是管理依赖。 但 [Chart指南](https://helm.sh/zh/docs/topics/charts)提供了更多子chart运行的信息。 + +## 在子chart中添加值和模板 + +下一步,为`mysubchart`创建一个简单的模板和values文件。`mychart/charts/mysubchart`应该已经有一个`values.yaml`。 设置如下: + +```shell +dessert: cake +``` + +下一步,在`mychart/charts/mysubchart/templates/configmap.yaml`中创建一个新的配置映射模板: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-cfgmap2 +data: + dessert: {{ .Values.dessert }} +``` + +因为每个子chart都是 _独立的chart_,可以单独测试`mysubchart`: + +```console +$ helm install --generate-name --dry-run --debug mychart/charts/mysubchart +SERVER: "localhost:44134" +CHART PATH: /Users/mattbutcher/Code/Go/src/helm.sh/helm/_scratch/mychart/charts/mysubchart +NAME: newbie-elk +TARGET NAMESPACE: default +CHART: mysubchart 0.1.0 +MANIFEST: +--- +# Source: mysubchart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: newbie-elk-cfgmap2 +data: + dessert: cake +``` + +## 用父chart的值来覆盖 + +原始chart,`mychart`现在是`mysubchart`的 _父_。这种关系是基于`mysubchart`在`mychart/charts`中这一事实。 + +因为`mychart`是父级,可以在`mychart`指定配置并将配置推送到`mysubchart`。比如可以修改`mychart/values.yaml`如下: + +```yaml +favorite: + drink: coffee + food: pizza +pizzaToppings: + - mushrooms + - cheese + - peppers + - onions + +mysubchart: + dessert: ice cream +``` + +注意最后两行,在`mysubchart`中的所有指令会被发送到`mysubchart`chart中。因此如果运行`helm install --dry-run --debug mychart`,会看到一项`mysubchart`的配置: + +```yaml +# Source: mychart/charts/mysubchart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: unhinged-bee-cfgmap2 +data: + dessert: ice cream +``` + +现在,子chart的值已经被顶层的值覆盖了。 + +这里需要注意个重要细节。我们不会改变`mychart/charts/mysubchart/templates/configmap.yaml`模板到 `.Values.mysubchart.dessert`的指向。从模板的角度来看,值依然是在`.Values.dessert`。当模板引擎传递值时,会设置范围。 因此对于`mysubchart`模板,`.Values`中只提供专门用于`mysubchart`的值。 + +但是有时确实希望某些值对所有模板都可用。这是使用全局chart值完成的。 + +## 全局Chart值 + +全局值是使用完全一样的名字在所有的chart及子chart中都能访问的值。全局变量需要显式声明。不能将现有的非全局值作为全局值使用。 + +这些值数据类型有个保留部分叫`Values.global`,可以用来设置全局值。在`mychart/values.yaml`文件中设置一个值如下: + +```yaml +favorite: + drink: coffee + food: pizza +pizzaToppings: + - mushrooms + - cheese + - peppers + - onions + +mysubchart: + dessert: ice cream + +global: + salad: caesar +``` + +因为全局的工作方式,`mychart/templates/configmap.yaml`和`mysubchart/templates/configmap.yaml` 应该都能以`{{ .Values.global.salad }}`进行访问。 + +`mychart/templates/configmap.yaml`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-configmap +data: + salad: {{ .Values.global.salad }} +``` + +`mysubchart/templates/configmap.yaml`: + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-cfgmap2 +data: + dessert: {{ .Values.dessert }} + salad: {{ .Values.global.salad }} +``` + +现在如果预安装,两个输出会看到相同的值: + +```yaml +# Source: mychart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: silly-snake-configmap +data: + salad: caesar + +--- +# Source: mychart/charts/mysubchart/templates/configmap.yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: silly-snake-cfgmap2 +data: + dessert: ice cream + salad: caesar +``` + +全局值在类似这样传递信息时很有用,不过要确保使用全局值配置正确的模板,确实需要一些计划。 + +## 与子chart共享模板 + +父chart和子chart可以共享模板。在任意chart中定义的块在其他chart中也是可用的。 + +比如,我们可以这样定义一个简单的模板: + +```yaml +{{- define "labels" }}from: mychart{{ end }} +``` + +回想一下模板标签时如何 _全局共享的_。因此,`标签`chart可以包含在任何其他chart中。 + +当chart开发者在`include` 和 `template` 之间选择时,使用`include`的一个优势是`include`可以动态引用模板: + +```yaml +{{ include $mytemplate }} +``` + +上述会取消对`$mytemplate`的引用,相反,`template`函数只接受字符串字符。 + +## 避免使用块 + +Go 模板语言提供了一个 `block` 关键字允许开发者提供一个稍后会被重写的默认实现。在Helm chart中, 块并不是用于覆盖的最好工具,因为如果提供了同一个块的多个实现,无法预测哪个会被选定。 + +建议改为使用`include`。 \ No newline at end of file