Construire la techno d’une startup part 2: Intégration Continue, Déploiement Continu

Après avoir mis en place le minimum minimorum pour lancer l’infrastructure logicielle d’une nouvelle aventure (voir la partie 1), l’étape suivante est de construire un pipeline de CICD (Continuous Integration Continuous Deployment). C’est un effort assez conséquent, chaque outil nécessitant de se former, mais cet investissement permet d’augmenter fortement la productivité une fois en place. Point important, cet effort peut par ailleurs être découpé en petites améliorations, donc vous pouvez vous y mettre progressivement. Je ne présente pas ici l’approche par container (Docker, Rkt) qui change largement le déploiement, peut-être pour une autre fois.

J’introduis les différentes briques CICD dans l’ordre du plus au moins rentable en termes de retour sur investissement. C’est une opinion personnelle, donc discutable, mais c’est aussi l’ordre chronologique que j’ai suivi dans la mise en place de mes projets.

Déploiement automatisé

Le déploiement automatisé consiste à écrire sous forme de code le processus d’installation des machines et des services développés. Ainsi, au lieu de devoir se logger sur une machine, installer manuellement avec apt-get, yum, faire une copie locale etc, on écrit une fois pour toute du code qu’on peut refaire tourner à l’envie à chaque fois que l’on veut pousser en production une nouvelle version.

Les gains de productivité sont énormes et immédiats :

  • chaque nouveau déploiement est simple et rapide (une commande). Concrètement, cela permet donc de déployer plus souvent, donc des modifications plus petites, et donc d’apporter des améliorations incrémentales au produit tout en limitant le risque de bug. Cette démarche s’inscrit dans une logique DevOps et Agile, où on privilégie un cycle de développement et de déploiement court afin de réduire le risque d’erreur (DevOps) et itérer rapidement avec les utilisateurs/clients (Agile/Lean).
  • il est facile de revenir à une version antérieure (revert) en cas de bug détecté sur une nouvelle version
  • la connaissance du déploiement est accessible à tout le monde (tous ceux qui ont l’autorisation de lire le code), au lieux d’être dans la tête d’une seule personne (le mec ou la nana qui gère les opérations). Il est donc documenté, accessible, auditable, versionnable etc. Pour une organisation, ne pas être totalement dépendante d’une personne, aussi sympa soit elle, est important.

Les outils les plus utilisés sont Chef, Puppet et probablement Ansible. Je connais bien Ansible, outil réputé le plus simple, mais qui nécessite tout de même un peu de travail pour être bien maîtrisé. Au contraire de Chef et Puppet, il utilise uniquement ssh, et ne nécessite pas d’agent distant installé sur les machines à installer. Il vous suffit donc de déployer une clé SSH avec un accès root sur les machines à configurer pour les rendre accessibles à Ansible.

Intégration continue

L’intégration continue consiste à faire tourner automatiquement un ensemble de tests et à compiler le code d’un projet à chaque modification effectuée sur le code.

L’outil très largement standard est Jenkins, open-source (Licence MIT). On peut configurer Jenkins pour lancer un build à chaque commit, sur la branche master ou sur n’importe quelle branche. Dans ce dernier cas, il est probable que de nombreux build soient lancés, et si celui-ci est long, votre serveur Jenkins va souffrir. En général, avoir des builds et des tests qui tournent en temps raisonnable (quelques minutes) est une bonne pratique.

Chacun a sa stratégie de test, mais en général il me semble qu’on met trop l’accent sur les tests unitaires, et pas assez sur les tests d’intégration. Dit autrement, je m’en fous un peu de savoir que tous les tests unitaires passent, même avec une très bonne couverture du code, s’il n’y a rien qui me prouve que le service testé se comporte correctement dans son environnement.

Déploiement continu

C’est la dernière étape, consistant à intégrer le déploiement automatisé à la suite du build de l’intégration continu. Ainsi, à chaque nouveau commit, vous déclenchez automatiquement un build, une série de tests, et le déploiement de la nouvelle version du code en production.

C’est un peu effrayant, puisqu’il n’y a plus aucune intervention manuelle pour vérifier que le produit à déployer est bon. Il faut avoir des tests suffisamment fiables pour avoir suffisamment d’assurance qu’un code buggé ne sera pas déployé. Il faut aussi être capable de revenir à une version antérieure très rapidement, ce que ce pipeline doit vous fournir facilement. Il faut aussi un monitoring propre pour être capable de détecter une anomalie.

Honnêtement, cette dernière étape est loin d’être indispensable, et n’apporte pas tant de gain en productivité. Rester sur un déploiement automatisé lancé manuellement est souvent un bon compromis.