Contexte

Depuis toujours, l’installation et la maintenance d’éléments d’infrastructure informatique que ce soit des équipements physiques (serveurs, stockage de données, bases de données, périphériques réseaux, … ), des machines virtuelles ou bien des logiciels (applications spécifiques, services Cloud, …) requièrent toujours des interventions humaines et des opérations manuelles qui peuvent prendre plus ou moins de temps : commande de matériel, câblage des machines, installation et configuration. Des étapes partiellement automatisées (scripts spécifiques, outils divers pour les configurations …) permettent de faciliter certains processus sur les tâches répétitives et coûteuses en temps.

 

 

Avec la montée en puissance des fournisseurs de services Cloud qui mettent à disposition tout type d’éléments d’infrastructure, la virtualisation et la popularité de la conteneurisation des applications, il est aujourd’hui possible d’approvisionner un nombre conséquent de serveurs en un clic de souris, installés avec le bon OS et les bons outils, câblés sur le bon réseau avec les paramètres de sécurité recommandés et reliés avec les éléments de stockage adaptés. Tous ces nouveaux services ont également augmenté le nombre d’environnements à maintenir : serveurs divers, Cloud public/privé, environnement de développement, tests et QA par exemple.

De plus en plus, le clic souris et les scripts spécifiques laissent place à la ligne de commande (CLI: Command Line Interface) et à des outils plus perfectionnés et pensés pour du déploiement automatique d’infrastructures.

 

Une des missions confiées à CACD2 est l’étude des technologies de Cloud Computing, la maîtrise des pratiques d’Infrastructure as Code est donc incontournable.

 

Infrastructure as Code, qu’est-ce que c’est ?

L’Infrastructure as Code est une approche DevOps qui consiste à gérer et à provisionner tous les éléments d’infrastructure (serveurs, réseau, stockage, applications, …) de manière automatique sous forme de code source de la même manière que l’on gère un composant logiciel.

Les avantages liés à cette pratique sont les suivants:

  • Automatisation: Finies les opérations de configuration manuelles rébarbatives et consommatrices en temps, finies les attentes interminables des étapes avant de pouvoir cliquer sur « suivant » ou « j’accepte » … L’automatisation participe à la réduction des coûts, la rapidité et la facilité du déploiement. Elle écarte le risque d’erreurs humaines et toutes les étapes fastidieuses.

 

  • Reproductibilité: Finies les opérations de configuration manuelles qui ne fonctionnent que dans un environnement et pas un autre. L’infrastructure présente les mêmes caractéristiques fonctionnelles à chaque déploiement et cette identité est répétable sur chaque environnement.

 

  • Traçabilité et maintenabilité: Le code source de l’infrastructure toute entière peut être visible de tous, versionné, et audité. Comme tout bon code source, il est facilement maintenable et testable.

 

  • Dynamicité: Le fait que tout soit sous forme de code source rend tout ajout d’éléments et configuration facilement extensible; un besoin d’élasticité ou un approvisionnement de périphériques supplémentaires se règle en quelques lignes de code.

 

  • Gestion du retour arrière: La traçabilité du code permet un retour en arrière sur une configuration stable en cas de changements inopportuns.

 

  • Gain de temps: Comme tout logiciel, la capacité à décliner à volonté, la récupération de solutions open source prêtes à l’emploi, ou d’une brique déjà implémentée permet un gain de temps considérable.

 

Quant aux inconvénients, le système magique et parfait n’existe pas, on contrebalance toujours en comparant la forte valeur ajoutée générée par rapport aux quelques désagréments causés, on peut citer :

  • Technicité et complexité: Le passage du clic de boutons sur une interface graphique pour instancier et configurer des ressources vers la création d’un code source équivalent dans le bon langage nécessite une plus grande technicité, surtout pour les premières briques à implémenter.  On est sur une approche développement de code, il faut bien solliciter quelques neurones supplémentaires pour maitriser un langage et un framework. La montée en compétence requiert de la patience et de la pratique.

 

  • Temps de mise en place: Comme tout développement logiciel, le temps de réalisation est plus long, mais une fois achevé, personne ne va contester les bénéfices que l’automatisation apporte. Et finalement,  n’est-il pas plus long de configurer répétitivement des machines ou de passer du temps à coder cette automatisation ??

 

 

Chez CACD2, on a l’Infrastructure as Code dans notre ADN

 

Notre infrastructure a été pensée et conçue avec cet esprit où tout élément est provisionné par du code source à tous les étages.

D’une part, parce que les technologies actuelles le permettent, et d’autre part, notre cœur de métier est le développement logiciel et non la maintenance ou la configuration de serveurs, nous privilégions attentivement l’approche dirigée par le code et la ligne de commande. Les interfaces graphiques ne servent en général que pour nos phases préparatoires et exploratoires.

 

Je suis paré pour une auto installation ou une auto désinstallation de l’usine logicielle entière

 

  • Amazon Web Services / Cloud Formation

 

Notre fournisseur de services Cloud AWS met à disposition tous ses éléments d’infrastructure à portée de clic de souris, via sa console d’administration, ou bien via la AWS CLI : réseaux, stockage, capacité de traitement, service managé. Notons également qu’AWS fournit un langage commun pour décrire et provisionner toutes ses ressources d’infrastructure sous forme de fichiers YAML ou JSON avec sa technologie Cloud Formation.

EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
        ImageId: !FindInMap [ AWSRegionArch2AMI, !Ref ‘AWS::Region’ , !FindInMap [  AWSInstanceType2Arch, !Ref InstanceType, Arch ] ]
        KeyName: !Ref KeyName
        InstanceType: !Ref InstanceType
        SecurityGroups:
        – !Ref Ec2SecurityGroup
        BlockDeviceMappings:
        –
          DeviceName: /dev/sda1
          Ebs:
            VolumeSize: 50
        –
          DeviceName: /dev/sdm
          Ebs:
            VolumeSize: 100

Exemple de fichier Cloud Formation pour instancier une machine EC2 (Extrait de Amazon)

 

Nous avons utilisé Cloud Formation pour monter notre Plateforme d’Intégration Continue que ce soit pour des briques de base et leur configuration ou pour monter nos piles logicielles (Nexus, Jenkins, Sonarqube …). Le templating des ressources permet d’avoir une meilleure modularité, une configuration plus dynamique et une combinaison d’assemblage des éléments plus aisée.

 

  • Ansible

Ansible est un outil opensource pour la configuration et la gestion de machines qui est réputé pour être simple à appréhender car il n’y a pas d’agent à installer, l’apprentissage du langage est rapide et son utilisation reste simple. De plus, Ansible offre de nombreux plugins ou modules (1300+) qui étendent ses fonctionnalités et réduit la complexité de déploiement.

Les phases d’installation sont décrites dans des « playbooks » Ansible.

Chez CACD2, nos playbooks détaillent l’installation de chaque brique de notre infrastructure, et chaque bloc d’instructions peut exécuter aussi bien du script (bash, python, …) que des templates Cloud Formation via le plugin dédié. Un jeu de variables permet de séparer les configurations entre nos divers environnements (usines, clients, développement, production …). Ansible est en quelque sorte notre chef d’orchestre pour l’installation et la configuration du matériel et du logiciel.

– name: ensure S3 ChartMuseum bucket exists
  cloudformation:
    region: ‘{{ aws_region }}’
    profile: ‘{{ aws_profile }}’
    stack_name: ‘chartmuseum-data-bucket-stack’
    template_url: ‘{{ cf_base_url }}/solution/chartmuseum-bucket.yml’
    state: ‘present’
    template_parameters:
      BucketRole: ‘{{ kubernetes_NodeRoleArn }}’
      ChartMuseumBucketName: ‘{{ chartmuseum_s3_bucket_name }}’

– name: ensure Helm ChartMuseum is installed
  shell: |
    helm repo add incubator https://kubernetes-charts-incubator.storage.googleapis.com
    helm upgrade –install \
    –namespace={{ k8s_helm_chartmuseum_namespace }} \
    –values=/tmp/values.yaml \
    –version {{ helm_chart_chartmuseum_version }} \
    {{ k8s_helm_chartmuseum_name }} incubator/chartmuseum
  environment:
    KUBECONFIG: « {{ lookup(‘env’,’HOME’) }}/.kube/{{ inventory_hostname }}-{{ tag_env }} »

Extrait d’instructions Ansible installant un bucket S3 par le plugin Cloud Formation et son template, et exécutant des commandes shell pour installer un ChartMuseum

 

  • Docker

La conteneurisation d’applications via Docker est populaire pour ses nombreuses qualités fonctionnelles de portabilité (local ou multi-clouds, indépendance de l’OS hôte), de légèreté, d’extensibilité, de rapidité de démarrage et de déploiement ou d’ isolation. Mais selon nous, est-ce que son côté opensource et son adoption des pratiques Infra as Code n’ont-ils pas aussi renforcé son attrait auprès des développeurs ?

Le Dockerfile qui est le fichier utilisé pour créer l’image Docker d’une application est spécifié dans une approche descriptive d’Infrastructure as Code. On part d’une image d’OS de base que l’on enrichit de manière descriptive avec des outils, on y décrit le déploiement de notre application, et le tout aboutit à une image immuable et portable au comportement reproductible et extensible.

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]

Exemple de Dockerfile pour conteneuriser une application SpringBoot (Extrait de Pivotal)

 

Toutes les images hébergées sur le DockerHub (repository public officiel des images Docker ) sont bien versionnées et leur Dockerfile est facilement consultable.

Nous utilisons en grande partie des images officielles toutes prêtes dans leur version dédiée pour notre PIC (Jenkins, Sonarqube, Nexus, SeleniumGrid …) , des images spécialisées pour nos pipelines CI/CD Jenkins (Nodejs, Maven, Docker, Helm, kubectl …) et nous étendons finalement des images de base (NodeJs, Maven) pour nos applicatifs.

 

  • Kubernetes

L’orchestration des conteneurs et la gestion de leur cycle de vie sont confiées à Kubernetes, notre orchestrateur privilégié.

Un article CACD2 plus détaillé sur l’orchestrateur Kubernetes est disponible ici.

Kubernetes utilise un format YAML et spécifie tous ses objets sous une forme descriptive; on y retrouve les descriptions suivantes:

  • Déploiement du POD (ensemble de conteneurs):  Images dockers, volumes à monter, variables d’environnements, ressources CPU et RAM nécessaires sur le noeud Kubernetes déployé, replica, stratégie de restart, liveness et readiness probes, affinités et sélections entre noeuds/PODs
  • Service du POD (exposition de l’applicatif): ports ouverts ou redirigés, load balancer, ingress
  • Stockage: Gestion de la persistance des conteneurs
  • Secrets, Permissions, Quota, InitContainer,Jobs: d’autres aspects spécifiques!

 

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template: # create pods using pod definition in this template
    metadata:
    # unlike pod-nginx.yaml, the name is not included in the meta data as a unique name is
    # generated from the deployment name
      labels:
        app: nginx
    spec:
      containers:
      – name: nginx
        image: nginx:1.7.9
        ports:
        – containerPort: 80

Exemple de fichier k8s de déploiement pour nginx ( extrait de kubernetes )

 

Chez CACD2, de nombreux éléments de notre infrastructure utilisent les Kubernetes Helm Charts qui permettent de paramétrer les fichiers Kubernetes, avec quelques modifications et adaptations, notamment pour nos besoins de persistance et câblage avec les bons éléments de stockage chez AWS. Le déploiement de nos applications suit la même trajectoire avec des descriptifs Kubernetes/Helm associés.

 

  • Jenkins

L’orchestrateur de Continuous Integration et Continuous Deployment (CI/CD) Jenkins est un incontournable dans l’industrie. Initialement développé pour être utilisé et configuré via son interface graphique, Jenkins a depuis quelques années pris la mouvance de l’automatisation et du Pipeline as Code avec son fameux Jenkinsfile qui va décrire chacune des étapes de la CI/CD sous forme de script.

node {
  stage(‘Checkout’) {
    checkout scm
  }
   stage(‘Build’) {
    sh « npm install »
  }
  stage(‘Tests’) {
    sh « npm test »
  }
}

Exemple de Jenkinsfile décrivant un pipeline simple avec 3 étapes (checkout, build, test)

 

Chez CACD2, tous nos projets Web, mobile et solutions End-to-End ont leur propre Jenkinsfile qui décrit et suit nos process de CI/CD. L’ajout automatisé des jobs Jenkins s’effectue avec l’outil Jenkins Job Builder qui offre une étape d’automatisation supplémentaire.

 

 

Conclusion

 

Installer, configurer et maintenir une infrastructure matérielle et logicielle sur de nombreux environnements divers et variés, c’est comme se retrouver confronté à la complexité du cockpit de la navette spatiale Endeavour.

L’Infrastructure as Code, malgré sa complexité inhérente et le temps nécessaire de mise en place, permet de simplifier de nombreuses étapes d’installation et de configuration, d’accélérer et de fiabiliser l’intégration et la migration de nouveaux éléments déployés.

Chez CACD2, nous pouvons désormais installer et désinstaller notre usine logicielle et nos environnements de déploiements client de manière automatique en une ligne de commande. Le code est lisible, extensible et maintenable par les personnes qui ont participé à son élaboration. Nous pouvons tracer toutes modifications et mises à jour d’un élément d’infrastructure. Nous pouvons intégrer un nouvel élément d’infrastructure plus rapidement.

Notre expérience en la matière met en évidence que la démarche d’Infrastructure as Code nécessite un investissement sur le long terme, avec un effort à maintenir sur la durée pour améliorer continuellement les mécanismes de déploiement. En particulier, nous continuons encore aujourd’hui nos travaux pour industrialiser encore davantage la création de nouveaux projets de développement.

L’Infrastructure as Code nous a permis finalement d’épargner du temps sur ces aspects répétitifs et complexes de gestion d’infrastructure pour pouvoir nous concentrer sur des activités à plus forte valeur ajoutée.

 

Références

  • https://cacd2.io/le-caas-du-siecle-notre-infrastructure-de-containers-as-a-service

 

  • https://aws.amazon.com/fr/cloudformation/
  • https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-whatis-howdoesitwork.html

 

  • https://docs.docker.com/engine/reference/builder/
  • https://hub.docker.com/

 

  • https://kubernetes.io/docs/concepts
  • https://github.com/kubernetes/charts

 

  • https://www.ansible.com/integrations/infrastructure
  • http://docs.ansible.com/ansible/latest/modules/modules_by_category.html

 

  • https://jenkins.io/solutions/pipeline/
  • https://docs.openstack.org/infra/jenkins-job-builder/