Dans cet article, nous allons voir comment faire du développement continu sur Kubernetes, c’est-à-dire simplifier le cycle de développement et de debug. Pour cela, nous découvrirons un outil développé par Google dont j’ai brièvement parlé lors de mon précédent article sur Cloud Code et lors de mon précédent WeSpeakCloud (cet outil était directement intégré dans Cloud Code), il se nomme Skaffold.

Qu’est-ce que Skaffold :

Skaffold est un outil en ligne de commande Open Source développé par Google depuis 2017, il est sorti de sa beta depuis novembre 2019.

Cet outil permet de faciliter le développement dans Kubernetes en intégrant une notion de développement continu des applications natives de Kubernetes. Il est très simple d’utilisation.

Skaffold va automatiquement gérer pour nous le pipeline suivant :

image8

Ce pipeline sera exécuté de façon continue afin de donner un cycle, car au moindre changement de code, il sera exécuté de nouveau.

Skaffold peut fonctionner aussi bien depuis notre poste de travail que dans le cadre d’un pipeline d’une CI/CD. Il n’y a pas de composant supplémentaire à installer sur le cluster.

Les fonctionnalités de Skaffold :

Skaffold a 4 fonctionnalités majeures qui en font un outil redoutable pour un développeur sur Kubernetes.

Développement Kubernetes local rapide :

  • Skaffold détecte les changements dans votre code source et gère le pipeline pour créer, pousser et déployer automatiquement votre application avec un tag d'image basé sur des règles et des flux, à chaque modification de code.
  • rétroaction continue - Skaffold gère automatiquement la journalisation du déploiement et la redirection de port de ressources.

Les projets Skaffold fonctionnent partout :

  • partagé avec d'autres développeurs : Skaffold est le moyen le plus simple de partager votre projet avec le monde : git clone et skaffold run.
  • sensible au contexte : utilisez les profils Skaffold, la configuration de l'utilisateur local, les variables d'environnement et les indicateurs pour intégrer facilement les différences entre les environnements.
  • commande CI/CD : utilisez skaffold build et skaffold deploy dans le cadre de votre pipeline CI/CD, ou exécutez simplement skaffold de bout en bout.
  • intégration GitOps : utilisez le rendu Skaffold pour créer vos images et rendre des manifestes Kubernetes basés sur des modèles à utiliser dans les flux de travail GitOps.

Skaffold.yaml, une seule configuration déclarative pour votre projet :

  • Skaffold init : Skaffold peut découvrir la configuration de construction et de déploiement, et générer une configuration Skaffold.
  • applications multicomposants : Skaffold prend en charge les applications avec de nombreux composants, ce qui le rend idéal pour les applications basées sur des microservices.
  • apportez vos propres outils : Skaffold a une architecture modulaire, permettant différentes implémentations des étapes de construction et de déploiement.

Léger :

  • côté client uniquement : Skaffold n'a pas de composant côté cluster, donc il n'y a pas de surcharge ou de charge de maintenance pour votre cluster.
  • pipeline minimal : Skaffold fournit un pipeline minimaliste pour garder les choses simples.

Comment fonctionne Skaffold :

Maintenant que nous avons décrit Skaffold et ses différentes fonctionnalités, nous allons pouvoir creuser un peu pour voir comment est organisé le pipeline d’orchestration au sein de Skaffold.

Architecture et design :

A titre de rappel, voici le pipeline de design d’orchestration qu’utilise Skaffold de bout en bout que nous avons introduit plus haut :

image8-1

Avec la description des différentes étapes constitutives d’un pipeline Skaffold :

Capture2

Si nous zoomons sur quelques briques comme la partie “Building artifacts” nous voyons qu’il y a plusieurs possibilités d’outils pour la partie build, idem pour la partie “tagging” et la partie “deploying”, comme nous pouvons le voir ci-dessous :

image11

Comme nous l’avons écrit plus haut, l’architecture de Skaffold permet d’utiliser différents types d’outils ou méthodes selon nos besoins ou préférences ; les outils supportés sont les suivants :

Build :

  • Dockerfile exécuté localement, en cluster avec kaniko ou sur le Cloud à l'aide de Google Cloud Build
  • Jib Maven et Jib Gradle exécutés localement ou sur le cloud à l'aide de Google Cloud Build
  • Bazel exécuté localement
  • Cloud Native Buildpack exécuté localement ou sur le cloud à l'aide de Google Cloud Build
  • Script personnalisé exécuté localement ou dans le cluster (aucun langage imposé)

Test :

Tag :

  • Git tag
  • SHA256 tag
  • Env Template tag
  • DateTime tag

Deploy :

Pour le pipeline d’orchestration de Skaffold, nous pouvons le définir comme nous le désirons, il est possible par exemple de ne pas pousser l’image dans le pipeline d’orchestration, de déployer notre application via Kustomize au lieu de Helm. Nous allons voir ci-dessous deux cas de différents pipelines d’orchestration. Ceux-ci restent des exemples, nous pouvons en définir comme bon nous semble.

1er exemple :

image7

Dans le premier exemple, nous avons décidé de construire notre image sur Docker en mode local, de taguer l’image via son sha256 hash, de ne pas pousser l’image sur une registry et de déployer cette image via kubectl.

2ème exemple :

image3

Dans ce second exemple, nous avons décidé de builder via Google Cloud Build (outil de CI/CD de Google qui va nous permettre de créer l’image de notre conteneur), de taguer l’image via son git commit ID, de pousser l’image sur un repository de conteneur (par exemple la “container registry” de GCP) et de déployer ce même conteneur via Helm.

Installation de Skaffold :

L’installation de Skaffold est vraiment très simple et rapide sur Linux, macOS, Windows ou via une image Docker et le Google Cloud SDK. Voici comment l’installer sur Linux, Docker ou Gcloud :

  • Gcloud :

Skaffold est directement intégré dans les composants disponibles via le SDK de Google Cloud. L’installation de Skaffold avec ce SDK passe par les commandes suivantes :

gcloud components update
gcloud components install skaffold
  • Docker :

Skaffold dispose d’une image Docker officielle déjà construite, si nous voulons la télécharger, nous n'avons qu’à exécuter ces commandes :

Version stable :

docker run gcr.io/k8s-skaffold/skaffold:latest skaffold <command>

Version edge :

docker run gcr.io/k8s-skaffold/skaffold:edge skaffold <command>
  • Linux

Pour installer Skaffold sur Linux, nous pouvons trouver le binaire d’installation sur ce site : https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64.

Pour l’installation sur Linux rien de plus simple, nous n’aurons besoin d'exécuter que ces 2 commandes.

curl -Lo skaffold https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
sudo install skaffold /usr/local/bin/

Pour les autres installations, nous pouvons retrouver les consignes sur la documentation Skaffold : https://skaffold.dev/docs/install/.

Vérification de mise à jour :

Skaffold a un système de vérification de mise à jour qui s’assure de la disponibilité d'une nouvelle version. Cette vérification est activée par défaut. Si nous voulons la désactiver, il existe deux façons différentes qui sont les suivantes :

# mettre la variable d'environnement SKAFFOLD_UPDATE_CHECK à "false"
export SKAFFOLD_UPDATE_CHECK=false
# OU
# stopper ce service directement dans la configuration globale de Skaffold
skaffold config set -g update-check false

En pratique :

Dans notre exemple, nous allons avoir besoin de Git, Docker, d’un cluster GKE (Google Kubernetes Engine) sur GCP (Google Cloud Platform) et de disposer du SDK Google ainsi que Kubectl (command line de Kubernetes). Pour le stockage des images Docker, ce sera dans la container registry de GCP.

La CLI :

Voici les différentes commandes au sein de Skaffold :

Pipelines de bout en bout :

  • skaffold run - Construit l’image, la tag et push l’image ainsi qu’un déploiement sur un cluster Kubernetes local ou distant.
  • skaffold dev - Construit l’image, la tag, push et deploy, et met en place un watch sur le moindre changement de code. Dès que vous avez fini il fait un clean de l’image et du déploiement dans Kubernetes.
  • skaffold debug - Skaffold debug agit comme skaffold dev, mais il va configurer les conteneurs qui tournent dans le pod en mode débogage selon le type de langage utilisé. Les ports de débogage associés seront exposés et étiquetés afin qu’ils puissent être redirigés vers la machine locale. Les langages supportés en mode debug sont les suivants : Go, NodeJs, JAVA, Python.
    Block pour les pipelines de CI/CD :
  • skaffold build - Construit et tag l’image.
  • skaffold deploy - Déploie l’image.
  • skaffold delete - Supprime l’image.
  • skaffold render - Construit et tag l’image, et génère un manifeste Kubernetes.
    Commencer avec un nouveau projet :
  • skaffold init - Génère le fichier de configuration de Skaffold.

Maintenant, mettons en pratique l’utilisation de ces commandes. Pour cela nous allons nous baser sur le projet Github suivant : https://github.com/GoogleCloudPlatform/skaffold . Ce projet contient des exemples prêts à l’emploi en Go, que nous pouvons utiliser pour tester Skaffold. Nous allons ici nous focaliser sur l’exemple getting-started.

git clone https://github.com/GoogleCloudPlatform/skaffold
cd skaffold/examples/getting-started

Le projet contient les fichiers suivants :

image6

  • Dockerfile : pour la création de l’image Docker de notre application
  • main.go : code source de notre application
  • k8s-pod.yaml : manifeste afin de déployer l’image que nous allons créer sur notre cluster Kubernetes
  • skaffold.yaml : fichier de configuration qui va définir notre cycle d’orchestration de Skaffold.

Voici le contenu des fichiers k8s-pod.yaml et main.go :

k8s-pod.yaml :

apiVersion: v1
kind: Pod
metadata:
  name: getting-started
spec:
  containers:
  - name: getting-started
	image: gcr.io/sandbox-akolacz/skaffold-example

Main.go :

package main

import (
    	"fmt"
    	"time"
)

func main() {
    	for {
            	fmt.Println("Hello wescale")
            	time.Sleep(time.Second * 1)
    	}
}

Skaffold.yaml :

apiVersion: skaffold/v2beta6
kind: Config
build:
  artifacts:
  - image: skaffold-example
deploy:
  kubectl:
	manifests:
  	- k8s-*

Dans cette configuration nous avons modifié le fichier “k8s-pod.yaml” afin que l’image qui sera prise soit celle que nous allons stocker dans notre container registry de GCP (image qui sera stockée via cette url : “gcr.io/sandbox-akolacz/skaffold-example”). Suite à ces changements nous allons supprimer le fichier “skaffold.yaml” afin de faire comme si nous voulions initier un nouveau projet.
Pour cela, nous allons générer sa configuration : nous n’aurons qu’à taper la commande suivante “skaffold init” afin qu’il nous génère notre fichier skaffold.yaml

Si nous utilisons la commande “skaffold init” et qu’un fichier “skaffold.yaml” existe déjà il vous demandera d’exécuter cette commande avec l’option “--force” afin d’écraser l’ancien fichier.

Voici le résultat du nouveau fichier skaffold.yaml généré avec la commande “skaffold init”, nous voyons qu’il a parcouru nos fichiers afin de pouvoir récupérer les informations de notre image pointant sur ma container registry de GCP et le nom de mes manifestes Kubernetes :

image9

Maintenant que nous notre configuration est prête, nous allons nous authentifier sur GCP avec la commande suivante :

gcloud auth login

et ayant déjà un cluster GKE de disponible, nous aurons simplement besoin de nous connecter à notre cluster GKE avec la commande suivante (dans mon cas, le projet s’appelle “sandbox-akolacz” et mon cluster se situe dans la zone europe-west1-b) :

gcloud container clusters get-credentials cluster-1 --zone europe-west1-b --project sandbox-akolacz 

Nous aurons aussi besoin de configurer nos informations de connexion Google pour nous connecter à la container registry avec la commande suivante :

gcloud auth configure-docker

Si nous regardons la container registry de Google, nous n’avons actuellement aucune image Docker.

image1

Nous pouvons voir qu’il n’y a bien aucun pod tourne sur le cluster.

image5

Maintenant, nous allons faire la commande “skaffold dev”. Petite précision sur le système de détection, nous pouvons spécifier son fonctionnement avec l’option “--trigger” au passage de la commande, cette option peut avoir les valeurs suivantes : polling, notify, ou manual. Par défaut, Skaffold est configuré en mode notify. Dans ce mode, il détectera le changement de code qu’à la fermeture du fichier modifié (ce qui pourrait poser problème si nous utilisons un IDE et que nous voulons avoir le code afficher sur notre fenêtre en même temps). Le mode polling, lui, va checker à intervalle régulier s’il y a eu un changement de code et cela même si le fichier est encore ouvert.

image4

Nous voyons que Skaffold a bien construit mon image, il indique qu’elle a été poussée sur la container registry de Google (GCR) et qu’il a déployé le pod. Il nous retourne les logs stdout de ce dernier directement dans la console.

image12

Si nous vérifions sur la container registry, on voit que l’image que nous avons appelée skaffold-example est bien présente et ci-dessous, nous voyons que le pod est bien “Running” sur le cluster.

image14

Maintenant, nous allons laisser tourner la commande “skaffold dev” et nous allons modifier le code, on enregistre, et là, PAF ! Skaffold détecte automatiquement le changement dans le code, refait le cycle de build, tag, test et deploy. On observe bien que dans les messages de sortie en stdout, le message a changé : au lieu d’avoir “Hello Wescale”, nous avons “Hello Wescale et le blog”.

image2

Maintenant que nous avons vu une mise en pratique de Skaffold, nous allons arrêter l’exécution de la commande en faisant un ctrl+c, ce qui va entraîner automatiquement la suppression de nos ressources au sein de mon cluster Kubernetes.

Le mot de la fin :

Nous avons pu voir un outil qui, je pense, peut vite devenir indispensable quand on commence à développer, ou même après. Il permet de simplifier notre cycle de développement et de debug en continu sans avoir à se préoccuper du cycle de développement de Kubernetes et pouvoir se concentrer à 100% sur notre code. Le fait que le moindre changement de code soit détecté automatiquement et refasse le cycle de développement Kubernetes de façon automatique sans avoir à y prêter attention est vraiment magique pour moi.