Retour aux articles
5 min de lecture

Terraform marche jusqu'à ce que ça marche plus, essaye Pulumi

Des années de HCL m'ont appris que les vrais langages battent les DSL. Avec Pulumi c'est flagrant.

PulumiTerraformIaC

J’ai passé des années à écrire du Terraform. À le maintenir. À le patcher. J’ai vu HCL évoluer, Terraform devenir un pansement sur une plaie béante, puis la fragmentation avec OpenTofu.

Dans les vrais projets, Terraform devient une pile de contournements. Scripts externes, modules custom, locals en cascade, hacks pour faire ce que le langage peut pas exprimer nativement.

HCL marche pour deux ou trois ressources. Pousse un peu plus loin et tu te noies dans le boilerplate!

Les vrais problèmes

Essaie de traiter des données avant de créer des ressources. Tu peux pas appeler d’APIs, tu peux pas parser du JSON depuis des sources externes, tu peux pas valider de logique métier. T’es limité à ce que les fonctions HCL fournissent.

Besoin de créer des ressources basées sur des calculs runtime? Utilise terraform_data avec des provisioners et des scripts externes. Tu finis par mélanger du script dans ta config déclarative!

Tu veux partager de la logique entre modules? Crée un module. Mais les modules peuvent pas retourner de valeurs computed facilement, ils se composent mal, et tu finis avec des chaînes d’outputs qui cassent dès que quelque chose change.

Des ressources conditionnelles? T’es coincé avec count = var.enabled ? 1 : 0 partout. Et quand tu passes de count à for_each, Terraform veut tout détruire et recréer parce que l’adressage a changé!

Le langage te force dans des patterns pour lesquels HCL a pas été conçu. Tu finis avec des blocks locals qui font de la manipulation de strings, des appels templatefile qui devraient être des fonctions, et des data sources qui tapent dans des scripts externes parce que HCL peut pas exprimer la logique.

Les tests c’est une blague

Tu veux tester ta logique? Terratest. Lance un terraform apply complet dans ta suite de tests juste pour vérifier que ton expression count marche.

Pas de tests unitaires. Pas moyen de valider la logique sans déployer de vraie infrastructure. T’écris du code à l’aveugle en espérant que ça marche quand tu apply!

J’ai débugué des expressions for_each en lançant terraform plan en boucle, ajustant les variables, et devinant ce qui allait pas. C’est pas de l’ingénierie, c’est de l’essai-erreur.

Pulumi c’est du vrai code

Avec Pulumi, t’écris du TypeScript, Python, ou Go. De vrais langages avec de vrais outils.

Même infrastructure, en TypeScript:

const instances = config.environment === 'prod'
  ? [1, 2, 3]
  : [1];

instances.forEach(i => {
  new aws.ec2.Instance(`app-${i}`, {
    ami: config.amiId,
    instanceType: config.environment === 'prod' ? 't3.medium' : 't3.micro',
    ebsBlockDevices: config.volumes.map(v => ({
      deviceName: v.device,
      volumeSize: v.size,
    })),
  });
});

Pas de for_each. Pas de dynamic blocks. Des boucles et des if normaux, comme dans n’importe quel code!

Besoin de réutiliser un bout? T’écris une fonction:

function createInstance(name: string, size: string, volumes: Volume[]) {
  return new aws.ec2.Instance(name, {
    ami: config.amiId,
    instanceType: size,
    ebsBlockDevices: volumes.map(v => ({
      deviceName: v.device,
      volumeSize: v.size,
    })),
  });
}

const prod = ['app-1', 'app-2', 'app-3'];
const instances = prod.map(name =>
  createInstance(name, 't3.medium', config.volumes)
);

Essaie de faire ça en HCL. Impossible. Les modules s’en rapprochent mais c’est lourd et chiant à utiliser.

De vrais tests

Le code Pulumi se teste comme n’importe quel code:

import * as pulumi from '@pulumi/pulumi';
import { createInstance } from './infra';

pulumi.runtime.setMocks({
  newResource: (args) => ({ id: 'mock-id', state: args.inputs }),
  call: (args) => args.result,
});

describe('createInstance', () => {
  it('crée le bon type d'instance pour prod', async () => {
    const instance = createInstance('test', 't3.medium', []);
    const type = await instance.instanceType;
    expect(type).toBe('t3.medium');
  });
});

Tests unitaires. Pas d’infrastructure déployée. Feedback rapide. Tu valides la logique avant d’apply quoi que ce soit!

Le state et les backends marchent pareil

Pulumi a du state. Il le stocke dans des backends comme Terraform. S3, Azure Blob, le service Pulumi, ou self-hosted.

La différence c’est que t’as pas besoin de Terragrunt pour le gérer. Les stacks Pulumi gèrent les environnements nativement:

pulumi stack init dev
pulumi stack init prod
pulumi stack select dev
pulumi up

Chaque stack a son propre state. Pas de fichiers state séparés par workspace, pas de configs backend complexes, pas d’outils wrapper!

‘Mais faut apprendre un langage de programmation’

Non. Pulumi supporte le YAML si c’est ce que tu veux. Même syntaxe déclarative, meilleurs outils.

resources:
  bucket:
    type: aws:s3:Bucket
    properties:
      website:
        indexDocument: index.html

Ça marche comme tu penses. T’as les avantages de Pulumi sans toucher au code!

Mais sérieux: les DevOps savent programmer. Les sysadmin sont pas des débiles qui capent que du YAML. Si tu gères de l’infrastructure à l’échelle, tu peux gérer du TypeScript ou Python.

L’argument ‘je veux pas apprendre à programmer’ c’est de la flemme. T’écris déjà de la logique en HCL, tu debug déjà des systèmes complexes, tu lis déjà du code. Utiliser un vrai langage rend ça plus simple, pas plus dur!

Quand Terraform gagne encore

Si ton équipe connaît que HCL et veut rien apprendre d’autre, reste sur Terraform. Forcer un outil sur des gens réticents ça marche jamais.

Si t’as des années de modules Terraform et pas de budget pour réécrire, reste avec Terraform. La migration a un coût.

Pour les nouveaux projets ou les équipes prêtes à apprendre, Pulumi est meilleur. De vrais langages, de vrais tests, moins de boilerplate!

Commencer

Installe Pulumi:

curl -fsSL https://get.pulumi.com | sh

Crée un projet:

pulumi new aws-typescript

Écris ton infrastructure:

import * as aws from '@pulumi/aws';

const bucket = new aws.s3.Bucket('my-bucket');

export const bucketName = bucket.id;

Déploie:

pulumi up

C’est tout. Pas de providers à configurer manuellement, pas de dance d’init, juste du code et du déploiement!

La vraie différence

Terraform te fait combattre le langage. Tu passes du temps à contourner les limitations au lieu de résoudre des problèmes.

Pulumi te laisse écrire l’infrastructure comme du code applicatif. Fonctions, boucles, if, tests. Les outils que tu connais déjà.

HCL était un compromis. On avait besoin d’infrastructure as code avant qu’il y ait mieux. Maintenant y’a mieux!

La réalité est souvent plus nuancée. Moi, la nuance ça m'ennuie. Je préfère la clarté.

Commentaires