Primeros pasos con helm
- 26 kubernetes
- 2 helm
Introduccion
En este tutorial vamos a ver como usar Helm, el cluster de despliegue sera minikube si preferis kind or cualquier otro cluster deberia funcionar de la misma manera:
Creando el chart:
helm create hello-world
Siempre hay que tener en cuenta las restricciones de DNS a la hora de elegir nombres, ya que esto puede traer problemas despues.
Inspeccionemos el contenido, como podemos ver son recursos de kubernetes similar a los templates de go:
$ cd hello-world
charts <--- Dependencies, charts that your chart depends on.
Chart.yaml <--- Metadata mostly, defines the version of your chart, etc.
templates <--- Here is where the magic happens.
values.yaml <--- Default values file (this is used to replace in the templates at runtime)
Nota: este link explica lo basico de manejo de dependencias, tu chart puede tener varias dependencias, solo tienes que listarlas como dependencias.
El archivo values.yaml
por defecto se ve asi:
replicaCount: 1
image:
repository: nginx
tag: stable
pullPolicy: IfNotPresent
nameOverride: ""
fullnameOverride: ""
service:
type: ClusterIP
port: 80
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /
hosts:
- chart-example.local
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
resources: {}
nodeSelector: {}
tolerations: []
affinity: {}
El proximo paso es revisar la carpeta templates
:
deployment.yaml <--- Recurso deployment estandar de kubernetes con variables de go templates.
_helpers.tpl <--- En este archivo se definen funciones y variables comunes.
ingress.yaml <--- Recurso ingress.
NOTES.txt <--- Este archivo se usa para mostrar las notas una vez que termino el despliegue del chart.
service.yaml <--- Recurso service de kubernetes o balanceador de carga virtual interno.
Go templates basico, si necesitas refrescar go templates, siempre se puede ir a la documentacion.
Revisemos el archivo deployment:
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: {{ include "hello-world.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "hello-world.name" . }}
helm.sh/chart: {{ include "hello-world.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "hello-world.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
labels:
app.kubernetes.io/name: {{ include "hello-world.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
La mayoria de los campos se reemplazan con lo que pasemos via values.yaml
esto se pasa via .Values
a menos que uses
un helper o variable extra.
Sigamos con el archivo service:
apiVersion: v1
kind: Service
metadata:
name: {{ include "hello-world.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "hello-world.name" . }}
helm.sh/chart: {{ include "hello-world.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: {{ include "hello-world.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
Luego el archivo ingress:
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "hello-world.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app.kubernetes.io/name: {{ include "hello-world.name" . }}
helm.sh/chart: {{ include "hello-world.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . | quote }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
Este es probablemente el archivo mas interesante por que hace uso de variables locales, tambien itera sobre hosts
.
Desplegando nuestro chart:
$ helm install --name my-nginx -f values.yaml .
NAME: my-nginx
LAST DEPLOYED: Sun Dec 23 00:30:11 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME AGE
my-nginx-hello-world 0s
==> v1beta2/Deployment
my-nginx-hello-world 0s
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
my-nginx-hello-world-6f948db8d5-s76zl 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=hello-world,app.kubernetes.io/instance=my-nginx" -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
Nuestro despliegue parece exitoso, ya que vemos el pod con estado Pending inmediatamente.
Revisando el servicio:
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 1h
my-nginx-hello-world ClusterIP 10.111.222.70 <none> 80/TCP 5m
Podemos probar desde otro pod de manera interactiva si todo funciona correctamente:
$ kubectl run -i --tty alpine --image=alpine -- sh
If you don't see a command prompt, try pressing enter.
/ # apk add curl
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/main/x86_64/APKINDEX.tar.gz
fetch http://dl-cdn.alpinelinux.org/alpine/v3.8/community/x86_64/APKINDEX.tar.gz
(1/5) Installing ca-certificates (20171114-r3)
(2/5) Installing nghttp2-libs (1.32.0-r0)
(3/5) Installing libssh2 (1.8.0-r3)
(4/5) Installing libcurl (7.61.1-r1)
(5/5) Installing curl (7.61.1-r1)
Executing busybox-1.28.4-r2.trigger
Executing ca-certificates-20171114-r3.trigger
OK: 6 MiB in 18 packages
/ # curl -v my-nginx-hello-world
* Rebuilt URL to: my-nginx-hello-world/
* Trying 10.111.222.70...
* TCP_NODELAY set
* Connected to my-nginx-hello-world (10.111.222.70) port 80 (#0)
> GET / HTTP/1.1
> Host: my-nginx-hello-world
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.14.2
< Date: Sun, 23 Dec 2018 03:45:31 GMT
< Content-Type: text/html
< Content-Length: 612
< Last-Modified: Tue, 04 Dec 2018 14:44:49 GMT
< Connection: keep-alive
< ETag: "5c0692e1-264"
< Accept-Ranges: bytes
<
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
* Connection #0 to host my-nginx-hello-world left intact
y voila, como podemos ver nuestro chart de nginx funciona perfectamente.
Podemos verificar el estado via helm de esta manera:
$ helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
my-nginx 1 Sun Dec 23 00:30:11 2018 DEPLOYED hello-world-0.1.0 1.0 default
Actualizemos nuestro despliegue cambiando el tag
en el archivo values.yaml
de stable
a mainline
y tambien actualizemos la metadata en Chart.yaml
para mantener la version de nuestro chart en buenas condiciones.
$ helm upgrade my-nginx . -f values.yaml
Release "my-nginx" has been upgraded. Happy Helming!
LAST DEPLOYED: Sun Dec 23 00:55:22 2018
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
my-nginx-hello-world-6f948db8d5-s76zl 1/1 Running 0 25m
my-nginx-hello-world-c5cdcc95c-shgc6 0/1 ContainerCreating 0 0s
==> v1/Service
NAME AGE
my-nginx-hello-world 25m
==> v1beta2/Deployment
my-nginx-hello-world 25m
NOTES:
1. Get the application URL by running these commands:
export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=hello-world,app.kubernetes.io/instance=my-nginx" -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
Parece que todo salio bien, como podemos ver cambio la revision y la version del chart
$ helm ls
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
my-nginx 2 Sun Dec 23 00:55:22 2018 DEPLOYED hello-world-0.1.1 1.0 default
Ahora verifiquemos que la version de nginx es la que nosotros especificamos:
$ kubectl exec my-nginx-hello-world-c5cdcc95c-shgc6 -- /usr/sbin/nginx -v
nginx version: nginx/1.15.7
al momento de escribir esto la version mainline es 1.15.7, podemos hacer “rollback” si algo no salio bien con helm de esta manera:
$ helm rollback my-nginx 1
Rollback was a success! Happy Helming!
Hay varias formas de hacer rollback, en este caso para nuestro chart my-nginx
especificamos la revision a la que queremos hacer “rollback” y voila.
Revisemos la version de nginx de nuevo:
$ kubectl exec my-nginx-hello-world-6f948db8d5-bsml2 -- /usr/sbin/nginx -v
nginx version: nginx/1.14.2
Siempre es una buena idea limpiar todo cuando terminamos de probar algo:
$ helm del --purge my-nginx
release "my-nginx" deleted
Si necesitas depurar o ver los templates a medida que vas trabajando en ellos podes hacer lo siguiente:
$ helm template . -n name -f values.yaml
# Source: hello-world/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: name-hello-world
Y eso es todo por hoy, ante cualquier duda deja un comentario o revisa la documentacion y el comando helm help
.
DRY: Don’t Repeat Yourself
Lo bueno de usar templates es que podemos ahorrar mucho tiempo y a la vez mantener todo ordenado y sin mucha repeticion.
Upcoming topics
Algunos articulos que te pueden interesar:
- Expand on helm, search and install community charts.
- Getting started with Ksonnet and friends
- Getting started with Skaffold.
- Getting started with Gitkube.
Errata
Si ves algun error por favor enviame un mensaje para poder corregirlo.
No tienes cuenta? Regístrate aqui
Ya registrado? Iniciar sesión a tu cuenta ahora.
-
Comentarios
Online: 0
Por favor inicie sesión para poder escribir comentarios.