写Helm Chart之前我希望提前知道的8个有用的事项

这是Kubernetes3 Adcent Calendar 2018年11月份的第11篇文章。

在开始编写Helm Chart模板之前,我会介绍一些我希望在此之前就知道的要点。

基本上,如果你能好好地读一下《图表模板开发人员指南》,然后再开始,就可以了…

如果存在多个环境,使用”–values”选项可以按环境指定变量,这看起来是个不错的选择。

看起来像是需要根据环境使用不同的变量文件,就像这个幻灯片上所展示的一样。(因为我们是同一家公司,所以我也在学习他们的做法…)

2. –set选项将覆盖–values指定的文件

在只需要修改tag指定时使用。

3. – 很困难

如果在if语句中去掉前面的空格和换行符号,可以实现相应的去除操作,但是如果只想显示else部分,就比较难控制了…如果按照下面这样写

  {{- if .Values.hpa.enabled -}}
  {{- else -}}
  replicas: {{ .Values.replicas | default "2" }}
  {{- end -}}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "my-chart.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}

由于不符合正确的yaml格式,会导致出现以下情况,因此会产生错误…

spec:replicas: 3selector:
    matchLabels:
      app.kubernetes.io/name: my-chart
      app.kubernetes.io/instance: my-chart

文档中写着要使用缩进函数({{indent 2 “mug:true”}}),但是按照这种方法,无法使用默认值(?),所以最终我选择了下面的方式。

spec:
  {{- if .Values.hpa.enabled -}}
  {{- else }}
  replicas: {{ .Values.replicas | default "2" }}
  {{- end }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "my-chart.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}

当.Values.hpa.enabled为true时,

spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: my-chart
      app.kubernetes.io/instance: my-chart

当.Values.hpa.enabled参数为false时,

spec:
  replicas: 3
  selector:
    matchLabels:
      app.kubernetes.io/name: my-chart
      app.kubernetes.io/instance: my-chart

尝试使用以下方法,

  {{- if .Values.hpa.enabled -}}
  {{- else }}
  replicas: {{ .Values.replicas | default "2" }}
  {{ end -}}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "my-chart.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}

当是真的时不行了…

spec:selector:
    matchLabels:
      app.kubernetes.io/name: my-chart
      app.kubernetes.io/instance: my-chart
  template:
    metadata:
      labels:
        app.kubernetes.io/name: my-chart
        app.kubernetes.io/instance: my-chart

使用include和nindent可能比使用template更好。

由于模板的缩进不能被控制,建议使用 “{{- include xxx . | nindent n }}” 这样的写法。
在存在多个容器的情况下特别方便。

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  name: {{ include "my-chart.fullname" . }}
  labels:
    app.kubernetes.io/name: {{ include "my-chart.name" . }}
    helm.sh/chart: {{ include "my-chart.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
  {{- if .Values.hpa.enabled -}}
  {{- else }}
  replicas: {{ .Values.replicas | default "2" }}
  {{- end }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "my-chart.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "my-chart.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      containers:
      # ここ
      {{- include "my-chart.app" . | nindent 6 }}
      {{- include "my-chart.sidecar" . | nindent 6 }}

5. 使用“with”能少写一些字,但是也有利有弊。

使用”with”语句时,只能使用该范围内的变量,如果想要使用不同层次的变量,只能通过结束或重新定义来实现。
因此,前面提到在使用多个容器时可能需要分割模板,但是使用”with”语句时,也可能需要为每个范围定义变量。

{{- define "my-chart.sidecar" -}}
{{- with .Values.sidecar -}}
- image: "{{ .image.repository }}:{{ .image.tag | default "v1.0.2" }}"
  name: sidecar
  resources:
    requests:
      cpu: {{ .resources.requests.cpu | default "50m" }}
      memory: {{ .resources.requests.memory | default "50Mi" }}
    limits:
      cpu: {{ .resources.limits.cpu | default "100m" }}
      memory: {{ .resources.limits.memory | default "100Mi" }}
  ports:
  - containerPort: 24224
    name: sidecar
    protocol: "TCP"
  env:
  - name: SIDECAR_WEB_HOST
    value: "localhost:9990"
{{- end -}}
{{- end -}}

6. 模板的嵌套和with的嵌套

模板的嵌套可以很普遍地实现。缩进会被继承,因此在下面的例子中是6 + 2。(因为在上面示例中的deployment中的{{- include “my-chart.app” . | nindent 6 }})

{{- define "my-chart.app" -}}
{{- with .Values.app -}}
- name: app
  image: "{{ .image.repository }}:{{ .image.tag }}"
  ports:
    - name: http
      containerPort: 80
      protocol: TCP
  livenessProbe:
    httpGet:
      path: /
      port: http
  readinessProbe:
    httpGet:
      path: /
      port: http
  resources:
    requests:
      cpu: {{ .resources.requests.cpu | default "100m" }}
      memory: {{ .resources.requests.memory | default "500Mi" }}
    limits:
      cpu: {{ .resources.limits.cpu | default "100m" }}
      memory: {{ .resources.limits.memory | default "500Mi" }}
  env:
    {{- include "my-chart.app.env" . | nindent 2 }}
{{- end -}}
{{- end -}}

然而,由于使用“with”的范围仍然是父级的,所以在.Values.app的模板中进行include时,它将成为.Values.app的范围。

{{- define "my-chart.app.env" -}}
# .Values.app.envではない
{{- with .env -}}
env:
- name: APP_ENVIRONMENT
  value: {{ .APP_ENVIRONMENT | quote }}
- name: WRK_WARMUP_DURATION
  value: {{ .WRK_WARMUP_DURATION | default "10" | quote }}
{{- end -}}
{{- end -}}

8. Values的键是必需的。

CPU:即使设置了默认值(”100m”),变量文件中还必须始终将requests写成如下形式。

resources:
  requests: {}
  limits: {}

因此,如果将其按照上述方式分成多个容器并进行结构化,即使是对于默认值的情况,也不得不写更多的键。

environment: dev

replicas: 3

app:
  image:
    repository: nginx
    tag: stable
  resources:
    requests: {}
    limits: {}
  env:
    APP_ENVIRONMENT: dev

sidecar:
  image:
    repository: fluentd
    tag: stable
  resources:
    requests: {}
    limits: {}

hpa:
  enabled: false

最后
最终
最后

设计变量和模板的设计是一个让人头疼的问题。目前还在摸索中…

广告
将在 10 秒后关闭
bannerAds