Les templates ytt
Ytt fait aussi partie de la suite carvel. Ytt est un outil de templating et d’applications de patch pour fichiers Yaml. Il n’est pas essentiellement utilisé pour écrire des manifests kubernetes mais peut être aussi utilisé avec d’autres outils dont les fichiers de configurations sont écrit en Yaml.
Installation de ytt
Comme pour les autres outils je vous montre comment installer toute la suite Carvel:
wget -O- https://carvel.dev/install.sh > install.shsudo bash install.shytt versionytt version 0.38.0
Fonctionnement de ytt
Ytt charge tous les documents, les analyse pour identifier leurs types et
calculer la sortie. Il existe différentes types de documents: les fichiers
plein, les templates et ses sous-types et les overlays. Pour différencier les
types de documents, il recherche tout simplement la présence de lignes contenant
des instructions ytt qui débute par #@
.
En noir le pipeline.
Les différents types de documents manipulés par ytt
Comme dis dans le descriptif du document ytt utilise différents types de documents :
-
Les
Data Values Schema Document
qui décrivent les variables ytt avec leur type et valeur par défaut :#@data/values-schema---instances: 1 -
Les
Data Values Document
qui fixent les valeurs des variables :#@data/values---instances: 8 -
Les
Templated Documents
:#@ load("@ytt:data", "data")---apiVersion: apps/v1kind: Deploymentmetadata:name: my-appspec:replicas: #@ data.values.instances... -
Les
Overlay Documents
qui sont appliqués tout à la fin du processus d’évaluation.#@ load("@ytt:overlay", "overlay")#@overlay/match by=overlay.subset({"kind": "Deployment", "metadata": {"name": "nginx-deployment"}})---spec:#! change spec.replicas to 3replicas: 3
Le langage ytt
Le langage ytt est dérivé de celui de starlark ↗, qui est un dialecte de Python destiné à être utilisé comme langage de configuration.
Les commentaires
Les commentaires débute par #!
:
#! Ceci est un commentaire
Les types manipulés par ytt
NoneType
: None (equivalent to null in other languages)Bool
: True or FalseInteger
: 1Float
: 1.1String
: “string”List
: [1, 2, {“a”:3}]Tuple
: (1, 2, “a”)Dictionary
: {“a”: 1, “b”: “b”}Struct
: struct.make(field1=123, field2=“val2”)Annotation
: @name arg1,arg2,keyword_arg3=123
Instructions de contrôles
Les conditions
On retrouve bien une syntaxe proche de python avec if else elif
en ajoutant le
@ end
:
#@ test = 123#@ if test > 100 and test < 200:test1: 123#@ elif test == 100 or test == 200:test2: 124#@ else:test3: 125#@ end
Les tests peuvent être écrits sur une seule ligne :
test1: #@ passwd if passwd else assert.fail("password must be set")
ou encore :
#@ if/end True:key3: nested_key: further_nesting: value1
Les boucles
On retrouve la boucle for
avec les instructions continue/break
. Sa
définition se termine avec @ end
:
array_odd:#@ for j in range(0,10):#@ if j % 2 == 0:#@ continue#@ end#@ if j > 5:#@ break#@ end- #@ j#@ end
Une boucle peut s’écrire sur une ligne :
#@ for/end val in [1,5,{"key":"val"}]:- item: #@ val
Les fonctions
On retrouve les instructions def
et return
. Ici une fonction créant un
deployement et utilisant des variables #@ <variable-name>
. Sa définition se
termine par @ end
:
#@ def my_deployment(name, replicas=1, labels={}):kind: Deploymentmetadata: name: #@ name labels: #@ labelsspec: replicas: #@ replicas#@ end
---kind: Listitems:- #@ my_deployment("dep1", replicas=3)
Vous avez remarqué nous retrouvons les paramètres optionnels de python qui doivent être nommé leur définition :
Load
La fonction load
permet de faire appel aux fonctions provenant :
- de modules démarrant par
@yt:
: - de documents écrits sous la forme yaml, text ou starlark :
#@ load("@ytt:overlay", "overlay") # load overlay module from builtin ytt library#@ load("@ytt:overlay", ov="overlay") # load overlay symbol under a different alias#@ load("helpers.star", "func1", "func2") # load func1, func2 from Starlark file#@ load("helpers.lib.yml", "func1", "func2") # load func1, func2 from YAML file#@ load("helpers.lib.txt", "func1", "func2") # load func1, func2 from text file#@ load("/dir/helpers.lib.yml", "func1") # load func1 from file relative to root of library#@ load("sub-dir/helpers.lib.txt", "func1") # load func1 from a sub-directory#@ load("@project:dir/helpers.lib.txt", "func1") # load func1 from a project located under _ytt_lib
Les fichiers .star sont des fichiers écrits en starlark :
# this file can only contain Starlark code, not YAML content# this restriction is based on the file extension
def func1(): return [1,2,{"key": "value"}]end
Écrire ses premiers templates Ytt
Maintenant que nous avons vu les bases de ce langage, passons à l’écriture d’un premier template (tiré de la documentation).
Nous allons déclarer nos variables dans le ficher de schema schema.yml
contenant deux définitions echos et service :
#@data/values-schema---echos:- name: "" port: 8080 text: "Hello #ytt World on 8080!"service: enabled: true
Créons un fichier de data default.yml
qui vient écraser les valeurs par
défaut :
#@data/values---echos:- name: first- name: second port: 8081 text: "Hello #ytt World on 8081!"
Créons le template lui-meme demo.yml
. Le code est expliqué par ses
commentaires.
#! On charge les valeurs depuis le fichier#@ load("@ytt:data", "data")
#! Une fonction retournant deux clés/valeurs#@ def labels():app: echoorg: test#@ end
#! Une autre fonction name retournant une string#@ def name(echo):#@ return "echo-"+echo.name#@ end
kind: PodapiVersion: v1metadata: name: echo-app #! Appel de la fonction labels labels: #@ labels()spec: containers: #! Une boucle écrite sur une ligne utilisant la variable echos définit dans le fichier de data #@ for/end echo in data.values.echos: - name: #@ name(echo) image: hashicorp/http-echo args: - #@ "-listen=:" + str(echo.port) - #@ "-text=" + echo.text
#@ if/end data.values.service.enabled:---kind: ServiceapiVersion: v1metadata: name: echo-servicespec: selector: #@ labels() ports: #@ for/end echo in data.values.echos: - name: #@ name(echo) port: #@ echo.port
Pour lancer l’évaluation de ce template il suffit de lancer ytt avec tous ces fichiers de définition (peu importe l’ordre) :
ytt -f default.yml -f schema.yml -f demo.yml# ou plus simplementytt -f ./
Ce qui nous donne :
kind: PodapiVersion: v1metadata: name: echo-app labels: app: echo org: testspec: containers: - name: echo-first image: hashicorp/http-echo args: - -listen=:8080 - '-text=Hello #ytt World on 8080!' - name: echo-second image: hashicorp/http-echo args: - -listen=:8081 - '-text=Hello #ytt World on 8081!'---kind: ServiceapiVersion: v1metadata: name: echo-servicespec: selector: app: echo org: test ports: - name: echo-first port: 8080 - name: echo-second port: 8081
Pour gérer plusieurs environnements, on pourrait créer plusieurs jeux de valeurs default-dev.yml default-prod.yml.
Regardez cet exemple : vmware-tanzu/carvel-ytt-starter-for-kubernetes ↗
Patcher des manifests kubernetes avec Ytt
L’utilisation la plus simple d’ytt est de l’utiliser pour patcher des fichiers
yaml. Nous allons voir comment l’utiliser pour patcher un manifest Kubernetes
récupérer avec vendir
.
Commençons par écrire la configuration vendir
qui se charge de récupérer le
manifest du deployment de pod nginx :
apiVersion: vendir.k14s.io/v1alpha1kind: Configdirectories: - path: deploy/definitions contents: - path: nginx git: url: https://github.com/kubernetes/website ref: main includePaths: - content/en/examples/application/deployment.yaml newRootPath: content/en/examples/application/
Le paramètre newRootPath
permet de changer le chemin root par défaut. Le
résultat, c’est le que le fichier qui se trouvait dans le répertoire
content/en/examples/application/
sera déposé dans le path
défini
deploy/definitions
.
Lançons la synchronisation :
vendor sync
Rappel : vendir
créé un lockfile pointant sur le commit qui a été utilisé. Si
vous voulez ré la même version il suffit de lancer la commande vendir sync --locked
Maintenant créons le fichier de patch que nous allons déposer dans le répertoire
deploy/patchs
mkdir -p deploy/patchs/nginxvi deploy/patchs/nginx/nginx-deployment-replica-count.yaml
C’est donc un fichier formaté ytt
:
#! Ceci est un commentaire ytt, Les instruction ytt sont de la forme #@#@ load("@ytt:overlay", "overlay")#@overlay/match by=overlay.subset({"kind": "Deployment", "metadata": {"name": "nginx-deployment"}})---spec: #! change spec.replicas to 3 replicas: 3
Ici on charge le module ytt
overlay ↗ et on lui indique ce
qui doit être patcher le deployement avec le match sur la définition {"kind": "Deployment", "metadata": {"name": "nginx-deployment"}}
Créons le manifest kubernetes patché :
ytt -f deploy/definitions/nginx/ -f deploy/patchs/nginx
En sortie nous obtenons bien replicas : 3
:
apiVersion: apps/v1kind: Deploymentmetadata: name: nginx-deploymentspec: selector: matchLabels: app: nginx replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
Conclusion
Ytt est une belle alternative à Helm. Mais je n’ai pas trouvé trace de repository où on y retrouverait comme pour helm tous les templates des applications les plus courantes. Il va falloir donc tout écrire.