In this tutorial, we'll briefly discuss how Helm can help simplify the management of Kubernetes applications and learn how to use Helm to create a basic chart.
Application management is a complex aspect of Kubernetes. Helm makes it much easier by providing a unified software packaging method that supports version control. Helm installs and manages packages (called Charts in Helm) for Kubernetes, just like yum and apt do.
In this tutorial, we'll let Helm create a basic chart for us. This tutorial assumes that you have at least a basic understanding of what Helm is. If you are not familiar with it, I suggest you read this tutorial before starting the article: https://www.alibabacloud.com/help/doc-detail/86511.htm
We'll then tweak it incrementally to see how the values ββfile and template parts work together.
With such a basic working chart, it's easier to work with than starting from scratch.
Chart is a Helm package. It contains all the resource definitions required to run an application, tool, or service within a Kubernetes cluster.
Think of it as the Kubernetes equivalent of a Homebrew formula, an Apt dpkg, or a Yum RPM file.
Creating a complete work chart directory structure
helm create myhelm1 Creating myhelm1
This creates a complete working chart with all the required files in the myhelm directory.
myhelm1/ | |- .helmignore # Contains patterns for files to ignore when packaging Helm charts. | |- Chart.yaml # Meta Information about your chart | |- values.yaml # The default values for your templates | |- charts/ # Charts that this chart depends on: dependencies | |- templates/ # The template files
You will be presented with some of these files throughout this tutorial - only when we need to know about those specific files.
The goal is to use the chart as soon as possible to create a working instance. We then investigate what the chart created and how it did it.
The file comes first values.yaml
. It contains our defaults for the Kubernetes objects we want to create.
, nginx
. 55 . busybox
β 650 .
values.yaml
nano ./myhelm1/values.yaml # Default values for myhelm1. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: nginx tag: stable pullPolicy: IfNotPresent
values.yaml
, busybox, . .
nano ./myhelm1/values.yaml # Default values for myhelm1. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: radial/busyboxplus tag: base pullPolicy: IfNotPresent
deployment.yaml
.
(deployment), , Kubernetes. , .
deployment.yaml
27 β . busybox. , , . busybox
60 .
( , values.yaml
. β .)
nano ./myhelm1/templates/deployment.yaml spec: containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} command: ['sh', '-c', 'sleep 60']
Helm .
helm install ./myhelm1/
.
helm install ./myhelm1/ NAME: loopy-otter LAST DEPLOYED: Thu Feb 14 08:48:42 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE loopy-otter-myhelm1 ClusterIP 10.109.163.87 <none> 80/TCP 0s ==> v1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE loopy-otter-myhelm1 1 0 0 0 0s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE loopy-otter-myhelm1-67b67bf4c8-tsdcq 0/1 Pending 0 0s NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=myhelm1,app.kubernetes.io/instance=loopy-otter" -o jsonpath="{.items[0].metadata.name}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl port-forward $POD_NAME 8080:80
Helm : NAME: loopy-otter
. . .
, .
, Helm .yaml
, , values.yaml
.
nginx. busybox
.
NOTES.txt, .
, Pod .
kubectl get pods NAME READY STATUS RESTARTS AGE loopy-otter-myhelm1-67b67bf4c8-tsdcq 0/1 Running 0 13s
. helm delete
, .
helm delete loopy-otter release "loopy-otter" deleted
helmignore NOTES.txt
.helmignore
NOTES.txt
.
.helmignore
, Helm .
nano ./myhelm1/.helmignore NOTES.txt
, , .
helm install .\myhelm1\ --name test1 NAME: test1 LAST DEPLOYED: Thu Feb 14 08:56:10 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE test1-myhelm1 ClusterIP 10.96.102.116 <none> 80/TCP 0s ==> v1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE test1-myhelm1 1 0 0 0 0s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE test1-myhelm1-6f77bf4459-9nxpz 0/1 ContainerCreating 0 0s
( , .)
test1.
helm delete test1 release "test1" deleted
--dry-run --debug
--dry-run
--debug
, , Helm YAML .
Kubernetes .
.
helm install .\myhelm1\ --name test1 --dry-run --debug [debug] Created tunnel using local port: '49958' [debug] SERVER: "127.0.0.1:49958" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 Error: a release named test1 already exists. Run: helm ls --all test1; to check the status of the release Or run: helm del --purge test1; to delete it
, .
release
helm ls --all test1 NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE test1 1 Thu Feb 14 08:56:10 2019 DELETED myhelm1-0.1.0 1.0 default
.
(debug
) : test2:
helm install .\myhelm1\ --name test2 --dry-run --debug [debug] Created tunnel using local port: '49970' [debug] SERVER: "127.0.0.1:49970" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test2 REVISION: 1 RELEASED: Thu Feb 14 08:59:22 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: affinity: {} fullnameOverride: "" image: pullPolicy: IfNotPresent repository: radial/busyboxplus tag: base ingress: annotations: {} enabled: false hosts: - chart-example.local paths: [] tls: [] nameOverride: "" nodeSelector: {} replicaCount: 1 resources: {} service: port: 80 type: ClusterIP tolerations: [] HOOKS: --- # test2-myhelm1-test-connection apiVersion: v1 kind: Pod metadata: name: "test2-myhelm1-test-connection" labels: app.kubernetes.io/name: myhelm1 helm.sh/chart: myhelm1-0.1.0 app.kubernetes.io/instance: test2 app.kubernetes.io/managed-by: Tiller annotations: "helm.sh/hook": test-success spec: containers: - name: wget image: busybox command: ['wget'] args: ['test2-myhelm1:80'] restartPolicy: Never MANIFEST: --- # Source: myhelm1/templates/service.yaml apiVersion: v1 kind: Service metadata: name: test2-myhelm1 labels: app.kubernetes.io/name: myhelm1 helm.sh/chart: myhelm1-0.1.0 app.kubernetes.io/instance: test2 app.kubernetes.io/managed-by: Tiller spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/name: myhelm1 app.kubernetes.io/instance: test2 --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test2-myhelm1 labels: app.kubernetes.io/name: myhelm1 helm.sh/chart: myhelm1-0.1.0 app.kubernetes.io/instance: test2 app.kubernetes.io/managed-by: Tiller spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: myhelm1 app.kubernetes.io/instance: test2 template: metadata: labels: app.kubernetes.io/name: myhelm1 app.kubernetes.io/instance: test2 spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: IfNotPresent command: ['sh', '-c', 'sleep 60'] ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {}
, , .
, .
. nginx. .
20 # Source: myhelm1/templates/service.yaml ... kind: Service
β β Pod.
, .helmignore .
nano ./myhelm1/.helmignore test-connection.yaml service.yaml
busybox livenessProbes.
29 42 deployment.yaml
nano ./myhelm1/templates/deployment.yaml ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {}
, helm install
.
labels: app.kubernetes.io/name: myhelm1 helm.sh/chart: myhelm1-0.1.0 app.kubernetes.io/instance: test4 app.kubernetes.io/managed-by: Tiller selector: matchLabels: app.kubernetes.io/name: myhelm1 app.kubernetes.io/instance: test4 metadata: labels: app.kubernetes.io/name: myhelm1 app.kubernetes.io/instance: test4
.
helm install .\myhelm1\ --name test2 --dry-run --debug [debug] Created tunnel using local port: '49976' [debug] SERVER: "127.0.0.1:49976" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test2 REVISION: 1 RELEASED: Thu Feb 14 09:09:55 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: affinity: {} fullnameOverride: "" image: pullPolicy: IfNotPresent repository: radial/busyboxplus tag: base ingress: annotations: {} enabled: false hosts: - chart-example.local paths: [] tls: [] nameOverride: "" nodeSelector: {} replicaCount: 1 resources: {} service: port: 80 type: ClusterIP tolerations: [] HOOKS: MANIFEST: --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test2-myhelm1 spec: replicas: 1 template: spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: IfNotPresent command: ['sh', '-c', 'sleep 60']
:
- USER-SUPPLIED VALUES: , . .
- COMPUTED VALUES:
values.yaml
. , . - HOOKS: .
-
deployment.yaml
. ,values.yaml
.
--dry-run --debug
. , , . : Helm , .
, .
helm install .\myhelm1\ --name test2 NAME: test2 LAST DEPLOYED: Thu Feb 14 09:12:01 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE test2-myhelm1 1 0 0 0 0s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE test2-myhelm1-5bd9bb65c7-6pr4q 0/1 ContainerCreating 0 0s
β Pod. Pod .
kubectl get pods NAME READY STATUS RESTARTS AGE test2-myhelm1-5bd9bb65c7-6pr4q 1/1 Running 0 10s
helm delete test2 release "test2" deleted
imagePullPolicy = Never
values.yaml
(placeholders) .
. , , --set
.
imagePullPolicy .
, .
values.yaml.
nano ./myhelm1/values.yaml # Default values for myhelm1. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: radial/busyboxplus tag: base pullPolicy: IfNotPresent
, . ( 22-25)
nano ./myhelm1/templates/deployment.yaml containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }}
.Values.image.pullPolicy
-
values.yaml
-
.image.pullPolicy
image: pullPolicy: IfNotPresent
pullPolicy: IfNotPresent
. (, , .)
, , . (imagePullPolicy: Never
)
Kubernetes:
imagePullPolicy: Never: , . .
, --set
.
helm install .\myhelm1\ --set imagePullPolicy=Never --name test3 --dry-run --debug [debug] Created tunnel using local port: '50101' [debug] SERVER: "127.0.0.1:50101" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test3 REVISION: 1 RELEASED: Thu Feb 14 10:10:37 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: imagePullPolicy: Never COMPUTED VALUES: affinity: {} fullnameOverride: "" image: pullPolicy: IfNotPresent repository: radial/busyboxplus tag: base imagePullPolicy: Never ingress: annotations: {} enabled: false hosts: - chart-example.local paths: [] tls: [] nameOverride: "" nodeSelector: {} replicaCount: 1 resources: {} service: port: 80 type: ClusterIP tolerations: [] HOOKS: MANIFEST: --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test3-myhelm1 spec: replicas: 1 template: spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: IfNotPresent command: ['sh', '-c', 'sleep 60']
USER-SUPPLIED VALUES : imagePullPolicy: Never
COMPUTED VALUES: :
image: pullPolicy: IfNotPresent tag: base imagePullPolicy: Never
--set
.
yaml.
: imagePullPolicy: IfNotPresent
: .
: :
helm install .\myhelm1\ --set image.PullPolicy=Never --name test3 --dry-run --debug [debug] Created tunnel using local port: '50107' [debug] SERVER: "127.0.0.1:50107" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test3 REVISION: 1 RELEASED: Thu Feb 14 10:14:11 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: image: PullPolicy: Never < - - - - - - COMPUTED VALUES: affinity: {} fullnameOverride: "" image: PullPolicy: Never < - - - - - - pullPolicy: IfNotPresent < - - - - - - repository: radial/busyboxplus
, . , -. ( β , ).
, , . values.yaml . .
, .
helm install .\myhelm1\ --set image.pullPolicy=Never --name test3 --dry-run --debug [debug] Created tunnel using local port: '50113' [debug] SERVER: "127.0.0.1:50113" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test3 REVISION: 1 RELEASED: Thu Feb 14 10:15:10 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: image: pullPolicy: Never < - - - - - - - - - - - - - COMPUTED VALUES: affinity: {} fullnameOverride: "" image: pullPolicy: Never repository: radial/busyboxplus tag: base ingress: annotations: {} enabled: false hosts: - chart-example.local paths: [] tls: [] nameOverride: "" nodeSelector: {} replicaCount: 1 resources: {} service: port: 80 type: ClusterIP tolerations: [] HOOKS: MANIFEST: --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test3-myhelm1 spec: replicas: 1 template: spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: Never < - - - - - - - - - - - command: ['sh', '-c', 'sleep 60']
, imagePullPolicy: Never
β¦ .
COMPUTED VALUES , .
COMPUTED VALUES: image: pullPolicy: Never
. .
, . , 5 .
nano ./myhelm1/values.yaml # Default values for myhelm1. # This is a YAML-formatted file. # Declare variables to be passed into your templates. replicaCount: 1 image: repository: radial/busyboxplus tag: base pullPolicy: IfNotPresent #nameOverride: "" #fullnameOverride: "" #service: # type: ClusterIP # port: 80 #ingress: # enabled: false # annotations: {} # kubernetes.io/ingress.class: nginx # kubernetes.io/tls-acme: "true" # paths: [] # hosts: # - chart-example.local # tls: [] # - secretName: chart-example-tls # hosts: # - chart-example.local #resources: {} # We usually recommend not to specify default resources and to leave this as a conscious # choice for the user. This also increases chances charts run on environments with little # resources, such as Minikube. If you do want to specify resources, uncomment the following # lines, adjust them as necessary, and remove the curly braces after 'resources:'. # limits: # cpu: 100m # memory: 128Mi # requests: # cpu: 100m # memory: 128Mi #nodeSelector: {} #tolerations: [] #affinity: {}
helm install .\myhelm1\ --set image.pullPolicy=Never --name test3 --dry-run --debug [debug] Created tunnel using local port: '50125' [debug] SERVER: "127.0.0.1:50125" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 Error: render error in "myhelm1/templates/ingress.yaml": template: myhelm1/templates/ingress.yaml:1:14: executing "myhelm1/templates/ingress.yaml" at <.Values.ingress.enab...>: can't evaluate field enabled in type interface {}
Values.ingress.enabled
myhelm1/templates/ingress.yaml
ingress β nginx, .
ingress.yaml
.
nano ./myhelm1/.helmignore ingress.yaml
: myhelm1 image.pullPolicy = Never
--set replicaCount=3
helm install .\myhelm1\ --set image.pullPolicy=Never --set replicaCount=3 --name test3 --dry-run --debug [debug] Created tunnel using local port: '50140' [debug] SERVER: "127.0.0.1:50140" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test3 REVISION: 1 RELEASED: Thu Feb 14 10:23:43 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: image: pullPolicy: Never < * * * = = = = = = = = = = = = = replicaCount: 3 < - - - - - - - - - - - - - - - - COMPUTED VALUES: image: pullPolicy: Never < * * * = = = = = = = = = = = = = repository: radial/busyboxplus tag: base replicaCount: 3 < - - - - - - - - - - - - - - - - HOOKS: MANIFEST: --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test3-myhelm1 spec: replicas: 3 < - - - - - - - - - - - - - - - - - - template: spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: Never < * * * = = = = = = = = = = = = = command: ['sh', '-c', 'sleep 60']
--set replicaCount
deployment.yaml
.
helm install .\myhelm1\ --set image.pullPolicy=Never --set replicaCount=3 --name test3 NAME: test3 LAST DEPLOYED: Thu Feb 14 10:34:45 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE test3-myhelm1 3 0 0 0 0s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE test3-myhelm1-878d8d7c-7xshs 0/1 Pending 0 0s test3-myhelm1-878d8d7c-fnjqn 0/1 ContainerCreating 0 0s test3-myhelm1-878d8d7c-gjw4m 0/1 Pending 0 0s
. β 3, , 3 .
3 . helm status
.
helm status test3 LAST DEPLOYED: Thu Feb 14 10:34:45 2019 NAMESPACE: default STATUS: DEPLOYED RESOURCES: ==> v1/Deployment NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE test3-myhelm1 3 3 3 3 20s ==> v1/Pod(related) NAME READY STATUS RESTARTS AGE test3-myhelm1-878d8d7c-7xshs 1/1 Running 0 20s test3-myhelm1-878d8d7c-fnjqn 1/1 Running 0 20s test3-myhelm1-878d8d7c-gjw4m 1/1 Running 0 20s
. test3.
helm delete test3 release "test3" deleted
value
values.yaml
.
.
: terminationGracePeriodSeconds
terminationGracePeriodSeconds β , . grace period β , , , , , . , . 30 .
terminationGracePeriodSeconds: 30
values.yaml
, 5β12 , :
nano ./myhelm1/values.yaml replicaCount: 1 terminationGracePeriodSeconds: 30 image: repository: radial/busyboxplus tag: base pullPolicy: IfNotPresent
, ( 22 29 , )
nano ./myhelm1/templates/deployment.yaml containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} command: ['sh', '-c', 'sleep 60']
.
helm install .\myhelm1\ --name test4 --dry-run --debug [debug] Created tunnel using local port: '50239' [debug] SERVER: "127.0.0.1:50239" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test4 REVISION: 1 RELEASED: Thu Feb 14 10:54:58 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: {} COMPUTED VALUES: image: pullPolicy: IfNotPresent repository: radial/busyboxplus tag: base replicaCount: 1 terminationGracePeriodSeconds: 30 < - - - - - - - HOOKS: MANIFEST: --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test4-myhelm1 spec: replicas: 1 template: spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: IfNotPresent terminationGracePeriodSeconds: 30 < - - - - - - command: ['sh', '-c', 'sleep 60']
. COMPUTED VALUES: .
: , terminationGracePeriodSeconds
10.
helm install .\myhelm1\ --set terminationGracePeriodSeconds=10 --name test4 --dry-run --debug [debug] Created tunnel using local port: '50245' [debug] SERVER: "127.0.0.1:50245" [debug] Original chart version: "" [debug] CHART PATH: C:\k8\myhelm1 NAME: test4 REVISION: 1 RELEASED: Thu Feb 14 10:56:33 2019 CHART: myhelm1-0.1.0 USER-SUPPLIED VALUES: terminationGracePeriodSeconds: 10 < - - - - - - COMPUTED VALUES: image: pullPolicy: IfNotPresent repository: radial/busyboxplus tag: base replicaCount: 1 terminationGracePeriodSeconds: 10 < - - - - - - HOOKS: MANIFEST: --- # Source: myhelm1/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: test4-myhelm1 spec: replicas: 1 template: spec: containers: - name: myhelm1 image: "radial/busyboxplus:base" imagePullPolicy: IfNotPresent terminationGracePeriodSeconds: 10 < - - - - - - command: ['sh', '-c', 'sleep 60']
. COMPUTED VALUES: 10
10.
_helpers.tpl
. ( . .)
, .
. (.helmignore
)
At work, you will create your own skeletal base charts from which you will copy.
We learned the basic concepts of Helm on the very first day, modifying the chart nginx
to suit our requirements. --dry-run --debug
- best Helm feature: trial run and debug before installation.