Sortie de Terraform 0.9

25
17
mar.
2017
Cloud

Le 15 mars 2017 a été annoncée la sortie de la version 0.9 de Terraform par HashiCorp (Vagrant, Consul, Nomad, etc.).

Terraform est un outil d’Infrastructure as Code qui permet de décrire et créer son infrastructure sous forme d’un code source déclaratif. Il est en partie équivalent à des outils tels puppet, Ansible ou Chef (pour la partie infrastructure).

Pour ce faire il s’appuie sur un ensemble de providers permettant de manipuler des ressources Amazon Web Services, Google Cloud, OpenStack, mais aussi Docker, Nomad, etc. La liste est longue et continue régulièrement à s’agrandir.

Sommaire

Exemple

Pour mieux comprendre, voici deux petits exemples de ce qui peut être réalisé.

Le premier crée une instance dans un cloud OpenStack en y attachant un volume de données :

resource "openstack_blockstorage_volume_v1" "myvol" {
  name = "myvol"
  size = 1
}

resource "openstack_compute_instance_v2" "volume-attached" {
  name            = "volume-attached"
  image_id        = "ad091b52-742f-469e-8f3c-fd81cadf0743"
  flavor_id       = "3"
  key_pair        = "my_key_pair_name"
  security_groups = ["default"]

  network {
    name = "my_network"
  }

  volume {
    volume_id = "${openstack_blockstorage_volume_v1.myvol.id}"
  }
}

Le deuxième définit une image pour Docker et crée un conteneur avec elle :

# Configure the Docker provider
provider "docker" {
  host = "tcp://127.0.0.1:2376/"
}

# Create a container
resource "docker_container" "foo" {
  image = "${docker_image.ubuntu.latest}"
  name  = "foo"
}

resource "docker_image" "ubuntu" {
  name = "ubuntu:latest"
}

Nouveautés de la 0.9

Provisionneurs à la destruction

Depuis les débuts de Terraform, un système d’approvisionnement permet d’exécuter des actions locales ou distantes lors de la création d’une ressource. Par exemple, vous voulez qu’un script shell soit exécuté à la création d’un serveur ; désormais, vous pouvez aussi réaliser cette action à la destruction. Cela peut permettre à un serveur membre d’une grappe d’envoyer un message indiquant qu’il va quitter la grappe juste avant que cela ne soit effectif.

Voici un exemple où un membre d’une grappe de serveurs Consul indique qu’il quitte la grappe au moment de la destruction :

resource "aws_instance" "consul" {
  # ... other fields

  provisioner "remote-exec" {
    command = "consul leave"
    when = "destroy"
  }
}

Verrouillage de l’état

Afin de pouvoir savoir quelles actions doivent êtres réalisées à chaque exécution, Terraform sauvegarde l’état courant de l’infrastructure dans un fichier. Avec cette solution il n’était pas possible d’exécuter simultanément (par exemple, par deux personnes différentes) plusieurs fois Terraform. Pour prévenir ce problème, il fallait s’appuyer sur des outils externes du type de Terragrunt.

Désormais, Terraform est capable de poser un verrou au niveau de l’état, que l’infrastruture soit stockée localement (dans un fichier), sur AWS S3 ou dans Consul. D’autres prises en charge vont être ajoutées dans les versions 0.9.x, ainsi que des fonctionnalités avancées de verrouillage.

C’était attendu avec impatience, non que Terragrunt ne fasse pas son boulot, mais cela va permettre de réduire le nombre d’outils mis en œuvre pour réaliser les actions de base.

Approvisionnements interruptibles

Terraform a toujours su s’arrêter proprement sur un Ctrl + c. Mais, pour rester dans un état cohérent, il devait attendre que la tâche courante se termine. Certaines tâches prenant parfois plusieurs minutes, cela n’était pas optimal (par exemple, création d’une instance de base de données chez Amazon). Désormais, Terraform va rendre la main sans attendre et marquer l’instance comme tainted ce qui forcera sa recréation à la prochaine exécution.

Gestion des environnements

Si vous avez de multiples environnements pour votre projet (par exemple, staging, pré‐production, production) rien n’était fait jusqu’à présent pour vous faciliter la vie. Comme dit plus haut, Terraform stocke l’état de l’infrastructure dans un fichier. Mais, qui dit multiples environnements, dit multiples fichiers d’états à partir d’un même code et probablement de multiples fichiers de variables pour stocker des identifiants différents par environnement. Et ce n’était tout simplement pas géré.

Avant la version 0.9, nous utilisions une surcouche à base de Makefile pour gérer tout ceci :

apply:
    $(TERRAFORM_BIN) apply -state=$(call getenv).tfstate -var environment=$(call getenv) -var-file=$(call getenv).tfvars

Ce qui permettait de faire (je vous ai masqué un peu les détails) make apply env=staging ou make apply production.

Certes, ça fonctionne, mais c’est mieux de l’éviter pour se concentrer sur des choses de plus grande valeur et pour gagner en fiabilité.

Avec la 0.9, il est donc possible d’avoir de multiples environnements :

$ terraform env list
  default
* mitchellh-test

$ terraform env select default
Switched to environment "default"!

$ terraform env delete mitchellh-test
Deleted environment "mitchellh-test"!

Et une nouvelle interpolation ${terraform.env} permet de connaitre l’environnement dans les fichiers Terraform :

resource "aws_instance" "example" {
  count = "${terraform.env == "default" ? 5 : 1}"

  tags { Name = "web - ${terraform.env}" }

  # ... other fields
}

Réorganisation du stockage distant de l’état

Nous avons vu plus haut le nouveau verrouillage des fichiers d’état, y compris pour le stockage distant.

Le stockage des états à distance a été revu en profondeur pour un usage plus agréable et une meilleure confiance. Par exemple, si un stockage distant est configuré, Terraform en ligne de commande va l’utiliser préférentiellement au fichier d’état local.

DataSources pour Ignition

C’est un point qui n’est pas présent dans le billet de sortie de la version 0.9, mais il fait partie des améliorations que nous utilisons en production depuis quelques temps.

Nous utilisons Terraform pour instancier des grappes de serveurs CoreOS. Les machines nécessitant souvent quelques actions initiales (par exemple, formater et monter un disque) nous utilisons pour cela Ignition qui au premier amorçage va configurer ces éléments plutôt bas niveau. Or, la prise en charge d’Ignition était loin d’être parfaite, avec certains comportements plutôt désagréables.
Avec la version 0.9 la manière de gérer Ignition a été fortement améliorée.

Voici un exemple réel (un poil allégé tout de même) montrant la configuration d’un serveur qui va installer un service systemd directement au premier démarrage :

# Définition de l’unité systemd se trouvant dans le fichier data/elasticsearch.service
data "ignition_systemd_unit" "elasticsearch" { 
  name    = "elasticsearch.service" 
  content = "${file("${path.module}/data/elasticsearch.service")}"
}

# Définition d’un serveur prenant en charge elasticsearch
resource "aws_instance" "es_srv" {
  # ... paramètres de l'instance, taille, etc

  # Indique la configuration à appliquer au premier boot
  user_data = "${data.ignition_config.es_srv.rendered}"
}

# Configuration systemd (ou autre)
data "ignition_config" "es_srv" {
  systemd = [
    "${data.ignition_systemd_unit.elasticsearch.id}",
  ]
}

Open Source

Le développement de Terraform est ouvert. Terraform (ainsi que les autres outils de HashiCorp) fait partie de ces projets où il est facile d’échanger avec l’équipe de développeurs, que ce soit pour rapporter des bogues ou pour proposer des améliorations.
Le projet est sous licence publique Mozilla version 2.

Suite des développements

Le développement de la version 0.9.1 est déjà en route, avec entre autres un nouveau provider pour Kubernetes, l’orchestrateur de conteneurs de Google qui a bien le vent en poupe en ce moment.

Aller plus loin

  • # hors cloud, point de salut ?

    Posté par  . Évalué à 2.

    Si j'ai bien tout compris, l'intérêt par rapport à puppet/ansible/chef et autres, c'est que Terraform fait le provisionning des machines en s'interfaçant avec différentes solution de cloud à la mode.

    Un truc qui m'a fait sourire: pour provisionner une machine, on fait appel à des providers.
    Et ce qui dans puppet s'appelle un provider s'appelle un provisioner dans Terraform.

    Et j'en viens à ma question : existe-t-il un provider permettant de faire du provisionning sur une machine réelle ?

    Oui je sais c'est sale, mais le bas peuple en utilise encore en masse :-)

    P.S : provisionner une machine est clairement un affreux néologisme/barbarisme, si vous avez mieux je suis preneur.

    • [^] # Re: hors cloud, point de salut ?

      Posté par  (site web personnel) . Évalué à 2.

      Terraform est cool pour gérer toute la chaine, de la création de la machine à sa conf. Dans le cadre d'une machine physique classique le problème est que ça manque d'API pour communiquer avec :-)

      Si on ne parle que de machines physiques vs machines virtuelles, il y a un provider pour packet.

      Après j'ai jamais testé ce point, mais peut-être qu'on peut jouer avec des null_resource pour pouvoir agir sur des éléments non créés par terraform.

      Il faudrait regarder du côté de connection et de null_resource.

      • [^] # Re: hors cloud, point de salut ?

        Posté par  . Évalué à 3.

        Dans le cadre d'une machine physique classique le problème est que ça manque d'API pour communiquer avec

        Lorsqu'on installe une machine virtuelle, il y a effectivement une API pour créer puis lancer la machine virtuelle, mais tout le reste c'est le même principe que pour une machine physique : on a une « image » qui est installée via un programme d'initialisation chargé en TFTP par exemple. Ou via un démarrage sur clef USB qui va ensuite chercher l'image à installer.

        • [^] # Re: hors cloud, point de salut ?

          Posté par  (site web personnel) . Évalué à 2.

          Bien sur mais là le but c'est de piloter tout ça. Terraform via ses providers va appeler les api. Par exemple appeler l'api de packet.net pour instancier une nouvelle machine.

          En local et physique le principe est peut-être le même mais je n'ai pas d'api pour appuyer sur le bouton du serveur, ni pour brancher la clé usb et sélectionner l'entrée dans le bios ;-)

          • [^] # Re: hors cloud, point de salut ?

            Posté par  . Évalué à 3.

            C'est pour ça que les outils qui permettent cela (genre The Foreman) utilise principalement PXE (voir pour certains, l'IPMI, qui te permet de sélectionner l'entrée dans le bios par exemple) qui te permet de lancer une installation automatiquement (et tu peux distinguer le preseed par mac).

            « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

          • [^] # Re: hors cloud, point de salut ?

            Posté par  (site web personnel) . Évalué à 1.

            Le bios est in problems en soi.

            Avec coreboot, on a au joins une console serie pour scripter et faire des choses.

    • [^] # Re: hors cloud, point de salut ?

      Posté par  (site web personnel) . Évalué à 4. Dernière modification le 17 mars 2017 à 13:00.

      Terraform a des notions de provisioners et de providers.

      On trouve de quoi utiliser docker ou lxc depuis Ansible, puppet, chef ou terraform.

      Provisionner : « prévoir en tant que provision » dans le domaine de la comptabilité. En pratique, ici on ne fait pas que « prévoir » une machine, on la construit.

  • # euh ?

    Posté par  (site web personnel) . Évalué à 3.

    Et sinon quel est la différence avec Ansible par exemple ?

    J'ai toujours l'impression que le but est de faire un script pour gérer une grappe de serveur virtuel ou non.

    "La première sécurité est la liberté"

    • [^] # Re: euh ?

      Posté par  (site web personnel) . Évalué à 4.

      Il est évident que cela se recoupe sur certains points.
      Ĺ'une des différences est que les outils comme ansible sont avant tout des outils de gestion de configuration alors que terraform est plus un outil d'orchestration. Terraform est surtout là pour créer les serveurs et faire les premières étapes de provisionnement, de configuration. On peut d'ailleurs très bien associer terraform pour le bas niveau et ansible pour le plus haut niveau, le configuration des serveurs, des applications, etc. Je l'ai sur un projet et ça fait le boulot.

      Sur le projet sur lequel je bosse on associe terraform avec mgmt pour faire justement la gestion de la configuration. C'est (très) jeune mais sympa à utiliser.

      Une autre différence est sur la façon d'envisager l'outil. Terraform se base sur une notion d'immutabilité. On peut exécuter n fois de suite le même terraform sans problème, le premier va créer ce qu'il faut et, sauf changement, les autres ne feront rien du tout. Au contraire de certains outils qui vont relancer des commandes systématiquement.

      Les frontières sont parfois minces entre les différentes catégories, les outils se recoupent souvent aussi.

      Pour avoir un aperçu des différences entre Terraform et d'autres outils : https://blog.gruntwork.io/why-we-use-terraform-and-not-chef-puppet-ansible-saltstack-or-cloudformation-7989dad2865c

    • [^] # Re: euh ?

      Posté par  (site web personnel) . Évalué à 2.

      J'avais oublié, il y a quand même une sacré différence entre terraform et ansible : ansible nécessite d'avoir python sur la machine cible (il va exécuter du python au travers de ssh).

      Dans mon cas les machines cibles n'ont pas python et tant que possible je ne souhaite absolument pas le mettre (ni ruby, perl ou autre chose du genre). Certes c'est plus intéressant que d'avoir un système d'agent mais tout de même, la dépendance à python est un gros frein.

      Le deuxième frein est justement ce que j'ai mis entre parenthèse au dessus, ansible va se connecter à chaque machine et exécuter ce qu'il faut. Une fois qu'on commence à avoir pas mal de machines c'est une latence qui n'est pas agréable. L'idée est d'utiliser mgmt (cf plus haut) qui se base sur le cluster etcd formé par les machines. Il devient donc possible de répliquer très facilement la conf, le provisionning, en agissant que sur un membre d'un cluster et non tous.

      • [^] # Re: euh ?

        Posté par  . Évalué à 3.

        Il y a moyen de faire sans Python avec Ansible. Mais ça ne semble pas adapté au cas que tu décris http://docs.ansible.com/ansible/raw_module.html

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

    • [^] # Re: euh ?

      Posté par  (site web personnel) . Évalué à 2.

      Je crois que comprendre que Terraform est déclaratif tandis que Ansible est impératif. Ainsi Terraform a une compréhension sémantique que n'a pas Ansible, une conséquence pratique est que Terraform est capable de calculer une sorte de “plus court chemin” transformer l'infrastructure A en infrastructure B. (Ceci dit le seul utilisateur expérimenté de Terraform à qui j'ai parlé m'a dit que Terraform a tendance à tout détruire pour tout reconstruire!)

      • [^] # Re: euh ?

        Posté par  (site web personnel) . Évalué à 4.

        J'ai l'impression que c'est un vrai "model" d'infrastructure. Par contre, le moyen qui l'a pour en connaitre l'état courant, est de garder un fichier sous le coude pour savoir ce qui a été fait. Si il y a une intervention par ailleurs, le fichier est désynchronisé. Il faudrait que le modèle utilise des getter sur l'infrastructure pour connaitre son état au lieu de le conserver "dupliqué".

        Aller de A à B implique une "synchronisation" de l'état précédent avec le nouvelle état. C'est un problème très compliqué à résoudre. (un renommage est-il équivalent à une destruction/création, idem pour un déplacement)

        "La première sécurité est la liberté"

  • # Plugins

    Posté par  (site web personnel) . Évalué à 3.

    D'un point de vue purement théorique sur la manière dont fonctionne terraform, il a un gros avantage par rapport a Ansible, Chef ou Puppet : il stocke son état courant.

    En pratique ça veut dire que lorsqu'on enlève une ressource du fichier terraform, au prochain lancement, il va se souvenir que la ressource existait, quelle n'existe plus, et il tentera de la supprimer. Dans les faits, ça lui permet d'être toujours au plus proche de son état.

    Des outils de gestion de conf classique, en cas de suppression d'une ressource dans les sources, ne vont pas la supprimer. Elle restera là sur les serveurs. Ce qui je trouve peut poser problème. Imagine que ce soit un serveur avec une faille de sécurité… En pratique, la solution est d'indiquer la ressource mais avec une booléen pour dire qu'elle doit être absente. Pas très propre je trouve.

    En constatant cela, j'ai immédiatement pensé a comment faire pour utiliser terraform a la place de puppet, chef ou ansible. En pratique, c'est pas faisable … dans terraform on ne gère pas des fichiers, des services ou d'autres objets existant sur la machine où on exécute terraform. Ce que fait terraform c'est gérer des ressources distantes par API Web.

    Mais en pratique, terraform permet l'écriture de plugins. En théorie rien n'empêche donc d'écrire un plugin qui au lieu de discuter avec une API Web, discutera avec une API d'appel systèmes pour provisionner une machine réelle et pas dans le cloud.

    Après, en pratique, je n'ai pas tenté cette voie parce que terraform n'est vraiment pas fait pour ça, et rien ne dit que ça marchera pour tout faire. Et il n'y aura aucune volonté de merger du code sur ces fonctionnalités upstream. Ce serait un gros hack en quelque sorte. mais si vous avez du temps a faire, ça peut être un truc cool :)

    Sachant qu'il existe un outil : mgmt (déjà discuté plus haut), tout neuf, écrit par un gars de Red Hat qui pourrait remplir ce rôle parfaitement.

  • # Préprocesseur

    Posté par  (site web personnel) . Évalué à 2.

    Est-ce que tu as essayé d'utiliser un préprocesseur générique (comme m4) devant terraform, pour obtenir une plus grande expressivité (et des conditionnelles ;) )

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.