Aller au contenu

Le gestionnaire de déploiement kapp"

logo carvel

kapp est un outil de la suite Carvel qui permet de gérer le déploiement d’applications sur des clusters Kubernetes.

Les points forts de kapp :

  • Kapp peut fonctionner avec des manifests classiques ou issu de templates Helm ou yyt.
  • Kapp sépare la phase de calcul du changement (diff) de la phase d’application du changement (apply) pour donner aux utilisateurs une visibilité sur ce qui va changer.
  • Kapp suit et fait converger les ressources sur la base d’une étiquette générée unique, évitant ainsi à ses utilisateurs de se soucier du nettoyage des anciennes ressources lors de la mise à jour de l’application
  • Kapp ordonne certaines ressources afin que le serveur d’API Kubernetes puisse les traiter avec succès (par exemple, les CRD et les espaces de noms avant les autres ressources)
  • kapp attends que les ressources soient prêtes avant de considérer que le déploiement s’est fait avec succès.
  • Kapp est gitops ready.

Installation de kapp

Comme pour les autres outils de la suite on installe tout :

Terminal window
wget -O- https://carvel.dev/install.sh > install.sh
sudo bash install.sh
kapp version
kapp version 0.44.0
Succeeded

Utilisation de kapp

Kapp possède plusieurs commandes permettant de gérer les applications d’un cluster kubernetes dont les principales sont : deploy, list, inspect et logs.

Pour obtenir de l’aide il suffit de taper le classique :

Terminal window
kapps [<command>] --help

Toutes les commandes possèdent des alias (deploy : dep ou d) qui sont affichés dans le début de l’aide de chaque commande.

Kapp possède une option --json qui permet d’afficher la ressource sous forme de json. Bien utile pour les ansible users entre autre.

Mon exemple d’application vient des exemples fournis sur le projet de kapp.

Je vais utiliser kind pour créer un cluster et déployer dessus.

Déployer à jour une application

Pour déployer une application on doit lui indiquer comme pour helm un identifiant qui servira à identifier toutes les ressources associées. Pour cela on utilise l’option -a qui vient se placer derrière la commande deploy :

Terminal window
kapp deploy -a simple-app -f config.yml
Target cluster 'https://10.240.0.10:6443' (nodes: master1, 1+)
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default simple-app Deployment - - create - reconcile - -
^ simple-app Service - - create - reconcile - -
Op: 2 create, 0 delete, 0 update, 0 noop, 0 exists
Wait to: 2 reconcile, 0 delete, 0 noop
Continue? [yN]:

kapp compare les ressources spécifiées dans les fichiers de ressources à ceux qui existent déjà dans le cluster Kubernetes. Une fois l’ensemble de modifications calculé, il offre une option pour l’appliquer.

Terminal window
Continue? [yN]: y
7:01:44AM: ---- applying 2 changes [0/2 done] ----
7:01:44AM: create deployment/simple-app (apps/v1) namespace: default
7:01:44AM: create service/simple-app (v1) namespace: default
7:01:44AM: ---- waiting on 2 changes [0/2 done] ----
7:01:44AM: ok: reconcile service/simple-app (v1) namespace: default
7:01:44AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
7:01:44AM: ^ Waiting for generation 2 to be observed
7:01:44AM: L ok: waiting on replicaset/simple-app-765bb9c475 (apps/v1) namespace: default
7:01:44AM: L ongoing: waiting on pod/simple-app-765bb9c475-fv62b (v1) namespace: default
7:01:44AM: ^ Pending
7:01:44AM: ---- waiting on 1 changes [1/2 done] ----
7:01:46AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
7:01:46AM: ^ Waiting for 1 unavailable replicas
7:01:46AM: L ok: waiting on replicaset/simple-app-765bb9c475 (apps/v1) namespace: default
7:01:46AM: L ongoing: waiting on pod/simple-app-765bb9c475-fv62b (v1) namespace: default
7:01:46AM: ^ Pending: ContainerCreating
7:01:54AM: ok: reconcile deployment/simple-app (apps/v1) namespace: default
7:01:54AM: ---- applying complete [2/2 done] ----
7:01:54AM: ---- waiting complete [2/2 done] ----
Succeeded

Vous remarquez que kapp attend bien que les ressources passent au status complete avant de rendre la main avec le code retour associé.

Lister les applications installées

La commande list permet d’afficher toutes les applications déployées avec kapp sur un cluster dans le namespace actuel :

Terminal window
kapp ls
Target cluster 'https://10.240.0.10:6443' (nodes: master1, 1+)
Apps in namespace 'default'
Name Namespaces Lcs Lca
simple-app default true 6m
Lcs: Last Change Successful
Lca: Last Change Age
1 apps
Succeeded

Cette commande peut prendre deux options pour afficher les applications d’un namespace : -n <namespace> et -A pour tous les namespaces.

Inspecter les applications

kapp permet d’afficher bien plus d’informations d’une application avec la commande inspect qui possède quelques options bien sympathiques :

Terminal window
kapp inspect -a simple-app --tree
Target cluster 'https://10.240.0.10:6443' (nodes: master1, 1+)
Resources in app 'simple-app'
Namespace Name Kind Owner Conds. Rs Ri Age
default simple-app Deployment kapp 2/2 t ok - 14m
default L simple-app-765bb9c475 ReplicaSet cluster - ok - 14m
default L.. simple-app-765bb9c475-fv62b Pod cluster 4/4 t ok - 14m
default simple-app Service kapp - ok - 14m
default L simple-app Endpoints cluster - ok - 14m
default L simple-app-mrbcg EndpointSlice cluster - ok - 14m
Rs: Reconcile state
Ri: Reconcile information
6 resources
Succeeded

Notez qu’il reconnaît aussi les ressources qu’il n’a pas créées directement comme le ReplicaSet et le Endpoints.

Afficher les logs d’une application

Vous allez voir tout de suite le bénéfice d’utiliser kapp pour afficher les logs d’une application. Il existe des alternatives comme stern qui peut produire le même résultat. Kapp s’appuie sur les labels qu’il a posés lors du déploiement pour afficher les logs des différents pods qui compose une application.

Avant on va passer à trois réplicas :

Terminal window
kubectl scale deployment simple-app --replicas 3
deployment.apps/simple-app scaled
Target cluster 'https://127.0.0.1:35919' (nodes: kind-control-plane)
# starting tailing 'simple-app-64bbd6695f-tc25z > simple-app' logs
# starting tailing 'simple-app-64bbd6695f-cw7l8 > simple-app' logs
# starting tailing 'simple-app-64bbd6695f-wdz2p > simple-app' logs
simple-app-64bbd6695f-wdz2p > simple-app | 2022/01/27 07:52:33 Server started
# ending tailing 'simple-app-64bbd6695f-wdz2p > simple-app' logs
simple-app-64bbd6695f-tc25z > simple-app | 2022/01/27 07:57:50 Server started
# ending tailing 'simple-app-64bbd6695f-tc25z > simple-app' logs
simple-app-64bbd6695f-cw7l8 > simple-app | 2022/01/27 07:57:50 Server started
# ending tailing 'simple-app-64bbd6695f-cw7l8 > simple-app' logs
Succeeded

Utilisation de kapp avec des templates

kapp peut utiliser des templates comme source de déclaration. Ici nous allons utiliser ytt, mais ca fonctionne aussi avec helm.

Nous allons utiliser un fichier d’overlay qui vient modifier certaines propriétés du manifest.

#@ load("@ytt:overlay", "overlay")
#@overlay/match by=overlay.subset({"kind": "Deployment"})
---
spec:
#@overlay/match missing_ok=True
replicas: 3
Terminal window
kapp deploy -a simple-app -c -f <(ytt template -f config-step-2-template/ -f config-step-2a-overlays/custom-scale.yml)
Target cluster 'https://127.0.0.1:35919' (nodes: kind-control-plane)
@@ update deployment/simple-app (apps/v1) namespace: default @@
...
103,103 spec:
104 - progressDeadlineSeconds: 600
105,104 replicas: 3
106 - revisionHistoryLimit: 10
107,105 selector:
108,106 matchLabels:
...
110,108 simple-app: ""
111 - strategy:
112 - rollingUpdate:
113 - maxSurge: 25%
114 - maxUnavailable: 25%
115 - type: RollingUpdate
116,109 template:
117,110 metadata:
118 - creationTimestamp: null
119,111 labels:
120,112 kapp.k14s.io/app: "1643269818769218079"
...
128,120 image: docker.io/dkalinin/k8s-simple-app@sha256:4c8b96d4fffdfae29258d94a22ae4ad1fe36139d47288b8960d9958d1e63a9d0
129 - imagePullPolicy: IfNotPresent
130,121 name: simple-app
131 - resources: {}
132 - terminationMessagePath: /dev/termination-log
133 - terminationMessagePolicy: File
134 - dnsPolicy: ClusterFirst
135 - restartPolicy: Always
136 - schedulerName: default-scheduler
137 - securityContext: {}
138 - terminationGracePeriodSeconds: 30
139,122 status:
140,123 availableReplicas: 3
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default simple-app Deployment 2/2 t 9m update - reconcile ok -
Op: 0 create, 0 delete, 1 update, 0 noop, 0 exists
Wait to: 1 reconcile, 0 delete, 0 noop
Continue? [yN]: y
8:01:10AM: ---- applying 1 changes [0/1 done] ----
8:01:10AM: update deployment/simple-app (apps/v1) namespace: default
8:01:10AM: ---- waiting on 1 changes [0/1 done] ----
8:01:11AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
8:01:11AM: ^ Waiting for generation 7 to be observed
8:01:11AM: L ok: waiting on replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:01:11AM: L ok: waiting on replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:01:11AM: L ok: waiting on replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:01:11AM: L ok: waiting on pod/simple-app-64bbd6695f-wdz2p (v1) namespace: default
8:01:11AM: L ok: waiting on pod/simple-app-64bbd6695f-tc25z (v1) namespace: default
8:01:11AM: L ok: waiting on pod/simple-app-64bbd6695f-cw7l8 (v1) namespace: default
8:01:11AM: L ongoing: waiting on pod/simple-app-549947d777-8rzh8 (v1) namespace: default
8:01:11AM: ^ Pending
8:01:12AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
8:01:12AM: ^ Waiting for 1 unavailable replicas
8:01:12AM: L ok: waiting on replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:01:12AM: L ok: waiting on replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:01:12AM: L ok: waiting on replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:01:12AM: L ok: waiting on pod/simple-app-64bbd6695f-wdz2p (v1) namespace: default
8:01:12AM: L ok: waiting on pod/simple-app-64bbd6695f-tc25z (v1) namespace: default
8:01:12AM: L ok: waiting on pod/simple-app-64bbd6695f-cw7l8 (v1) namespace: default
8:01:12AM: L ongoing: waiting on pod/simple-app-549947d777-8rzh8 (v1) namespace: default
8:01:12AM: ^ Pending: ContainerCreating
8:01:13AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
8:01:13AM: ^ Waiting for 1 unavailable replicas
8:01:13AM: L ok: waiting on replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:01:13AM: L ok: waiting on replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:01:13AM: L ok: waiting on replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:01:13AM: L ok: waiting on pod/simple-app-64bbd6695f-wdz2p (v1) namespace: default
8:01:13AM: L ok: waiting on pod/simple-app-64bbd6695f-tc25z (v1) namespace: default
8:01:13AM: L ok: waiting on pod/simple-app-64bbd6695f-cw7l8 (v1) namespace: default
8:01:13AM: L ok: waiting on pod/simple-app-549947d777-8rzh8 (v1) namespace: default
8:01:14AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
8:01:14AM: ^ Waiting for 1 unavailable replicas
8:01:14AM: L ok: waiting on replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:01:14AM: L ok: waiting on replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:01:14AM: L ok: waiting on replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:01:14AM: L ok: waiting on pod/simple-app-64bbd6695f-wdz2p (v1) namespace: default
8:01:14AM: L ongoing: waiting on pod/simple-app-64bbd6695f-tc25z (v1) namespace: default
8:01:14AM: ^ Deleting
8:01:14AM: L ok: waiting on pod/simple-app-64bbd6695f-cw7l8 (v1) namespace: default
8:01:14AM: L ongoing: waiting on pod/simple-app-549947d777-vz4hx (v1) namespace: default
8:01:14AM: ^ Pending: ContainerCreating
8:01:14AM: L ok: waiting on pod/simple-app-549947d777-8rzh8 (v1) namespace: default
8:01:17AM: ongoing: reconcile deployment/simple-app (apps/v1) namespace: default
8:01:17AM: ^ Waiting for 1 unavailable replicas
8:01:17AM: L ok: waiting on replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:01:17AM: L ok: waiting on replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:01:17AM: L ok: waiting on replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:01:17AM: L ok: waiting on pod/simple-app-64bbd6695f-wdz2p (v1) namespace: default
8:01:17AM: L ongoing: waiting on pod/simple-app-64bbd6695f-tc25z (v1) namespace: default
8:01:17AM: ^ Deleting
8:01:17AM: L ongoing: waiting on pod/simple-app-64bbd6695f-cw7l8 (v1) namespace: default
8:01:17AM: ^ Deleting
8:01:17AM: L ok: waiting on pod/simple-app-549947d777-vz4hx (v1) namespace: default
8:01:17AM: L ok: waiting on pod/simple-app-549947d777-8rzh8 (v1) namespace: default
8:01:17AM: L ongoing: waiting on pod/simple-app-549947d777-7hldh (v1) namespace: default
8:01:17AM: ^ Pending: ContainerCreating
8:01:20AM: ok: reconcile deployment/simple-app (apps/v1) namespace: default
8:01:20AM: ---- applying complete [1/1 done] ----
8:01:20AM: ---- waiting complete [1/1 done] ----
Succeeded

Vraiment sympa la sortie au format diff qui affiche toutes les modifications qui vont être appliqué.

Afficher l’historique des modifications

Pour afficher l’historique des modifications des applications on utilise la commande app-change list :

Terminal window
kapp app-change list -a simple-app
Target cluster 'https://10.240.0.10:6443' (nodes: master1, 1+)
App changes
Name Started At Finished At Successful Description
simple-app-change-k98bc 2022-01-27T09:56:19Z 2022-01-27T09:56:23Z true update: Op: 0 create, 0 delete, 1 update, 0 noop, 0 exists / Wait to: 1 reconcile, 0 delete, 0 noop
simple-app-change-l4fwv 2022-01-27T09:05:44Z 2022-01-27T09:05:50Z true update: Op: 2 create, 0 delete, 0 update, 0 noop, 0 exists / Wait to: 2 reconcile, 0 delete, 0 noop
2 app changes
Succeeded

Supprimer une application

Pour effacer une application rien de plus simple il suffit d’utiliser la commande delete :

Terminal window
kapp delete -a simple-app
Target cluster 'https://127.0.0.1:35919' (nodes: kind-control-plane)
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default simple-app Deployment 2/2 t 18m delete - delete ok -
^ simple-app Endpoints - 18m - - delete ok -
^ simple-app Service - 18m delete - delete ok -
^ simple-app-549947d777 ReplicaSet - 7m - - delete ok -
^ simple-app-5f8db95765 ReplicaSet - 18m - - delete ok -
^ simple-app-64bbd6695f ReplicaSet - 16m - - delete ok -
^ simple-app-64bbd6695f-ptkqs Pod 4/4 t 2m - - delete ok -
^ simple-app-64bbd6695f-qlfkl Pod 4/4 t 2m - - delete ok -
^ simple-app-64bbd6695f-v8fhl Pod 4/4 t 2m - - delete ok -
^ simple-app-xt22j EndpointSlice - 18m - - delete ok -
Op: 0 create, 2 delete, 0 update, 8 noop, 0 exists
Wait to: 0 reconcile, 10 delete, 0 noop
Continue? [yN]: y
8:09:15AM: ---- applying 10 changes [0/10 done] ----
8:09:15AM: noop pod/simple-app-64bbd6695f-qlfkl (v1) namespace: default
8:09:15AM: noop replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:09:15AM: noop pod/simple-app-64bbd6695f-ptkqs (v1) namespace: default
8:09:15AM: noop pod/simple-app-64bbd6695f-v8fhl (v1) namespace: default
8:09:15AM: noop replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:09:15AM: noop endpoints/simple-app (v1) namespace: default
8:09:15AM: noop endpointslice/simple-app-xt22j (discovery.k8s.io/v1) namespace: default
8:09:15AM: noop replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:09:16AM: delete deployment/simple-app (apps/v1) namespace: default
8:09:16AM: delete service/simple-app (v1) namespace: default
8:09:16AM: ---- waiting on 10 changes [0/10 done] ----
8:09:16AM: ongoing: delete pod/simple-app-64bbd6695f-v8fhl (v1) namespace: default
8:09:16AM: ok: delete service/simple-app (v1) namespace: default
8:09:16AM: ongoing: delete replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:09:16AM: ongoing: delete pod/simple-app-64bbd6695f-qlfkl (v1) namespace: default
8:09:16AM: ongoing: delete replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:09:16AM: ongoing: delete pod/simple-app-64bbd6695f-ptkqs (v1) namespace: default
8:09:16AM: ongoing: delete endpointslice/simple-app-xt22j (discovery.k8s.io/v1) namespace: default
8:09:16AM: ongoing: delete replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:09:16AM: ok: delete deployment/simple-app (apps/v1) namespace: default
8:09:16AM: ok: delete endpoints/simple-app (v1) namespace: default
8:09:16AM: ---- waiting on 7 changes [3/10 done] ----
8:09:16AM: ok: delete replicaset/simple-app-5f8db95765 (apps/v1) namespace: default
8:09:16AM: ok: delete replicaset/simple-app-549947d777 (apps/v1) namespace: default
8:09:16AM: ok: delete replicaset/simple-app-64bbd6695f (apps/v1) namespace: default
8:09:16AM: ok: delete endpointslice/simple-app-xt22j (discovery.k8s.io/v1) namespace: default
8:09:16AM: ---- waiting on 3 changes [7/10 done] ----
8:09:23AM: ok: delete pod/simple-app-64bbd6695f-ptkqs (v1) namespace: default
8:09:23AM: ok: delete pod/simple-app-64bbd6695f-qlfkl (v1) namespace: default
8:09:23AM: ---- waiting on 1 changes [9/10 done] ----
8:09:24AM: ok: delete pod/simple-app-64bbd6695f-v8fhl (v1) namespace: default
8:09:24AM: ---- applying complete [10/10 done] ----
8:09:24AM: ---- waiting complete [10/10 done] ----
Succeeded

Vous remarquez il détruit toute trace de tout ce qui a été déployé avec kapp.

Conclusion

kapp a vraiment du potentiel et je pense que je vais l’intégrer dans ma liste de pépites. Il manque le moyen de faire un rollback rapidement. Dans un prochain billet nous verrons la partie gitops de kapp.

Source