Quand le code rencontre l'infrastructure

Logo Terraform / OpenTofu

Cliquez sur l'image pour l'agrandir.

Terraform

Terraform fait partie des outils développés par l’entreprise américaine HashiCorp.

Si l’application n’a pas inventé le principe de IAC pour Infrastructure As Code, elle a grandement participé à sa démocratisation au point de devenir un véritable standard.

L’avènement du IAC est à mettre en parallèle de l’avènement du cloud public.

La possibilité initiée par AWS en 2006 de consommer de l’infrastructure informatique comme l’on consomme de l’électricité, c’est-à-dire à la demande, n’importe où et instantanément a changé la manière d’opérer une infrastructure.

Là ou chaque cloud provider c’est mis à proposer (et propose toujours) sa solution IAC, Terraform a eu la bonne idée de rendre le principe d’Infrastructure As Code transverse à l’écosystème cible, y compris sur les architectures OnPrem.

Disponible « gratuitement » à partir de 2014, Terraform permet de capitaliser sur la virtualisation de l’infrastructure et l’explosion du cloud pour décrire de manière cohérente ses composants d’architecture : stockage, réseaux, VM….Tout peut être indiqué dans le langage HCL

Grâce à des providers tiers il est ensuite possible de “transformer” son code en brique d’infrastructure.

Terraform ne tient pas compte de l’existant, uniquement de ce que vous pourrez décrire dans votre code.

Si l’on commence avec Terraform, alors il faut s’y tenir, car mélanger un déploiement IAC et standard peut créer des incohérences.

L’avantage du IAC est de pouvoir tracer et versionner son infrastructure ainsi que de redéployer rapidement ou cloner son environnement de travail.

Terraform cloud

Logo Terraform Cloud

Cliquez sur l'image pour l'agrandir.

Terraform peut s’utiliser en dehors de son offre cloud. Mais cette dernière est très intéressante puisqu’elle permet gratuitement de bénéficier de deux avantages:

  • Gérer ses configurations et suivre leur déploiement en équipe
  • Opérer des déploiements à distance

D’autres fonctions sont disponibles dans la version payante , mais l’offre gratuite est déjà sympathique.

Offre Terraform Cloud

Cliquez sur l'image pour l'agrandir.

En effet, lorsque vous exécutez Terraform sur votre poste, celui-ci va générer des fichiers liés à ses actions et à l’état de vos déploiements. Si une autre personne doit reprendre votre travail, il est nécessaire de lui fournir ces éléments, sans quoi Terraform n’aura pas connaissance des actions précédentes et donc des actions à réaliser ou non, fonction des modifications apportées par votre collègue.

Principes de terraform

Cliquez sur l'image pour l'agrandir.

Ce besoin d’avoir toujours à disposition ce référentiel des dernières taches réalisées peut vite devenir problématique dans le cadre d’une utilisation en entreprise ou plusieurs personnes peuvent manipuler la même infrastructure décrite dans le code HCL.

Plusieurs solutions sont possibles, dont la solution Terraform Cloud intégrée à la « HashiCorp Cloud Platform ».

En utilisant Terraform Cloud, vous et votre collègue pouvez partager un espace de travail commun ou chaque lancement local pourra se synchroniser avec le cloud et garantir ainsi le même référentiel Terraform.

De plus, Terraform cloud vous permet de déclencher des déploiements sur événements sans avoir besoin du binaire Terraform, notamment quand il s’agit d’agir chez un cloud provider public.

Vous pouvez par exemple, faire en sorte qu’en poussant votre code HCL dans un repo GIT vous déclenchiez automatiquement une lecture de ce dernier et une exécution de terraform directement depuis le cloud vers l’environnement cible.

Usage de Terraform Cloud

Rendez-vous sur le site de Terraform et créez-vous un compte.

Terraform Cloud Creation de compte

Cliquez sur l'image pour l'agrandir.

Puis créez votre organisation, celle-ci pourra être partagée avec d’autres personnes qui disposent également d’un compte Terraform et qui travaillent sur les mêmes infrastructures que vous.

Creation d'une organisation

Cliquez sur l'image pour l'agrandir.

Creation d'une organisation

Cliquez sur l'image pour l'agrandir.

Maintenant que nous avons une organisation, nous allons pouvoir créer un « Workspace ». Chaque Workspace correspond à un projet ou une infrastructure.

Il est possible d'intéragir avec un « Workspace » via plusieurs solutions.

  • Version Control : le déclenchement d'un déploiement se fait suite à une action réalisée sur un outil de gestion de source. Par exemple, avec GitLab. La création de votre infrastructure se fait automatiquement à chaque commit de votre code
  • API : le déclenchement d'un déploiement se fait via l'interraction avec l'API
  • CLI : le déclenchement d'un déploiement se fait via l'interraction avec la CLI. C'est la méthode qui sera décrite ici

Il suffit de nommer son workspace et d'indiquer une description.

Creation d'un workspace

Cliquez sur l'image pour l'agrandir.

Creation d'un workspace

Cliquez sur l'image pour l'agrandir.

Une fois votre workspace créé, il est possible de définir le mode d'exécution du workspace via l'option "General" puis "Execution Mode" pour choisir "Custom".

Un workspace peut avoir trois modes d’exécution.

  • Remote : dans ce cas, c’est directement Terraform Cloud qui s’occupe d’exécuter votre code sur votre environnement cible. Cela suppose que Terraform Cloud ait un accès à votre écosystème. C'est une option à privilégier lorsque vous déployez sur un cloud public
  • Agent : dans ce cas, Terraform Cloud communique avec un agent déployé sur votre environnement cible.
  • Local : dans ce cas c’est vous qui faites appel au binaire terraform et c’est depuis votre poste que le déploiement se fait. Vous utilisez alors Terraform Cloud pour synchroniser vos modifications, mais pas pour l’exécution des commandes.
  • Configuration du workspace

    Cliquez sur l'image pour l'agrandir.

Pour l’exemple je vais déployer une VM sur mon environnement VMWARE privée. Je vais donc choisir un worspace local, puisque Terraform Cloud n’a pas accès à mon environnement onprem.

Mon workspace étant prêt, il me reste à créer mon token API. C’est grâce à lui que je vais pouvoir m’authentifier depuis mon poste local à Terraform Cloud.

Il suffit pour cela d’aller dans les paramètres de son compte et de faire la demande de token.

Création d'un token

Cliquez sur l'image pour l'agrandir.

Création d'un token

Cliquez sur l'image pour l'agrandir.

Création d'un token

Cliquez sur l'image pour l'agrandir.

Création d'un token

Cliquez sur l'image pour l'agrandir.

Il faut bien évidemment conserver ce token dans un endroit sûr et ne pas le partager.

Dans la capture, je m'autorise un token sans date d'expiration. Dans un usage en production, c'est evidemment une option à proscrire. La review des tokens est essentiel pour éviter des accès non souhaités. De même, utilisez une description précise, et surtout évitez le token "du peuple". Privilégiez un token par usecase et par user.

Terraform se récupére sous la forme d’un simple binaire disponible pour différentes plateformes.

Récupération du binaire

Cliquez sur l'image pour l'agrandir.

Il suffit d’inclure l’emplacement de l’exe à son path local pour pouvoir appeler une commande terraform depuis n’importe quel emplacement de son poste.

Modification du path

Cliquez sur l'image pour l'agrandir.

Je vais utiliser la commande terraform login et utiliser mon token API récupéré précédemment pour m’authentifier sur le cloud terraform.

Authentification

Cliquez sur l'image pour l'agrandir.

Authentification

Cliquez sur l'image pour l'agrandir.

Comme indiquez par le retour de ma commande. La configuration (donc mon token) est enregistrée dans mon profil utilisateur sous C:\Users\mon_user\AppData\Roaming dans le dossier terraform.d

L’écosystème terraform est maintenant prêt à être utilisé. Je ne suis pas obligé d’utiliser le cloud Terraform comme backend pour la syncho de l’état de mes déploiements. Je peux rester avec une création des fichiers en local.

Mais si je veux faire sorte que mon projet tire parti du workspace que j’ai créé dans Terraform cloud, il me suffira d’ajouter au dossier local des fichiers de déploiement , un fichier « backend.tf » avec le contenu suivant:

  
  terraform {
    cloud {
      organization = "COOLCORP-IAC"
      workspaces {
        name = "devk8sctp501"
      }
    }
  }
  
  

De cette manière lorsque je ferais appel au binaire Terraform, celui-ci saura qu’il devra utiliser mon workspace devk8sctp501 dans le cloud terraform.

Étant donné que j’ai configuré mon accès cloud avec mon token API, le binaire pourra s’authentifier auprès de mon organisation dans le cloud Terraform.

Exemple de déploiement d'un VM sous VMware

La description de l’infrastructure à déployer se fait au sein de fichier portant génélement l’extension .tf que l’on va placer à la racine d’un dossier.

Organisation et roles des fichiers tf

Plusieurs stratégie sont possibles, mais, mais je trouve plus pratique de segmenter mes fichiers tf par fonction/rôle plutôt que d’utiliser un seul et même fichier pour tout.

La logique retenue est la suivante

  • Un fichier backend.tf

Comme vu précédemment, celui-ci permet d’indiquer qu’on souhaite utiliser un workspace dans le cloud Terraform.

  
  terraform {
    cloud {
      organization = "COOLCORP-IAC"
      workspaces {
        name = "devk8sctp501"
      }
    }
  }
  
  
  • Un fichier provider.tf

Celui-ci permet d’indiquer que l’on va avoir besoin du provider vSphere pour ajouter à Terraform la capacité de déployer des ressources dans l’environnement vSphere.

  
    provider "vsphere" {
      user           = var.vsphere_user
      password       = var.vsphere_password
      vsphere_server = var.vsphere_server
    
      # If you have a self-signed cert
      allow_unverified_ssl = true
    }       
  
  

Si Terraform permet de faire du IAC dans deux nombreux écosystèmes cloud et privé, il est nécessaire de lui faire récupérer le provider associé. Souvent celui-ci est proposé par l’éditeur de l’écosystème lui-même. Attention donc, avec Terraform vous pourrez par exemple aussi bien déployer une VM dans AWS, Azure, GCP ou autres, mais pas avec les mêmes fichiers !

Lorsque je parle en début d’article d’une manière transverse de faire du IAC, il s’agit d’exploiter un meme produit et un meme language, mais chaque provider dispose de ses propres ressources et de sa manieres de les décrires/configurer.

La syntaxe HCL reste la même, mais les ressources décrites sont propres à chaque provider.

Chaque provider impose un certains nombre de parametres. Dans le cas de vSphere, il faut préciser l'URL du vcenter et les informations d'authentification. Ici, on va variabiliser les informations demandées.

Sachez également, que contrairement à l'exemple présenté ici, il est conseillé de fixer la version du provider retenu, via l'option version. En effet, l'éditeur peut faire évoluer le provider à fur à mesure que son écosystème évolu.

Il n'est pas évident que votre infrastructure interne soit supportée par la derniere version du provider si vous n'etes pas à jour en rapport à la derniere version de l'écosystème proposé par l'éditeur.

Si vous ne fixez pas la version du provider, celui ci sera constamment récupéré dans sa derniere version, ce qui peut du jour au lendemain casser l'intéraction avec votre infrastructure

  • un fichier vsphere.tf
  
    data "vsphere_datacenter" "dc" {
      name = "${var.vsphere_datacenter}"
    }
    
    data "vsphere_compute_cluster" "cluster" {
      name          = "${var.vsphere_cluster}"
      datacenter_id = "${data.vsphere_datacenter.dc.id}"
    }
    
    data "vsphere_network" "network_lan" {
      name          = "${var.vlan_lan}"
      datacenter_id = "${data.vsphere_datacenter.dc.id}"
    }
    
    data "vsphere_virtual_machine" "template" {
      name          = "${var.vsphere_template}"
      datacenter_id = "${data.vsphere_datacenter.dc.id}"
    }  
  
  

Il contient uniquement quelques définition d'objets propres à vSphere.

  • un fichier variables.tf
  
    #######################Variables vsphere

    variable "vsphere_user" {
      default = "svc_prd_terraform@coolcorp.priv"
    }
    
    variable "vsphere_password" {
        type = string
        sensitive = true
    }
    
    variable "vsphere_server" {
      default = "vcenter.coolcorp.priv"
    }
    
    variable "vsphere_datacenter" {
      default = "Paris"
    }
    
    variable "vsphere_cluster" {
      default = "COOLCLUSTER"
    }
    
    variable "vsphere_template" {
      default = "prdtplk8s501"
    }
    
    
    
    ################################### Variables Network
    
    variable "vlan_lan" {
      default = "LAN"
    }
    
    
    variable "gateway_lan" {
      default = "192.168.10.253"
    }
    
    
    variable "default_dns" {
      default = "192.168.10.35"
    }
    
    variable "default_dns_domain" {
      default = "coolcorp.priv"
    }
    
    
    #################################### Variables K8S
    
    ####Detail VM
    
    variable "vm_01_name" {
      default = "devk8sctp501"
    }
    
    variable "vm_01_dts" {
      default = "VL1"
    }
    
    variable "vm_01_cpu_number" {
      default = "4"
    }
    
    variable "vm_01_memory_size" {
      default = "4096"
    }
    
    variable "vm_01_ip_address" {
      default = "192.168.10.66"
    }
    
    variable "vm_01_ip_netmask" {
      default = "24"
    }
    

Ce fichier permet d’indiquer toutes les variables nécessaires à mon déploiement et qui pourront être réutilisées dans différentes ressources. Ça permet de centraliser leur configuration et de ne pas repasser sur chaque fichier qui les utilise.

Certaines variables peuvent avoir un contenu critique. C’est le cas dans mon exemple, puisque Terraform doit disposer d’accès à mon vCenter pour provisionner ma VM cible.

La encore plusieurs stratégies sont possibles pour protéger ses informations de connexions. La plus simple est celle exprimé ici, ou je vais simplement indiquer à Terraform de me demander le password associé à mon compte pour l’accès au vcenter, au moment de l’exécution du code.

Une autre manière de faire serait de faire appel à un autre produit de l’éditeur, Vault, un gestionnaire de secret, lui aussi extrêmement utilisé.

Issu de Hashicorp également, Vault s’integre très bien avec Terraform, et ce dernier peut discuter avec une instance Vault pour récupérer toutes informations sensibles nécessaires au déploiement.

C’est un modèle très pertinent en entreprise mais que je ne détaillerais pas ici.

  • un fichier vm.tf
  
    data "vsphere_datastore" "datastore_vm_01" {
      name          = "${var.vm_01_dts}"
      datacenter_id = "${data.vsphere_datacenter.dc.id}"
    }
    
    
    resource "vsphere_virtual_machine" "vm_vm_01" {
      name             = "${var.vm_01_name}"
      resource_pool_id = "${data.vsphere_compute_cluster.cluster.resource_pool_id}"
      datastore_id     = "${data.vsphere_datastore.datastore_vm_01.id}"
    
      num_cpus = "${var.vm_01_cpu_number}"
      memory   = "${var.vm_01_memory_size}"
      guest_id = "${data.vsphere_virtual_machine.template.guest_id}"
    
      scsi_type = "${data.vsphere_virtual_machine.template.scsi_type}"
    
      network_interface {
        network_id   = "${data.vsphere_network.network_lan.id}"
        adapter_type = "${data.vsphere_virtual_machine.template.network_interface_types[0]}"
      }
    
      disk {
        label            = "disk0"
        size             = "${data.vsphere_virtual_machine.template.disks.0.size}"
        eagerly_scrub    = "${data.vsphere_virtual_machine.template.disks.0.eagerly_scrub}"
        thin_provisioned = "${data.vsphere_virtual_machine.template.disks.0.thin_provisioned}"
      }
    
      clone {
        template_uuid = "${data.vsphere_virtual_machine.template.id}"
         customize {
          linux_options {
            host_name = "${var.vm_01_name}"
            domain    = "coolcorp.priv"
          }
            network_interface {
              ipv4_address = "${var.vm_01_ip_address}"
              ipv4_netmask = "${var.vm_01_ip_netmask}"
          }
          ipv4_gateway = "${var.gateway_lan}"
          dns_suffix_list = ["${var.default_dns_domain}"]
          dns_server_list = ["${var.default_dns}"]
       }
      }
    }

Ce fichier contient toutes les caractéristiques de la VM (ici devk8sctp501) que je souhaite déployer : depuis quel template, avec quelle configuration matérielle, connectée à quel réseau…

On peut ensuite ajouter autant de fichiers tf que de ressources à gérer, ou bien rassembler dans un fichier des ressources de mêmes types : les VMs, le réseau, le stockage…

Dans tous les cas, la documentation de Terraform est plutôt bien faite avec des exemples propres à chaque provider utilisé.

Deploiment et commandes

Maintenant que l’infrastructure est décrite dans des fichiers via le langage HCL, on va pouvoir faire appel à Terraform.

La première commande terraform init permet d’initialiser le déploiement. C’est notamment dans cette phase que Terraform va récupérer directement sur Internet le ou les providers nécessaires.

terraform init

Cliquez sur l'image pour l'agrandir.

Puis on utilise la commande terraform plan

terraform plan

Cliquez sur l'image pour l'agrandir.

terraform plan

Cliquez sur l'image pour l'agrandir.

Cette phase va permettre de « planifier » le déploiement. A ce stade aucune action concrète n’est encore réalisée. Terraform va comparer le contenu de nos fichiers à son dernier référentiel pour savoir ce qui doit être modifié/ajouté/supprimé.

Étant donné qu’il s’agit d’une première exécution, le référentiel est inexistant. Il n’y aura donc pas de point de comparaison : pour rappel Terraform ne tient pas compte des ressources que vous auriez pu déployer en dehors de son usage. Si par exemple dans mon cas, je crée une VM X avant d’utiliser Terraform puis que je déclare cette VM dans un fichier HCL avec une configuration différente, Terraform ne modifiera pas ma VM existante… Il va tous simplement essayer de la recréer, car pour lui elle n’existe pas….Et cela ne va donc pas fonctionner.

Veuillez noter que Terraform me demande en input le password d'accès à mon vCenter. La donnée étant marquée comme sensible dans mon fichier variables.tf, ce dernier ne sera pas afficher en sortie.

Si la phase plan se termine sans erreur, alors on peut lancer la dernière opération via la commande terraform apply.

terraform apply

Cliquez sur l'image pour l'agrandir.

terraform apply

Cliquez sur l'image pour l'agrandir.

C’est lors de cette phase que le déploiement va réellement se faire et que la VM va être créée sur l’environnement vSphere.

Fin du déploiement

Cliquez sur l'image pour l'agrandir.

L’avantage d’avoir utilisé le cloud terraform comme backend c’est qu’au lieu de simplement avoir dans mon dossier les fichiers de référentiel générés lors du déploiement, j’ai accès au résumé des actions et je peux suivre ce qui a été fait.

Terraform Cloud

Cliquez sur l'image pour l'agrandir.

Terraform Cloud

Cliquez sur l'image pour l'agrandir.

Terraform Cloud

Cliquez sur l'image pour l'agrandir.

Attention toutefois à ne pas vous séparer du contenu du dossier .terraform au sein de votre répertoire de travail. En dehors du cloud terraform, c’est votre seule source pouvant servir de référence pour vos futurs déploiements.

Pour rappel Terraform « trace » ses actions et maintient son référentiel sous forme de fichiers à chaque exécution. Pour toutes modifications de vos configurations HCL, ces dernières sont comparées au référentiel et c’est ainsi que Terraform en déduit ce qui doit être fait.

Dossier contenant les opérations réalisées par Terraform

Cliquez sur l'image pour l'agrandir.

Si vous avez déployé une VM « X » avec terraform, puis que vous la modifiez en dehors de Terraform, si vous décidez à nouveau de revenir à terraform pour une seconde modification, Terraform ne sera pas informé de ce que vous avez pu faire avant.

Maintenant que nous pouvons déployer rapidement et simplement tout un ensemble de VMs à partir d’un template, il va être plus simple de décrire tous ses nœuds Kubernetes dans un projet Terraform de manière à automatiser le déploiement du cluster.

OpenTofu

À l’origine Terraform a été publié sous licence Mozilla Public Licence, autorisant un usage permissif de l’outil avec très peu d’obligation envers Hashicorp. Mais en aout 2023, l’éditeur a changé son modèle pour se tourner vers une licence « Business Source Licence ».

C’est malheureusement un tournant pris par pas mal d’éditeur auparavant open source, comme Grafana, Elastic Search ou encore récemment Redis. Certains ont crié au scandale, mais personnellement je peux comprendre ces changements. Le modèle économique de l’open source reste compliqué, et tout le monde ne joue pas franc jeu.

Terraform est au cœur de solutions commerciales qui se reposent sur les investissements et le code de Hashicorp, sans pour autant que ce dernier puisse bénéficier des gains engrangés par ces offres tierces.

La bascule sur une licence BSL rend toujours possible l’usage de terraform gratuitement… Mais limite désormais la possibilité pour des éditeurs tiers, des consultants ou intégrateur « d’embarquer » ou d’« héberger » les éditions communautaires des produits hashicorp.

Caractéristique Mozilla Public License (MPL) Business Source License (BSL)
Type de Licence Licence libre et open-source Licence propriétaire modifiée
Accès au Code Source Oui, complet Accès partiel; le code devient open-source après un délai spécifié
Modifications Les modifications doivent également être sous MPL Les modifications peuvent être soumises à des restrictions plus fortes
Utilisation commerciale Permise sans restrictions Souvent soumise à des restrictions, dépend des termes spécifiques de la BSL
Distribution Libre, tant que les modifications restent sous MPL Peut être limitée ou restreinte selon les termes de la licence
Compatibilité avec d'autres licences Compatible avec d'autres licences open-source Peut avoir des problèmes de compatibilité avec d'autres licences open-source
Contribution des modifications Les contributions doivent être sous la même licence Pas nécessairement requises, dépend des termes de la licence
Popularité et Adoption Largement utilisée dans des projets open-source Utilisée principalement par des entreprises offrant des produits avec un modèle "open-core"
Objectif principal Promouvoir et protéger le développement de logiciels open-source Protéger le modèle commercial de l'entreprise tout en offrant un accès anticipé au code source

Toucher à l’open source ne se fait jamais sans heurt. Il n’a pas fallu longtemps pour que la communauté s’organise et fork le projet pour donner vie à OpenTofu sous la bienveillance de la Linux Foundation.

Logo OpenTofu

Cliquez sur l'image pour l'agrandir.

Au moment d’écrire cet article, OpenTofu est 100% compatible avec Terraform 1.6, et l’usage de l’un ne bloque pas l’usage de l’autre…mais rien n’est garanti à l’avenir et des écarts potentiels peuvent apparaitre au fil des versions.

Me concernant, je compte basculer progressivement sous OpenTofu sans pour autant me désintéresser de terraform. Il reste encore des zones d’ombre et des divergences récentes (au moment de la rédaction de cet article) émergent déjà entre harshicorp et OpenTofu, le premier accusant le second de ne pas respecter la nouvelle licence adoptée pour terraform.

A l'usage, et à mon (faible) niveau, je n'ai pas remonté de différences

De la même maniere que pour terraform, le binaire peut se récupérer directement sur le site officiel et s'ajouter au path local du poste. L'exe est simplement tofu

Récupération du binaire OpenTofu

Cliquez sur l'image pour l'agrandir.

Pas la suite, les commandes sont idendiques à terraform :

  • tofu init
  • tofu plan
  • tofu apply

J'ai même pu m'appuyer sur le "state" généré par terraform, pour le reprendre par OpenTofu. J'ai simplement eu à modifier mon fichier backend.tf pour ajouter le hostname du cloud terraform, car celui-ci n'est pas implicite avec OpenTofu.

    
    terraform {
      cloud {
        organization = "COOLCORP-IAC"
        hostname = "app.terraform.io"
        workspaces {
          name = "devk8sctp501"
        }
      }
    }
    
    

Je n'ai pas encore parlé de cette commande, mais comme pour terraform, l'ajout du mot clef destroy supprime toute l'infrastructure déployée.

Suppression de l'infrastructure

Cliquez sur l'image pour l'agrandir.

Suppression de l'infrastucture

Cliquez sur l'image pour l'agrandir.

Il conviendra de suivre les divergences qui pourraient apparaitres entre les deux outils. En l'état, que vous reteniez l'un ou l'autre, la logique reste la même.

Le IAC est devenue une base, et qu'il s'aggisse de Terraform ou OpenTofu, décrire son infrastructure avec du code est devenu une bonne pratique que je vous encourage à adopter.