Ephémère est un qualificatif qui décrit de plus en plus ce qui est hébergé sur le cloud.
La beauté d’une approche Cloud Native est d’embrasser cette éphémérité pour donner l’illusion de persistance. En ne persistant que les données métiers, et en étant capable d’instancier instantanément des threads d'exécution consommant ou produisant cette donnée, nous atteignons des degrés d'agilité qui sont le socle des services du quotidiens.

Gitpod en est un exemple. La donnée métier y est votre code persisté sur Github. Le thread éphémère est un serveur VSCode, point d’entrée de votre environnement de développement.
Le tout donne une solution de Development Environment As A Service que nous présentions dans un précédent article.

Comme tout environnement, il nécessite une configuration afin de travailler efficacement avec nos outils de prédilection. Nous parlons ici de ce que l’on nomme dotfiles, c'est-à-dire ces fichiers cachés qui décrivent le comportement d’outils sous GNU/Linux.
À partir du moment où nous manipulons une infinité d’environnements de développement éphémères, se pose la question de la gestion de ces fichiers. Par exemple, en adapter le contenu selon que l’on développe pour un projet GCP ou AWS.
Gitpod ne propose pour le moment pas de solution satisfaisante à ce besoin.
Il existe néanmoins des approches qui s'adaptent à la philosophie de Gitpod et qui offrent une vision Cloud Native de ce que doit être une configuration.
Point que nous illustrerons en adaptant Gitpod à du développement sur la Google Cloud Platform.

Les dotfiles et les environnements conteneurisés locaux

Gitpod n’a pas le monopole des environnements de développement éphémères. Il est tout à fait possible d’avoir la même philosophie en local.
L’extension Containers de VSCode permet cela en s’appuyant sur la technologie des conteneurs. En se basant sur un Docker Daemon local, ainsi qu’un Dockerfile représentatif de l’environnement de développement, l’extension va créer une instance headless de VSCode à l'intérieur du conteneur.

Plutôt que de dupliquer nos fichiers de configuration dans l’image OCI de notre environnement nous pouvons nous appuyer sur la localité de l’information. En créant un bind-volume dont le contenu correspond à nos dotfiles, l’environnement de développement bénéficie de ce contenu et donc de notre configuration.
Mieux, nous pouvons même donner accès à du contenu type clé SSH ou configuration Kubernetes, pour bénéficier de connexions consommables au démarrage de l’environnement.

Volumes docker en tant que source de vos dotfiles‌ ‌

Une autre approche consiste à utiliser l’intégration native proposée par l’extension VSCode en pointant un dépôt Github dont le contenu sera copié dans le conteneur “environnement de développement”.
Il sera alors possible de préciser un script de démarrage qui appliquera la logique de votre choix pour compléter l’installation de ces fichiers. Par exemple en appliquant une logique de rendering de template.

Dépôt Github en tant que source de vos dotfiles‌ ‌

Ce point de templating est intéressant car c’est un besoin légitime pour adapter le contenu d’une configuration en fonction du contexte de développement. Nul besoin d’avoir tous nos dotfiles. Un .gitconfig pourrait légitimement spécifier des identités de commit différentes en fonction d’un environnement "professionnel" ou non.
Du point de vue VSCode, cette logique est à votre charge.

Gitpod, une gestion inachevée de la configuration

La notion de configuration qui nous intéresse dans le cadre de cet article est celle du workspace. Pour rappel, il s’agit du nom donné à l’environnement de développement éphémère provisionné par Gitpod et auquel on accède par une connexion HTTP.

La configuration d’un workspace concerne 3 axes :

  • Les extensions associées au VSCode Server
    Un workspace pourra sauvegarder les extensions que vous installerez
  • Les variables d'environnement
    Un workspace peut être enrichi par des variables d’environnement spécifiques
  • Le cycle de vie du workspace
    Le démarrage d’un workspace se fait en plusieurs étapes dont chacune est customisable via le metafile .gitpod.yaml présent à la racine du projet

Depuis peu, Gitpod offre une fonctionnalité bêta de gestion de dotfiles.
Il s’agit d’un calque de la fonctionnalité de l’extension VSCode container.
Autrement dit, un clone dans le $HOME du workspace du contenu d’un dépôt Git contenant vos dotfiles.
La customisation du contenu de ces fichiers reste encore à votre charge.

Bien que bienvenue, cette approche manque d’agilité. Comment adapter le contenu des dotfiles au contexte du workspace ? Comment gérer des contenus confidentiels tels que des clés SSH ?

Rappel sur une notion clé : la configuration layer

Traiter la gestion d’une configuration en environnement Cloud revient à traiter la problématique de la configuration en environnement éphémère.
Le concept de configuration layer est un pattern cloud natif que nous présentions il y a quelque temps.
Il s’agit de la mise en place des mécanismes d’hydratation de templates qui, en fonction d’un contexte, retourneront les valeurs souhaitées.

Nous décorrélons la configuration et la génération de son contenu de l’environnement qui la consomme. Ce dernier n’est là que de manière indicative pour la phase de génération.

C’est ce que décrit le schéma suivant :

Le rendering de template conditionné par le contenu des environnements cibles‌ ‌

Comment appliquer ce concept avec des workspace Gitpod sans créer d’usine à gaz ?

Chezmoi, une configuration layer pensée pour les dotfiles

Chezmoi est ce qu’on appelle un dotfiles manager. Prenant la forme d’un outil en ligne de commande, son usage permet de copier les fichiers de votre choix en go templates. Templates qui sont ensuite associés à un dépôt Github que vous pouvez cloner et interpréter sur n’importe quel environnement avec Chezmoi d’installé.

Note : Bien qu’initialement conçu pour les dotfiles, en réalité Chezmoi peut considérer n’importe quel fichier. Par exemple des clés SSH ou des configurations de connexion de Cloud SDK (à chiffrer bien entendu).

Chezmoi est nativement intégré avec age et gpg deux outils de chiffrement. Dans la pratique, on sécurisera la donnée par son accès avec un dépôt privé en plus de son chiffrement au repos avec age ou gpg.

Nous imaginions alors dans un précédent article l’usage suivant :

Chezmoi, la configuration layer de nos environnements éphémères

Notons que chaque environnement peut lui-même au besoin contribuer à la source de vérité de la configuration.

Gitpod + Chezmoi

La description de Chezmoi fait naturellement penser à une intégration avec les workspaces Gitpod. En manipulant les variables d’environnement des workspaces nous serions capables de piloter le comportement du rendering des templates Chezmoi pour en adapter à la volée le contenu au contexte de développement.
C’est ni plus ni moins le concept de configuration layer.

Le concept de configuration layer appliqué aux workspaces Gitpod

L’exemple d’un environnement Gitpod adapté à du développement GCP

Google Cloud Shell est un service de la GCP qui provisionne à la volée un shell sur le cloud.
La différence fondamentale avec Gitpod est que Cloud Shell n’a pas comme matière de travail un dépôt de code Git. C’est une VM accessible par un navigateur Web et sur laquelle vous travaillerez plus ou moins comme sur votre machine locale. Gitpod met en avant la notion de workspace dont la durée de vie correspond idéalement à celle de votre temps de développement sur une branche Git. Une feature, un workspace.

Cloud Shell est intéressant car déjà provisionné avec un certain nombre d'outils et en particulier le Cloud SDK déjà configuré pour interagir avec vos projets GCP.
Notre exemple consiste à reproduire cet environnement déjà configuré sur un workspace Gitpod.

Nos principaux axes de réflexions :

  • L’image Docker sur laquelle se base notre Workspace Gitpod

    Une approche directe consiste à utiliser l’image officielle de Google Cloud Shell. L’image est cependant trop lourde dans la pratique et implique un cold start à la minute.
    Autre contre-argument, Cloud Shell a une philosophie de multitenancy au “tab” de shell. Chacun peut définir une connexion à un projet GCP différent.
    Cette approche est codée dans un bashrc custom (/google/bashrc.google) qui va à l’encontre de la philosophie Gitpod dont la multitenancy prend l'échelle du Workspace.Il est possible d’override le comportement décrit du Cloud Shell mais cela revient à un hack difficile à documenter et maintenir.
    Nous partirons donc sur une image custom avec comme base l’image par défaut de Gitpod sur laquelle s’ajoute l’installation du google cloud SDK.
FROM gitpod/workspace-full
 
RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list \
    && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg  add - \
    && sudo apt-get update -y \
    && sudo apt-get install google-cloud-sdk -y
  • La création du dépôt de dotfiles

    Chezmoi comprend nativement les dépôts Github nommés “dotfiles”.
    En créant un tel dépôt nous simplifions l’intégration de Chezmoi avec Gitpod car chaque Workspace est initialisé avec une variable d’environnement $GITPOD_GIT_USER_NAME contenant votre login de connexion Github.
    Créons le lien sur votre machine locale entre chezmoi et Github :
chezmoi cd 
git remote add origin git@github.com:username/dotfiles.git
git branch -M main
git push -u origin main
  • Création du contenu du dotfiles repository

    Installer Chezmoi ainsi qu’ajouter du contenu est déjà très bien documenté.
    Nous installerons en supplément l’outil age pour chiffrer le contenu sensible.
    En particulier, le contenu généré par la commande gcloud init et que l’on retrouve sous $HOME/.config/gcloud. Ce répertoire contient les informations de connexion à vos différents projets GCP. Il est donc très important de chiffrer son contenu même si poussé dans un dépôt privé.
    Pour le chiffrer, nous créons une clé publique age (recipient) associée à une clé privée. Chezmoi sera configuré pour utiliser ce recipient pour un chiffrement asymétrique.
age-keygen -o /private/key/path/content.txt

La commande donne un recipient sur la sortie standard, ainsi qu’une clé privée dans le fichier spécifié.
Le fichier de configuration chezmoi.toml devra contenir ces informations.

encryption = "age"
[age]
    identity = "/private/key/path/content.txt"
    recipient = "agedfksldfjsdlfkjdsflkjdsqflkjdsqlgkjheot13245kdfjgs"

En considérant une configuration gcloud fonctionnelle situé par défaut dans $HOME/.config/gcloud, on lancera la commande :

chezmoi add --encrypt $HOME/.config/gcloud
chezmoi cd
git add .
git commit -m “Add gcloud configuration”
git push
  • La définition des variables d’environnement du workspace

    En prévision du déchiffrement d’un potentiel contenu sensible, créons une variable AGE_KEY avec le contenu de la clé privée précédemment créée. Passer par votre dashboard Gitpod est une option pour définir vos variables d’environnement que vous pouvez scoper à certains workspace seulement.
    Optionnellement une variable GCP_PROJECT_ID indique la configuration gcloud à activer. Configuration qui doit donc exister dans nos dotfiles.
  • La connexion des workspaces à notre dépôt Github de dotfiles

    Cette connexion est prise en charge par Chezmoi que nous installons à la phase d’initialisation du workspace. L’installation dans l’image est aussi une option.
    Une fois le binaire installé, nous installons les dotfiles et déchiffrons le cas échéant ceux chiffrés grâce à notre variable d’environnement AGE_KEY.
    Il est à noter que cette installation s’appuie sur un dépôt Github dont le propriétaire est récupéré par la variable d’environnement GITPOD_GIT_USER_NAME, notre profil de connexion à Gitpod et donc celui de Github. Cette installation s’adapte donc au profil connecté.
    La logique précédente se résume à ce fichier .gitpod.yaml :
image:
  file: gitpod.Dockerfile
tasks:
  - name: main
    before: |
      echo $AGE_KEY > $HOME/key.txt
      sh -c "$(curl -fsLS git.io/chezmoi)" -- init --apply $GITPOD_GIT_USER_NAME
      (cd bin && ./chezmoi apply)
      gcloud config configurations activate $GCP_PROJECT_ID
  • Installation de l’extension Cloud Code
    Pour coller au plus prêt de l’expérience Google Cloud Shell, installons l’extension Google Cloud code :
image:
  file: gitpod.Dockerfile
tasks:
  - name: main
    […]
 
#https://github.com/GoogleCloudPlatform/cloud-code-vscode/issues/256
vscode:
  extensions:
    - https://github.com/GoogleCloudPlatform/cloud-code-vscode/releases/download/v1.17.0/cloudcode-1.17.0.vsix

Puisque nous avons installé et authentifié gcloud, l’extension marchera “out-of-the-box”.

  • Le test

    Nous pouvons lancer un workspace et lancer la commande gcloud config list qui doit faire apparaitre notre configuration GCP active.
  • Aller plus loin
    Une fois authentifié avec gcloud, en fonction de nos droits sur le projet GCP ciblé, nous pouvons envisager de monter un “volume disk” GCS par l’intermédiaire du projet gcsfuse. Ainsi nous partageons plus facilement des informations entre nos différents Workspaces. Mieux, nous créons la capacité d’uploader des objets (texte, image, videos, …) sur nos workspaces, quelque chose que Gitpod ne permet pas nativement.

Résumons notre approche par un schéma :

Gitpod pour remplacer Google Cloud Shell

Nous reproduisons à peu de frais les fonctionnalités du Cloud Shell sur Gitpod en apportant par là même des SLA et SLO absents sur Google Cloud Shell.
Nous allons même plus loin en offrant de nouvelles fonctionnalités à nos Workspaces Gitpods en partageant de la donnée en temps réel via Google Cloud Storage.
Bref nous dépassons la simple somme des deux services en se basant sur une synergie inexploitée. C’est la beauté des services cloud.

Conclusion

Gitpod se concentre sur une offre bien définie, celle de fournir As A service des environnements de développement. Selon le contexte de cet environnement, il est possible de configurer un certain nombre de paramètres. Ils seront essentiellement liés à votre instance d’IDE ainsi qu’aux variables d'environnements disponibles.
Néanmoins nous n’avons qu’un support limité sur les dotfiles.

Chezmoi est un outil qui couvre ce besoin. Disponible sous format binaire, son installation s’intègre très facilement dans le cycle de vie d’un workspace Gitpod. Il y fait office de configuration layer qui se source depuis un dépôt Github dédié ainsi que les variables d’environnements de ce workspace.
Son intégration avec des outils de chiffrement tel age ou gpg finissent par le rendre indispensable.
À tel point qu’on ne peut que suggérer à Gitpod d’intégrer nativement cet outil pour supporter les dotfiles plutôt que de se contenter d’un service minimal calqué sur VSCode.

Aller plus loin :

  1. Une introduction à Chezmoi
  2. Le concept de configuration layer
  3. L’utilitaire de chiffrement age
  4. Une présentation de Google Cloud Shell
  5. Une présentation de Gitpod
  6. Gcsfuse un outil pour mimer le montage de volume filesystem à partir d’un bucket GCS