1. Overview
Written earlier Syntax overview of JenkinsPipeline and Summary of Dockerfile syntax And recently picked up Helm Chart again, just recalling its grammar~
Helm is a package management tool in k8s that can be used to deploy k8s resources. The core of Helm is the template, which is the templated k8s manifests file
It is essentially a template for Go. Helm adds a lot to the Go template template. Some examples include custom metadata information, extended libraries, and workflows like programming, such as conditional statements, pipelines, and so on. These things will make templates richer
With templates, how to incorporate configurations is the values.yaml file
2. Debugging
Helm also provides--dry-run--debug debugging parameters to help verify the correctness of the template. With these two parameters when executing helm install, you can print out the corresponding values values and rendered resource lists without actually deploying a release
For example, debug a chart package you created:
# helm install web --dry-run /root/mychart
3. Built-in Objects
Use {{Release.Name}} to insert the name of the release into the template. Here, Release is Helm's built-in object. Here are some common built-in objects
Release.Name | release name |
---|---|
Release.Name | release name |
Release.Namespace | release namespace |
Release.Service | Name of release service |
Release.Revision | release revision number, cumulative from 1 |
4,Values
The Values object provides values for the Chart template, and the value of this object comes from four sources
-
The values.yaml file in the chart package
-
The values.yaml file of the parent chart package
-
Custom yaml files passed in through the helm install or helm upgrade's -f or--values parameters
-
Value passed in through--set parameter
The values provided by chart.yaml can be overwritten by a user-provided values file, which can also be overwritten by a parameter provided by--set
Edit the mychart/values.yaml file, empty all default values, and add a copy number
# cat values.yaml replicas: 3 image: "nginx" imageTag: "1.17" # cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-deployment spec: replicas: {{ .Values.replicas }} selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: {{ .Values.image }}:{{ .Values.imageTag }} name: nginx
View rendering results:
# helm install --dry-run web ../mychart/
values files can also contain structured content, such as
# cat values.yaml ... label: project: ms app: nginx # cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-deployment spec: replicas: {{ .Values.replicas }} selector: matchLabels: project: {{ .Values.label.project }} app: {{ .Values.label.app }} template: metadata: labels: project: {{ .Values.label.project }} app: {{ .Values.label.app }} spec: containers: - image: {{ .Values.image }}:{{ .Values.imageTag }} name: nginx
View rendering results:
# helm install --dry-run web ../mychart/
5. Pipelines and Functions
The related modules mentioned earlier actually pass the value to the template engine for rendering, and the template engine also supports the secondary processing of getting data
For example, a value read from.Values becomes a string and can be implemented using the quote function
# vi templates/deployment.yaml app: {{ quote .Values.label.app }} # helm install --dry-run web ../mychart/ project: ms app: "nginx"
Quote.Values.label.app passes the following values as parameters to the quote function
The template function call syntax is: functionName arg1 arg2...
A default function is also frequently used that allows you to specify a default value in a template to prevent it from being ignored
For example, if you forget to define, executing helm install will fail to create resources due to missing fields, then you can define a default value
# cat values.yaml replicas: 2 # cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: - name: {{ .Values.name | default "nginx" }}
Other Common Functions
-
Indent: {{Values.resources | indent 12}}
-
Uppercase: {{upper.Values.resources}}
-
Capitalize: {{title.Values.resources}}
6. Process Control
Process control provides a capability for templates to handle more complex data logic
The Helm template language provides the following process control statements
- if/else conditional block
- with specified range
- range loop block
6.1 if
if/else blocks are the method used to conditionally include text blocks in a template, and the basic structure of conditional blocks is as follows
{{ if PIPELINE }} # Do something {{ else if OTHER PIPELINE }} # Do something else {{ else }} # Default case {{ end }}
Example
# cat values.yaml devops: k8 # cat templates/deployment.yaml ... template: metadata: labels: app: nginx {{ if eq .Values.devops "k8s" }} devops: 123 {{ else }} devops: 456 {{ end }}
In addition to the eq operator used in the above conditional statement to determine equality, the ne, lt, gt, and or operators are also supported
Rendering with the template engine yields the following results
# helm install --dry-run web ../mychart/ ... labels: app: nginx devops: 456
You can see that there will be extra blank lines when rendered because when the template engine runs, the control instructions will be deleted and all previously occupied positions will be blank, requiring the {-if...} method to eliminate this blank line
# cat templates/deploymemt.yaml ... env: {{- if eq .Values.env.hello "world" }} - name: hello value: 123 {{- end }}
There are no extra spaces now, so be careful if you use -}, such as in the template file above
# cat templates/deploymemt.yaml ... env: {{- if eq .Values.env.hello "world" -}} - hello: true {{- end }}
This renders as:
env:- hello: true
Because -} it deletes line breaks for both parties
A conditional judgment is a judgment of whether a condition is true or false if the value is
-
A false boolean type
-
One Number Zero
-
An empty string
-
A nil (empty or null)
-
An empty collection (map, slice, tuple, dict, array)
All but the above are true
For example, determine an empty array
# cat values.yaml resources: {} # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi # cat templates/deploymemt.yaml ... spec: containers: - image: nginx:1.16 name: nginx {{- if .Values.resources }} resources: {{ toYaml .Values.resources | indent 10 }} {{- end }}
For example, determine a Boolean value
# cat values.yaml service: type: ClusterIP port: 80 ingress: enabled: true host: example.ssgeek.com # cat templates/ingress.yaml {{- if .Values.ingress.enabled -}} apiVersion: networking.k8s.io/v1beta1 kind: Ingress metadata: name: {{ .Release.Name }}-ingress spec: rules: - host: {{ .Values.ingress.host }} http: paths: - path: / backend: serviceName: {{ .Release.Name }} servicePort: {{ .Values.service.port }} {{ end }}
6.2 with
with: controls the scope of variables
Previous {{Release.xxx}} or {{Values.xxx}}, where.Is a reference to the current scope and.Values is a value that tells the template to look for Values objects in the current scope. The with statement controls the scope of the variable, and its syntax is similar to a simple if statement
{{ with PIPELINE }} # restricted scope {{ end }}
The with statement allows you to set the current range. to a specific object, such as.Values.label, which you have been using previously. You can use with to point the. range to.Values.label
# cat values.yaml ... replicas: 3 label: project: ms app: nginx # cat templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-deployment spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: {{- with .Values.nodeSelector }} nodeSelector: team: {{ .team }} gpu: {{ .gpu }} {{- end }} containers: - image: nginx:1.16 name: nginx
After optimization
{{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} {{- end }}
A {{-with.Values.label}} XXX {{-end}} block has been added above so that.team and.gpu can be referenced directly within the current block.
with is a cyclic construct. Use the value in Values.nodeSelector: convert it to Yaml
The point after toYaml is the current value of the.Values.nodeSelector in the loop
6.3 range
In Helm template language, use range keyword for looping operations
Add the previous list of variables to the values.yaml file
# cat values.yaml test: - 1 - 2 - 3
Print the list in a loop
apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }} data: test: | {{- range .Values.test }} {{ . }} {{- end }}
Inside the loop is a., because the current scope is within the current loop, which references the currently read element
7. Variables
This is the basic concept in language: variables, which are not used in many cases in templates, but you can see how to use them to simplify your code and make better use of with and range, for example
Example 1: Get list key values
# cat ../values.yaml env: NAME: "gateway" JAVA_OPTS: "-Xmx1G" # cat deployment.yaml ... env: {{- range $k, $v := .Values.env }} - name: {{ $k }} value: {{ $v | quote }} {{- end }}
give the result as follows
env: - name: JAVA_OPTS value: "-Xmx1G" - name: NAME value: "gateway"
The above uses the $key and $value variables in the range loop to receive keys and values for subsequent list loops
Example 2: Built-in objects cannot be used in with
Release.Name objects can no longer be in the with statement block, otherwise an error is reported
You can solve this problem by assigning the object to a variable
apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-deployment spec: replicas: {{ .Values.replicas }} template: metadata: labels: project: {{ .Values.label.project }} app: {{ quote .Values.label.app }} {{- with .Values.label }} project: {{ .project }} app: {{ .app }} release: {{ .Release.Name }} {{- end }}
Error above
{{- $releaseName := .Release.Name -}} {{- with .Values.label }} project: {{ .project }} app: {{ .app }} release: {{ $releaseName }} # Or you can use the $symbol to introduce a global namespace release: {{ $.Release.Name }} {{- end }}
You can see that a sentence {{-$releaseName:=.Release.Name-} has been added to the with statement, where $releaseName is a reference variable to the following object in the form of $name, and the assignment operation uses: =, so the $releaseName variable inside the with statement block still points to.Release.Name
8. Naming Templates
Named Template: Defined by define, introduced by template, underlined by default in templates directory_ The starting file is a public template (_helpers.tpl)
# cat _helpers.tpl {{- define "demo.fullname" -}} {{- .Chart.Name -}}-{{ .Release.Name }} {{- end -}} # cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ template "demo.fullname" . }} ...
The template directive is a way to include one template in another. However, the template function cannot be used in the Go template pipeline. To solve this problem, add include functionality
# cat _helpers.tpl {{- define "demo.labels" -}} app: {{ template "demo.fullname" . }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" release: "{{ .Release.Name }}" {{- end -}} # cat deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "demo.fullname" . }} labels: {{- include "demo.labels" . | nindent 4 }} ...
It contains a template named demo.labels, passes the value.to the template, and passes the output of the template to the nindent function
9. Process for Chart Development
Create a template first
helm create demo
Modify Chart.yaml, Values.yaml, and add commonly used variables
Create the yaml file needed to deploy the image in the templates directory, and the variable references the frequently changing fields in yaml
More can be referred to Official Documents
See you ~
Pay attention to the public numbers and share more original dry goods with you~