您可以阅读有关 helmfile 本身及其使用示例的信息
我们将熟悉在 helmfile 中描述版本的非显而易见的方式
假设我们有一组 Helm Charts(例如,Postgres 和一些后端应用程序)和几个环境(几个 kubernetes 集群、几个命名空间或两者兼而有之)。 我们获取 helmfile,阅读文档并开始描述我们的环境和版本:
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yaml
helmfile.yaml
environments:
devel:
production:
releases:
- name: postgres
labels:
app: postgres
wait: true
chart: stable/postgresql
version: 8.4.0
values:
- envs/{{ .Environment.Name }}/values/postgres.yaml
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
version: 1.0.5
needs:
- postgres
values:
- envs/{{ .Environment.Name }}/values/backend.yaml
我们最终得到了 2 个环境: 与开发, 生产 — 每个都包含其自己的 helm 发布图表值。 我们将像这样部署到他们:
helmfile -n <namespace> -e <env> apply
不同环境下不同版本的 Helm Chart
如果我们需要将不同版本的后端部署到不同的环境怎么办? 如何参数化发布版本? 环境价值可通过 {{ .Values }}
helmfile.yaml
environments:
devel:
+ values:
+ - charts:
+ versions:
+ backend: 1.1.0
production:
+ values:
+ - charts:
+ versions:
+ backend: 1.0.5
...
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
- version: 1.0.5
+ version: {{ .Values.charts.versions.backend }}
...
不同环境下的不同应用程序集
很好,但是如果我们不需要怎么办? production
推出 postgres,因为我们知道我们不需要将数据库推送到 k8s,并且我们有一个很棒的独立 postgres 集群可供出售? 为了解决这个问题我们有标签
helmfile -n <namespace> -e devel apply
helmfile -n <namespace> -e production -l app=backend apply
这很棒,但我个人更喜欢不使用启动参数,而是在环境本身的描述中描述要在环境中部署哪些应用程序。 该怎么办? 您可以将版本描述放在单独的文件夹中,在环境描述中创建必要版本的列表,然后仅“选取”必要的版本,忽略其余版本
.
├── envs
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
+ ├── releases
+ │ ├── backend.yaml
+ │ └── postgres.yaml
└── helmfile.yaml
helmfile.yaml
environments:
devel:
values:
- charts:
versions:
backend: 1.1.0
- apps:
- postgres
- backend
production:
values:
- charts:
versions:
backend: 1.0.5
- apps:
- backend
- releases:
- - name: postgres
- labels:
- app: postgres
- wait: true
- chart: stable/postgresql
- version: 8.4.0
- values:
- - envs/{{ .Environment.Name }}/values/postgres.yaml
- - name: backend
- labels:
- app: backend
- wait: true
- chart: private-helm-repo/backend
- version: {{ .Values.charts.versions.backend }}
- needs:
- - postgres
- values:
- - envs/{{ .Environment.Name }}/values/backend.yaml
+ ---
+ bases:
+ {{- range .Values.apps }}
+ - releases/{{ . }}.yaml
+ {{- end }}
releases/postgres.yaml
releases:
- name: postgres
labels:
app: postgres
wait: true
chart: stable/postgresql
version: 8.4.0
values:
- envs/{{ .Environment.Name }}/values/postgres.yaml
releases/backend.yaml
releases:
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
version: {{ .Values.charts.versions.backend }}
needs:
- postgres
values:
- envs/{{ .Environment.Name }}/values/backend.yaml
注意
当使用 bases:
需要使用yaml分隔符 ---
,以便您可以使用环境中的值来模板发布(以及其他部分,例如 helmDefaults)
在这种情况下,postgres 版本甚至不会包含在生产描述中。 很舒服!
发布的可重写全局值
当然,您可以为每个环境设置 helm 图表的值,但是如果我们描述了多个环境,并且我们希望为所有环境设置相同的值,该怎么办? affinity
,但我们不想在存储在萝卜中的图表本身中默认配置它。
在这种情况下,对于每个版本,我们可以指定 2 个带有值的文件:第一个带有默认值,它将确定图表本身的值,第二个带有环境值,这反过来将覆盖图表本身的值。默认的。
.
├── envs
+ │ ├── default
+ │ │ └── values
+ │ │ ├── backend.yaml
+ │ │ └── postgres.yaml
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
├── releases
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yaml
releases/backend.yaml
releases:
- name: backend
labels:
app: backend
wait: true
chart: private-helm-repo/backend
version: {{ .Values.charts.versions.backend }}
needs:
- postgres
values:
+ - envs/default/values/backend.yaml
- envs/{{ .Environment.Name }}/values/backend.yaml
envs/default/values/backend.yaml
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- backend
topologyKey: "kubernetes.io/hostname"
在环境级别定义所有版本的 Helm Chart 的全局值
假设我们在多个版本中创建多个入口 - 我们可以为每个图表手动定义 hosts:
,但在我们的例子中,域是相同的,那么为什么不将其放入某个全局变量中并简单地将其值替换到图表中呢? 为此,那些具有我们想要参数化值的文件必须具有扩展名 .gotmpl
,这样helmfile就知道它需要通过模板引擎来运行。
.
├── envs
│ ├── default
│ │ └── values
- │ │ ├── backend.yaml
- │ │ ├── postgres.yaml
+ │ │ ├── backend.yaml.gotmpl
+ │ │ └── postgres.yaml.gotmpl
│ ├── devel
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ └── production
│ └── values
│ ├── backend.yaml
│ └── postgres.yaml
├── releases
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yaml
helmfile.yaml
environments:
devel:
values:
- charts:
versions:
backend: 1.1.0
- apps:
- postgres
- backend
+ - global:
+ ingressDomain: k8s.devel.domain
production:
values:
- charts:
versions:
backend: 1.0.5
- apps:
- backend
+ - global:
+ ingressDomain: production.domain
---
bases:
{{- range .Values.apps }}
- releases/{{ . }}.yaml
{{- end }}
envs/default/values/backend.yaml.gotmpl
ingress:
enabled: true
paths:
- /api
hosts:
- {{ .Values.global.ingressDomain }}
envs/default/values/postgres.yaml.gotmpl
ingress:
enabled: true
paths:
- /
hosts:
- postgres.{{ .Values.global.ingressDomain }}
注意
显然,postgres 图表中的 ingress 是非常可疑的东西,因此本文仅作为真空中的球形示例给出,以免仅仅为了描述 ingress 而在文章中引入一些新版本
用环境值替换秘密
类比上面的例子,你可以使用加密的来替换
.
├── envs
│ ├── default
│ │ └── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
│ ├── devel
│ │ ├── values
│ │ │ ├── backend.yaml
│ │ │ └── postgres.yaml
+ │ │ └── secrets.yaml
│ └── production
│ ├── values
│ │ ├── backend.yaml
│ │ └── postgres.yaml
+ │ └── secrets.yaml
├── releases
│ ├── backend.yaml
│ └── postgres.yaml
└── helmfile.yaml
helmfile.yaml
environments:
devel:
values:
- charts:
versions:
backend: 1.1.0
- apps:
- postgres
- backend
- global:
ingressDomain: k8s.devel.domain
+ secrets:
+ - envs/devel/secrets.yaml
production:
values:
- charts:
versions:
backend: 1.0.5
- apps:
- backend
- global:
ingressDomain: production.domain
+ secrets:
+ - envs/production/secrets.yaml
---
bases:
{{- range .Values.apps }}
- releases/{{ . }}.yaml
{{- end }}
envs/devel/secrets.yaml
secrets:
elastic:
password: ENC[AES256_GCM,data:hjCB,iv:Z1P6/6xBJgJoKLJ0UUVfqZ80o4L84jvZfM+uH9gBelc=,tag:dGqQlCZnLdRAGoJSj63rBQ==,type:int]
...
envs/production/secrets.yaml
secrets:
elastic:
password: ENC[AES256_GCM,data:ZB/VpTFk8f0=,iv:EA//oT1Cb5wNFigTDOz3nA80qD9UwTjK5cpUwLnEXjs=,tag:hMdIUaqLRA8zuFBd82bz6A==,type:str]
...
envs/default/values/backend.yaml.gotmpl
elasticsearch:
host: elasticsearch
port: 9200
password: {{ .Values | getOrNil "secrets.elastic.password" | default "password" }}
envs/devel/values/backend.yaml
elasticsearch:
host: elastic-0.devel.domain
envs/production/values/backend.yaml
elasticsearch:
host: elastic-0.production.domain
注意
顺便说一下, getOrNil
- helmfile 中 go 模板的特殊函数,即使 .Values.secrets
将不存在,不会抛出错误,但将允许使用该函数的结果 default
替换默认值
结论
描述的事情看起来很明显,但是关于使用 helmfile 方便地描述部署到多个环境的信息非常稀缺,而且我喜欢 IaC(基础设施即代码)并且希望对部署状态有清晰的描述。
最后,我想补充一点,默认环境的变量可以反过来用将启动部署的某个运行器的操作系统的环境变量进行参数化,从而获得动态环境
helmfile.yaml
environments:
default:
values:
- global:
clusterDomain: {{ env "CLUSTER_DOMAIN" | default "cluster.local" }}
ingressDomain: {{ env "INGRESS_DOMAIN" }}
来源: habr.com