Consejos y Trucos para el Desarrollo de Charts
Esta guía cubre algunos de los consejos y trucos que los desarrolladores de charts de Helm han aprendido al crear charts con calidad de producción.
Conozca las funciones de plantilla
Helm usa plantillas Go para crear plantillas para sus archivos de recursos. Si bien Go incluye varias funciones integradas, hemos agregado muchas otras.
Primero, agregamos todas las funciones en la biblioteca Sprig.
También agregamos dos funciones de plantilla especiales: include
y
required
. La función include
le permite traer otra plantilla y luego pasar
los resultados a otras funciones de la plantilla.
Por ejemplo, este fragmento de plantilla incluye una plantilla llamada mytpl
,
luego pone el resultado en minúsculas y luego lo envuelve entre comillas dobles.
value: {{ include "mytpl" . | lower | quote }}
La función required
le permite declarar una entrada de valores particulares según
sea necesario para la representación de la plantilla. Si el valor está vacío,
la representación de la plantilla fallará con un mensaje de error enviado al
usuario.
The following example of the required
function declares an entry for
.Values.who is required, and will print an error message when that entry is
missing:
El siguiente ejemplo de la función required
declara que una entrada para
.Values.who es obligatoria e imprimirá un mensaje de error cuando falte esa entrada:
value: {{ required "A valid .Values.who entry required!" .Values.who }}
Envuelve en comillas Candeas, no Enteros
Cuando trabaja con cadenas de carácteres, siempre es más seguro envolverlas entre comillas dobles que dejarlas como palabras sueltas:
name: {{ .Values.MyName | quote }}
Pero cuando trabaje con números enteros, no envuelva entre comillas dobles los valores. Eso puede, en muchos casos, causar errores de análisis dentro de Kubernetes.
port: {{ .Values.Port }}
Esta observación no se aplica a los valores de las variables de entorno que se espera que sean cadenas, incluso si representan números enteros:
env:
- name: HOST
value: "http://host"
- name: PORT
value: "1234"
Utilizar la Función 'include'
Go proporciona una forma de incluir una plantilla en otra utilizando la directiva
incorporada template
. Sin embargo, la directiva incorporada no se puede utilizar
en las canalizaciones de plantilla de Go.
Para que sea posible incluir una plantilla y luego realizar una operación en la
salida de esa plantilla, Helm tiene una función include
especial:
{{ include "toYaml" $value | indent 2 }}
Lo anterior incluye una plantilla llamada toYaml
, le pasa $value
y luego pasa
la salida de esa plantilla a la función indent
.
Debido a que YAML atribuye importancia a los niveles de sangría y los espacios en blanco, esta es una excelente manera de incluir fragmentos de código, pero manejar la sangría en un contexto relevante.
Utilizar la Función 'required'
Go proporciona una forma de configurar opciones de plantilla para controlar el
comportamiento cuando un mapa se indexa con una clave que no está presente en el
mapa. Por lo general, esto se establece con template.Options("missingkey=option")
,
donde option
puede ser default
, zero
o error
. Si bien establecer esta opción
en error detendrá la ejecución con un error, esto se aplicaría a todas las claves
que faltan en el mapa. Puede haber situaciones en las que un desarrollador de charts
quiera aplicar este comportamiento para valores seleccionados en el archivo values.yaml
.
La función required
brinda a los desarrolladores la capacidad de declarar una
entrada de valor según sea necesario para la renderización de la plantilla. Si
la entrada está vacía en values.yaml
, la plantilla no se procesará y devolverá
un mensaje de error proporcionado por el desarrollador.
Por ejemplo:
{{ required "A valid foo is required!" .Values.foo }}
Lo anterior renderizará la plantilla cuando se defina .Values.foo
, pero fallará
en renderizar y se cerrará cuando .Values.foo
no esté definido.
Utilizar la Función 'tpl'
The tpl
function allows developers to evaluate strings as templates inside a
template. This is useful to pass a template string as a value to a chart or
render external configuration files. Syntax: {{ tpl TEMPLATE_STRING VALUES }}
La función tpl
permite a los desarrolladores evaluar cadenas como plantillas
dentro de una plantilla. Esto es útil para pasar una cadena de plantilla como
valor a un chart o representar archivos de configuración externos. Sintaxis:
{{tpl TEMPLATE_STRING VALUES}}
Ejemplos:
# valores
template: "{{ .Values.name }}"
name: "Tom"
# plantilla
{{ tpl .Values.template . }}
# salida
Tom
Renderizar un archivo de configuración externo:
# archivo de configuración externo conf/app.conf
firstName={{ .Values.firstName }}
lastName={{ .Values.lastName }}
# valores
firstName: Peter
lastName: Parker
# plantilla
{{ tpl (.Files.Get "conf/app.conf") . }}
# salida
firstName=Peter
lastName=Parker
Creando Image Pull Secrets
Los Image Pull Secrets son esencialmente una combinación de registro,
username y password. Es posible que los necesite en una aplicación que está
implementando, pero para crearlos es necesario ejecutar base64
un par de veces.
Podemos escribir una plantilla auxiliar para componer el archivo de configuración
de Docker y usarlo como carga útil del Secret. Aquí hay un ejemplo:
Primero, suponga que las credenciales están definidas en el archivo values.yaml
así:
imageCredentials:
registry: quay.io
username: someone
password: sillyness
email: someone@host.com
Luego definimos nuestra plantilla auxiliar de la siguiente manera:
{{- define "imagePullSecret" }}
{{- with .Values.imageCredentials }}
{{- printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" .registry .username .password .email (printf "%s:%s" .username .password | b64enc) | b64enc }}
{{- end }}
{{- end }}
Finalmente, usamos la plantilla auxiliar en una plantilla más grande para crear el manifiesto del Secret:
apiVersion: v1
kind: Secret
metadata:
name: myregistrykey
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "imagePullSecret" . }}
Despliegue de Deployments Automáticamente
Often times ConfigMaps or Secrets are injected as configuration files in
containers or there are other external dependency changes that require rolling
pods. Depending on the application a restart may be required should those be
updated with a subsequent helm upgrade
, but if the deployment spec itself
didn't change the application keeps running with the old configuration resulting
in an inconsistent deployment.
A menudo, los ConfigMaps o Secrets se inyectan como archivos de configuración en
contenedores o hay otros cambios de dependencia externa que requieren recrear pods.
Dependiendo de la aplicación, es posible que sea necesario reiniciar si se actualizan
con un helm upgrade
posterior, pero si el Deployments Spec en sí no cambia, la
aplicación sigue ejecutándose con la configuración anterior, lo que da como resultado
un despliegue inconsistente.
La función sha256sum
se puede utilizar para garantizar que la sección de
anotaciones de una implementación se actualice si cambia otro archivo:
kind: Deployment
spec:
template:
metadata:
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
[...]
En el caso de que siempre desee lanzar su Deployment, puede usar un paso de anotación similar al anterior, en lugar de reemplazarlo con una cadena aleatoria para que siempre cambie y haga que la implementación se lance:
kind: Deployment
spec:
template:
metadata:
annotations:
rollme: {{ randAlphaNum 5 | quote }}
[...]
Cada invocación de la función de plantilla generará una cadena aleatoria única. Esto significa que si es necesario sincronizar las cadenas aleatorias utilizadas por varios recursos, todos los recursos relevantes deberán estar en el mismo archivo de plantilla.
Ambos métodos permiten que su Deployment aproveche la lógica de la estrategia de actualización incorporada para evitar tener tiempo de inactividad.
NOTA: En el pasado, recomendamos usar la marca --recreate-pods
como otra opción.
Esta bandera se ha marcado como obsoleta en Helm 3 a favor del método más
declarativo anterior.
Dígale a Helm que No Desinstale un Recurso
A veces hay recursos que no deben desinstalarse cuando Helm ejecuta un
helm uninstall
. Los desarrolladores de charts pueden agregar una anotación
a un recurso para evitar que se desinstale.
kind: Secret
metadata:
annotations:
"helm.sh/resource-policy": keep
[...]
(Se requieren comillas)
La anotación "helm.sh/resource-policy": keep
indica a Helm que omita la
eliminación de este recurso cuando una operación de helm (como helm uninstall
,
helm upgrade
o helm rollback
) resulte en su eliminación. Sin embargo, este
recurso queda huérfano. Helm ya no lo administrará de ninguna manera. Esto puede
ocasionar problemas si se usa helm install --replace
en una versión que ya se
ha desinstalado, pero que ha conservado los recursos.
Utilizar "Parciales" (Partials) e Incluir Plantillas
A veces, desea crear algunas partes reutilizables en tus charts, ya sean bloques o parciales de plantilla. Y, a menudo, es más limpio mantenerlos en sus propios archivos.
En el directorio templates /
, no se espera que ningún archivo que comience con
un guión bajo (_
) genere un archivo de manifiesto de Kubernetes. Entonces, por
convención, las plantillas auxiliares y los parciales se colocan en un archivo
_helpers.tpl
.
Charts Complejos con Muchas Dependencias
Muchos de los charts de Artifact Hub de la CNCF son "bloques de construcción" para crear aplicaciones más avanzadas. Pero los charts pueden usarse para crear instancias de aplicaciones a gran escala. En tales casos, un solo chart general puede tener múltiples sub-charts, cada uno de los cuales funciona como una parte del todo.
The current best practice for composing a complex application from discrete
parts is to create a top-level umbrella chart that exposes the global
configurations, and then use the charts/
subdirectory to embed each of the
components.
La mejor práctica actual para componer una aplicación compleja a partir de partes
discretas es crear un chart general de nivel superior que exponga las configuraciones
globales, y luego usar el subdirectorio charts/
para incrustar cada uno de los
componentes.
YAML es un Superconjunto de JSON
Según la especificación YAML, YAML es un superconjunto de JSON. Eso significa que cualquier estructura JSON válida debería ser válida en YAML.
Esto tiene una ventaja: a veces, a los desarrolladores de plantillas les puede resultar más fácil expresar una estructura de datos con una sintaxis similar a JSON en lugar de lidiar con la sensibilidad de los espacios en blanco de YAML.
Como práctica recomendada, las plantillas deben seguir una sintaxis similar a YAML, a menos que la sintaxis JSON reduzca sustancialmente el riesgo de problemas de formato.
Tenga Cuidado con la Generación de Valores Aleatorios
Hay funciones en Helm que le permiten generar datos aleatorios, claves criptográficas, etc. Está bien usarlos. Pero tenga en cuenta que durante las actualizaciones, las plantillas se vuelven a ejecutar. Cuando la ejecución de una plantilla genera datos que difieren de la última ejecución, se activará una actualización de ese recurso.
Instalar o Actualizar un Release con un Comando
Helm proporciona una forma de realizar una instalación o actualización como un solo
comando. Utilice helm upgrade
con el comando --install
. Esto hará que Helm vea
si la versión ya está instalada. De lo contrario, ejecutará una instalación. Si es
así, se actualizará el Release existente.
$ helm upgrade --install <release name> --values <values file> <chart directory>