Pods and containers

L’objet de cet article est de présenter l’image Docker jinja-init, ainsi que les raisons qui nous ont amenés à la créer.

Public visé : utilisateurs et administrateurs de solutions d’orchestration de conteneurs, en particulier Kubernetes
Pré-requis : connaissances de la notion de pod Kubernetes et de la notion de template de fichier.

Par Gauvain Pocentek, Consultant Cloud @ Objectif Libre

Avant l’orchestration, les images

Orchestrer le déploiement de conteneurs est devenu simple et rapide. Cependant, la création d’images de conteneurs facilement utilisables et uniformes peut rester un challenge.

La tendance pour le développement de nouvelles applications est de suivre les 12 facteurs : 12 règles qui permettent de faciliter les déploiements applicatifs et d’éviter les différences entre les différents stades (dev/prod). La conteneurisation est simplifiée, notamment grâce à la règle n°3 qui préconise de ne pas utiliser de fichier de configuration mais des variables d’environnement. Les orchestrateurs de conteneurs gèrent parfaitement cette fonctionnalité. Kubernetes peut par exemple exposer les informations des ConfigMaps et des Secrets sous forme de variables d’environnement dans les pods.

Comment conteneuriser la majorité des applications existantes, qui ne supportent pas la configuration par variables d’environnement ?

Plusieurs solutions sont possibles, présentant chacune avantages et inconvénients :

  • Inclure le fichier de configuration dans l’image : ou comment rendre inutilisable un outil prévu pour être portable.
  • Modification du code : possible pour des applications internes ou open source, mais implique un effort conséquent, et le besoin de maintenir les changements au fur et à mesure des évolutions de l’application.
  • Utilisation d’un script de configuration au démarrage du conteneur : le script lit les variables d’environnement et génère un fichier de configuration pour l’application. C’est une pratique très courante, mais il est nécessaire d’écrire un script spécifique à chaque application, ou type d’application.
  • Stocker le fichier de configuration sous forme d’objet : c’est le rôle des ConfigMaps de Kubernetes. Avec les mots de passe (bases de données, tokens d’API externes, …) stockés en clair. À proscrire, donc.

Dans le contexte Kubernetes, l’utilisation des ConfigMaps pour stocker les fichiers de configuration et des Secrets pour stocker les informations sensibles est pratique courante, mais il reste encore à générer un fichier de configuration final, utilisable par l’application. C’est ce que peuvent faire les initContainers.

Les initContainers : un début de solution

Les initContainer sont des conteneurs exécutés dans un pod avant que le conteneur applicatif soit démarré. Les initContainers n’ont pas pour vocation d’être exécutés durant la durée de vie de l’applicatif : ils sont là pour… initialiser !

Plusieurs cas d’usage :

  • Télécharger des artefacts pour l’exécution de l’application (le dernier .jar disponible par exemple)
  • S’assurer que le service de base de données est disponible, ou attendre qu’il le devienne si nécessaire
  • Générer un fichier de configuration

Grâce à la mise à disposition dans l’initConteneur des ConfigMaps et des Secrets, le fichier de configuration peut être généré et stocké dans un volume. Ensuite, le conteneur applicatif pourra utiliser ce volume pour accéder au fichier de configuration.

Le principal avantage de ce mécanisme est que le conteneur applicatif se contente de démarrer l’application, sans aucun besoin de modification. Ce principe devient particulièrement intéressant lors de l’utilisation d’outil de construction automatique d’images tels que source to image : les images de conteneurs sont identiques, quelles que soient les applications.

Cependant, l’utilisation d’initContainers ne fait que déplacer le problème : les spécificités du fichier de configuration de l’application doivent être gérées ailleurs. Il est maintenant nécessaire de créer des scripts et des images pour les initContainers.

Templates !

La problématique de génération de ces fichiers de configuration existait déjà avant l’ère des conteneurs. Les outils de gestion de configuration (Ansible, Puppet, …) fournissent tous un moteur de template pour simplifier la génération variabilisée de fichiers de configuration.

Le processus de génération est généralement le même pour tous ces outils :

  1. L’utilisateur écrit un template et définit les variables selon l’environnement cible
  2. Le moteur de template fait son travail
  3. Le fichier final est déployé sur les serveurs

 

Dans un environnement Kubernetes, le même procédé peut être utilisé : l’initContainer devient un simple moteur de template.

Une unique image peut être utilisée par tous les projets, par exemple jinja-init (dépôt github, docker hub).

Cette image docker utilise le moteur Jinja2 pour générer le fichier de configuration final de l’application.

 

 

Nous avons construit et utilisons cette image chez Objectif Libre pour plusieurs raisons :

  • Notre infrastructure interne utilise maintenant OpenShift, et nous utilisons source-to-image pour la construction des images. Il nous fallait un outil pour la gestion des configurations.
  • La migration vers Kubernetes/OpenShift avait pour but d’uniformiser les déploiements applicatifs. L’utilisation de jinja-init permet d’uniformiser la gestion de la configuration également.
  • La configuration reste de la configuration : pas besoin de scripts spécifiques. Il suffit de définir des variables.

Le choix de Jinja2 comme moteur de template est lié aux habitudes d’Objectif Libre (python !). Vous préférez le Go ou le Ruby ? Une image similaire peut être construite avec un moteur de rendu différent.

 

Conclusion

La création de jinja-init a permis de grandement simplifier la gestion des configurations applicatives dans un contexte d’orchestration de conteneurs. L’idéal serait de ne pas avoir à gérer ces problématique mais les applications « container-ready » ne sont pas si courantes aujourd’hui.