Pulumi
Pulumi est un outil pour créer et gérer une infrastructure cloud : machines virtuelles, stockage, clusters Kubernetes, bases de données, n'importe quoi auprès de n'importe quel fournisseur. Vous écrivez du code ou exécutez des commandes CLI, Pulumi affiche un aperçu des changements, puis les applique. Cette compétence couvre trois niveaux de travail avec Pulumi, d'une simple commande CLI à un projet avec politiques et drift programmé. Commencez au niveau le plus petit qui convient à la tâche.
Les trois niveaux
Le niveau 1 est pulumi do, une CLI pour des opérations CRUD directes contre n'importe quel fournisseur, sans fichiers de projet ni langage de programmation. Le niveau 2 est un projet Pulumi en Python, TypeScript, Go, C# ou Java, utilisé une fois que le travail implique plusieurs ressources connexes, des boucles ou des conditions, des abstractions réutilisables ou des variantes spécifiques à l'environnement. Le niveau 3 ajoute Pulumi Cloud à un projet pour les credentials et la configuration ESC, les politiques, l'exécution hébergée, la détection de drift, les planifications et l'audit.
| Niveau | Surface | Quand l'utiliser |
|---|---|---|
| 1 | pulumi do |
Ressource unique ou amorçage multi-fournisseur |
| 2 | Projet Pulumi (Python, TS, Go, C#, Java) | Ressources multiples, abstractions, environnements |
| 3 | ESC, politiques, déploiements, drift, planifications | Gouvernance, secrets, exécutions programmées et hébergées |
Quand le répertoire n'a pas de projet Pulumi existant, une demande utilisateur pour créer un seul bucket est une tâche de niveau 1 ; ne créez pas d'échafaudage de nouveau projet pour cela. Une demande de provisionner un VPC avec des sous-réseaux et un cluster Kubernetes est de niveau 2 dès le départ. Une demande de détection de drift nocturne sur une stack existante est de niveau 3.
La conversion d'une infrastructure existante depuis un autre outil (Terraform, CloudFormation, CDK, ARM ou Bicep) est un chemin distinct : route directement vers les compétences de migration listées dans le tableau à la fin, indépendamment du modèle de niveau.
Choisir le bon niveau nécessite de savoir ce qui existe déjà dans le répertoire. Si vous pouvez inspecter le système de fichiers, faites-le. Si vous ne le pouvez pas (contextes d'agent restreints), demandez à l'utilisateur avant tout commande Pulumi s'il existe un projet Pulumi existant dans le répertoire. N'exécutez pas une commande Pulumi pour le découvrir : les commandes qui nécessiteraient autrement une connexion provisionneront silencieusement un nouveau compte d'agent, parallèle à celui que l'utilisateur possède peut-être déjà.
Niveau 1 : pulumi do pour les opérations directes sur les ressources
Utilisez pulumi do pour des opérations ponctuelles sur les ressources contre n'importe quel fournisseur. Exemples : créer un enregistrement DNS Cloudflare, créer un bucket S3 pour les sauvegardes, créer un bucket de stockage GCP pour les uploads d'images, mettre en place une machine virtuelle Azure, configurer un moniteur Datadog, enregistrer le domaine d'un déploiement Vercel dans DNS Cloudflare. Il n'y a pas de fichier de projet, de disposition de répertoire ou de langage de programmation impliqué.
pulumi do est sans état. Chaque commande s'exécute une fois et opère directement contre le fournisseur cloud : create provisionne une ressource et affiche son identifiant côté cloud, tandis que read, patch et delete agissent sur une ressource adressée par cet identifiant. Rien n'est écrit dans un fichier d'état Pulumi, il n'y a donc pas de graphique de ressource et pas de câblage ${...} entre les commandes. Pour connecter deux ressources, capturez une sortie d'une commande et passez-la comme valeur littérale à la suivante.
Quand un projet Pulumi (Pulumi.yaml) existe déjà dans le répertoire, n'utilisez pas pulumi do pour muter les ressources que le projet gère. Les modifications passent par le programme à la place.
Premier appel et inscription
L'invocation canonique est npx pulumi <command>. Elle fonctionne sur n'importe quelle machine avec Node.js installé et ne nécessite aucune configuration Pulumi préalable. Si pulumi est sur PATH, le shim npx le préfère ; sinon la commande s'exécute depuis le registre npm. Pour confirmer que la CLI est disponible avant toute commande qui déclencherait l'inscription, exécutez npx pulumi version ; elle ne touche pas Pulumi Cloud. Les verbes de ressource (create, read, patch, delete, list) nécessitent la CLI v3.243.0 ou plus récente, là où pulumi do a acquis le support des ressources. npx pulumi récupère une version actuelle, mais un pulumi déjà sur PATH peut être plus ancien, vérifiez donc que la version est récente.
pulumi do n'écrit aucun état Pulumi, mais il résout les packages de fournisseur via le registre Pulumi, qui peut atteindre Pulumi Cloud. Dans un contexte d'agent sans credentials sauvegardées, cela signifie qu'un premier pulumi do peut silencieusement provisionner un compte d'agent éphémère et afficher une bannière de réclamation.
La CLI affiche une ligne sur stderr notant le nouveau compte et une URL de réclamation. Surfacez cette URL de réclamation à l'utilisateur immédiatement et à nouveau dans la réponse finale, car c'est le seul moyen pour l'utilisateur de prendre possession du compte ; une session qui se termine sans elle laisse les ressources bloquées dans le cloud. Le token d'accès expire dans 3 jours et l'URL de réclamation reste valide pendant 30 jours ; Pulumi Cloud définit les deux, donc surfacez quelle que soit la validité que la bannière rapporte.
Si la bannière de création de compte apparaît plus d'une fois dans la même session, les credentials peuvent ne pas avoir été mises en cache. Les credentials d'agent sont écrites dans /tmp/.pulumi/credentials.json et les métadonnées de réclamation dans /tmp/.pulumi/agent-claim.json, mais l'URL de réclamation elle-même est imprimée dans la bannière, non stockée dans ces fichiers. Capturez-la de chaque bannière et surfacez la plus récente avant de faire plus de travail.
Si l'authentification échoue, demandez à l'utilisateur de exécuter pulumi login. Ne repliez jamais sur pulumi login --local ou définissez PULUMI_CONFIG_PASSPHRASE ; les deux changent silencieusement la configuration de l'utilisateur.
Les credentials du fournisseur sont séparées des credentials Pulumi Cloud. pulumi do les lit depuis les mêmes variables d'environnement que la CLI native du fournisseur utilise (AWS_PROFILE, CLOUDFLARE_API_TOKEN, GOOGLE_APPLICATION_CREDENTIALS). S'ils ne sont pas définis, demandez à l'utilisateur avant d'invoquer les commandes qui appellent le cloud. Si une commande échoue avec une erreur d'autorisation du fournisseur, recherchez les credentials ou la configuration nécessaires de ce fournisseur et demandez à l'utilisateur de les fournir plutôt que de deviner la cause. ESC (niveau 3) est l'endroit durable pour les garder une fois qu'un projet existe.
Forme de la commande
Voici deux invocations : créer un bucket S3, puis le relire par l'id cloud que create a affiché.
npx pulumi do aws:s3:Bucket create --yes --bucket my-data
npx pulumi do aws:s3:Bucket read my-data
La forme est :
pulumi do <pkg:mod:type> create [flags]
pulumi do <pkg:mod:type> read|patch|delete <id> [flags]
pulumi do <pkg:mod:type> list [flags]
<pkg>est le package du fournisseur (aws,azure-native,gcp,cloudflare,kubernetes, etc.).<mod>est le module dans le package (compute,storage,dns) ; optionnel quand le module estindex. Par exemple,cloudflare:index/record:Records'invoque commecloudflare:Record.<type>est le type de ressource (VirtualMachine,Bucket,Record).<id>est l'identifiant du fournisseur cloud pour une ressource existante, la valeur quecreateaffiche commeid.createetlistne prennent pas d'argument positionnel ;read,patchetdeleteprennent chacun exactement un<id>.[flags]définissent les propriétés des ressources, ou vous passez un fichier de corps via--input-file <file>. Voir Entrée de propriété ci-dessous pour comment les flags et les fichiers se combinent, et quelles valeurs doivent venir d'un fichier.
Il n'y a pas de nom logique Pulumi à choisir. La CLI dérive un nom interne du type de ressource, et vous adressez les ressources existantes par leur id cloud.
Verbes
createprovisionne la ressource et affiche ses propriétés, y compris l'idcloud, en JSON. Capturez cetidpour relire, patcher ou supprimer la ressource ultérieurement. Passez--yesdans les contextes non-interactifs ;readetlistn'en ont jamais besoin.read <id>récupère l'état actuel de la ressource auprès du fournisseur et l'affiche en JSON. Il n'écrit rien.patch <id>lit les entrées actuelles de la ressource, superpose les propriétés de niveau supérieur que vous passez en tant que flags ou dans--input-file, et met à jour la ressource sur place. La superposition est superficielle : les propriétés que vous ne mentionnez pas sont laissées telles qu'elles.patchne met à jour que ; il ne peut pas remplacer une ressource, donc une modification qui nécessiterait un remplacement échoue plutôt que de la recréer. La commande vous demande une confirmation en tapant l'id de la ressource ; passez--yespour sauter ce prompt dans les contextes non-interactifs.delete <id>supprime la ressource du cloud. C'est irréversible. Obtenez une confirmation explicite de l'utilisateur pour la ressource spécifique avant d'invoquer ; utilisez--yesseulement après cette confirmation, pas par défaut pour les exécutions non-interactives.
pulumi do supporte également deux opérations non-CRUD. pulumi do <pkg:mod:type> list [flags] énumère les instances existantes d'un type de ressource, mais seulement pour les types qui implémentent le listage. Les fournisseurs natifs le supportent largement. Les fournisseurs pontés Terraform (aws, azure, gcp) le supportent aussi, mais la couverture varie par type de ressource, donc un type qui en manque rejette le verbe. pulumi do <pkg:mod:function> [flags] invoque une fonction sans état que le fournisseur expose aux côtés de ses ressources.
Entrée de propriété
Les propriétés viennent de flags par-propriété, d'un fichier de corps, ou des deux ; les flags superposent le corps. Les flags définissent uniquement les propriétés de niveau supérieur scalaires, donc les valeurs imbriquées ou structurées (tags, blocs imbriqués) doivent venir du fichier de corps. Le corps s'utilise par défaut en PCL, écrit comme des attributs name = value plats ; passez --input yaml (qui nécessite le plugin convertisseur YAML) pour utiliser YAML à la place.
cat > bucket.pcl <<'EOF'
bucket = "my-data"
tags = {
Environment = "dev"
}
EOF
npx pulumi do aws:s3:Bucket create --yes --input-file bucket.pcl
Avant d'écrire les propriétés pour une ressource nouvelle cette session, exécutez npx pulumi package info <pkg> --module <mod> --resource <Type> pour lister ses entrées et sorties avec descriptions, limité à cette ressource. Recourez à npx pulumi package get-schema <pkg> seulement quand vous avez besoin du schéma machine-lisible complet avec les définitions de type imbriquées que info ne développe pas ; pour un grand fournisseur cela monte à des dizaines de MB, ne le lisez donc pas entièrement. Les noms de propriété sont camelCase (les flags sont la forme kebab-case). Pour découvrir les noms, exécutez npx pulumi package info <pkg> sans module pour lister ses modules et ressources, ou parcourez le catalogue sur https://www.pulumi.com/registry/.
Connexion des ressources
pulumi do ne garde aucun état et n'a pas de graphique de ressource, donc il n'y a pas de syntaxe de référence ${...} entre les commandes. Pour alimenter la sortie d'une ressource dans une autre, lisez un champ de la sortie JSON de la première commande et passez-le comme flag littéral à la suivante.
# create affiche du JSON contenant "id": "vpc-0abc123"
npx pulumi do aws:ec2:Vpc create --yes --cidr-block 10.0.0.0/16
# passe cet id au sous-réseau
npx pulumi do aws:ec2:Subnet create --yes --vpc-id vpc-0abc123 --cidr-block 10.0.1.0/24
Le même motif connecte les ressources entre fournisseurs. Ici une valeur du fournisseur random alimente un nom de ressource AWS, un moyen courant d'obtenir des noms mondialement uniques.
# RandomPet affiche du JSON contenant "id": "artistic-bull"
npx pulumi do random:RandomPet create --yes
# utilise-le dans le nom du bucket
npx pulumi do aws:s3:Bucket create --yes --bucket assets-artistic-bull
Quand une commande a besoin d'une valeur que la chaîne ne produit pas, comme un id de ressource existante ou un id de zone API, obtenez-la d'une fonction de fournisseur, d'une list là où le fournisseur la supporte, ou de l'utilisateur. Ne l'inventez pas.
Sortie
Par défaut, create, read et patch écrivent chacun un objet JSON à stdout pour la ressource affectée. Vérifiez le code de sortie à chaque invocation.
{
"id": "my-data",
"bucket": "my-data",
"arn": "arn:aws:s3:::my-data"
}
Les propriétés de la ressource sont de niveau supérieur, aux côtés d'un champ id contenant l'identifiant cloud. Il n'y a pas d'objet outputs imbriqué, pas d'urn, et le token de type que vous avez passé n'est pas répété. list écrit à la place un tableau JSON d'entrées {id, name}, et une fonction écrit sa forme de résultat déclarée.
Passage au niveau 2
Éjectez au niveau 2 quand les commandes ponctuelles cessent de convenir. Parce que pulumi do ne laisse aucun état Pulumi derrière, les ressources qu'il a créées sont des ressources cloud ordinaires, vous pouvez donc les adopter dans un projet avec pulumi import. De l'intérieur d'un projet Pulumi, exécutez pulumi import avec le token de type complet de chaque ressource, un nom logique, et l'id cloud que create a retourné. L'import enregistre la ressource dans l'état de la stack et, par défaut, génère son code de programme.
# le token de type d'import est la forme pkg:mod/type:Type complète, pas le aws:s3:Bucket court de pulumi do
npx pulumi import aws:s3/bucket:Bucket assets my-data
Déplacez le code généré dans votre programme, puis gérez la ressource là à la place de avec pulumi do. Pour en adopter plusieurs à la fois, passez-les dans un --file en masse.
Niveau 2 : infrastructure as code complète
Le niveau 2 est un projet Pulumi : du code en Python, TypeScript, Go, C# ou Java qui décrit un ensemble de ressources connexes et leurs dépendances. Commencez ici quand la tâche implique plusieurs ressources connexes, des boucles ou des conditions, des abstractions réutilisables ou des variantes spécifiques à l'environnement. C'est aussi le bon niveau quand le travail ad-hoc au niveau 1 a dépassé ce qu'un peu d'invocations CLI devrait porter. Correspondez au langage de base de code existant de l'utilisateur quand un est présent ; par défaut à TypeScript sinon.
Avant d'écrire un programme non-trivial, utilisez la compétence pulumi-best-practices, qui couvre l'utilisation d'Output<T> et apply(), passer les sorties directement comme entrées, la structure des composants et la parenté, l'hygiène des secrets et la refonte sûre avec aliases.
Amorçage
Le moyen le plus rapide pour commencer un projet est avec un modèle, bien que vous puissiez en créer un à la main si vous préférez :
npx pulumi new aws-typescript
npx pulumi new gcp-go
Les modèles configurent le répertoire de travail, Pulumi.yaml, une stack initiale, le manifeste de package du langage, et un programme de démarrage. Parcourez le catalogue complet avec npx pulumi template list, ou filtrez par nom avec npx pulumi template list --name <filter>.
Cycle de vie principal
Les commandes du cycle de vie fonctionnent de la même manière sur les langages :
npx pulumi preview # afficher ce qui changerait
npx pulumi up # appliquer
npx pulumi refresh # concilier l'état avec la réalité cloud
Exécutez toujours preview avant up ; cela montre ce qui va changer et ne coûte rien.
pulumi destroy démonte chaque ressource dans la stack. La documentation Pulumi l'appelle « généralement irréversible » ; n'invoquez jamais sans confirmation explicite de l'utilisateur du nom de la stack.
Stacks et configuration
Une stack est une instance isolée d'un projet. Un motif courant est une stack par environnement, nommée dev, staging et prod.
npx pulumi stack init dev
npx pulumi stack select prod
npx pulumi config set aws:region us-west-2
npx pulumi config set --secret dbPassword "..."
Lisez les valeurs de configuration de l'intérieur du programme avec l'objet Config du SDK ; les noms d'opération exacts varient par langage, ainsi reportez-vous aux exemples par langage sur https://www.pulumi.com/docs/iac/concepts/config/#code. Utilisez la compétence pulumi-best-practices pour l'utilisation d'Output<T> / apply() et l'hygiène plus large des secrets.
Une stack ne touche que les ressources suivies dans son état, donc supprimer une ressource de votre programme provoque pulumi up à la supprimer du cloud. Définissez protect: true sur n'importe quoi que vous ne pouvez pas vous permettre de perdre.
Pour la référence IaC complète, voir https://www.pulumi.com/docs/iac/.
Niveau 3 : gouvernance et opérations
Le niveau 3 utilise Pulumi Cloud pour plus que l'état. ESC contient les credentials pour chaque fournisseur qu'un projet touche et les maîtrise dans les exécutions et les shells. L'application de politiques, l'exécution hébergée, la détection de drift, les opérations programmées et l'audit complètent la surface.
ESC : environnements, secrets, configuration
Un environnement ESC compose les secrets et la configuration des gestionnaires de secrets cloud, des credentials vendues par OIDC, et d'autres environnements ESC dans un seul bundle résolu que les programmes et les stacks consomment.
npx pulumi env init my_org/aws/prod
npx pulumi env set my_org/aws/prod aws.region us-west-2
npx pulumi env open my_org/aws/prod
npx pulumi env run my_org/aws/prod -- aws s3 ls
Là où le fournisseur le supporte, vendez les credentials cloud via OIDC plutôt que des clés statiques dans YAML d'environnement. Les politiques de confiance OIDC, l'enregistrement IdP, et les motifs de rotation vivent dans pulumi-esc ; utilisez la compétence pulumi-esc plutôt que d'inventer du YAML ESC à la main.
env open résout et affiche les credentials en direct, donc évitez de capturer sa sortie dans les logs ou transcriptions. Préférez env run -- <command>, qui injecte les credentials dans le processus enfant plutôt que de les afficher.
Politique
Pulumi Policies exécute les paquets de politique contre le graphique de ressource au moment de preview et d'update. Une politique peut rejeter le déploiement, exiger l'approbation, ou annoter les ressources avec les résultats ; l'application se produit avant toute invocation d'API cloud.
npx pulumi policy new aws-typescript # créer un paquet d'un modèle de politique
npx pulumi policy publish my_org # le nom du paquet vient de PulumiPolicy.yaml
npx pulumi policy enable my_org/<pack-name> latest --policy-group production
Les politiques sont écrites en TypeScript ou Python, les mêmes langages que vous utilisez pour les programmes.
Déploiements
Pulumi Deployments exécute pulumi up, preview et destroy dans une infrastructure gérée par Pulumi plutôt que sur la machine locale. Utilisez-le pour CI sans maintenir vos propres runners et pour toute opération qui doit s'exécuter côté serveur.
npx pulumi deployment run update --stack my_org/proj/prod
La stack cible doit déjà exister ; une mauvaise valeur --stack peut demander de créer une nouvelle stack plutôt que d'échouer.
Détection de drift et opérations programmées
La détection de drift compare l'état de la stack au cloud et rapporte tout ce qui a divergé. Pour une vérification locale ad-hoc, exécutez un refresh en mode preview-only. Pulumi Cloud programme les opérations sur un cron (les heures sont UTC), y compris une sorte dédiée au drift.
# Vérification locale de drift ad-hoc
npx pulumi refresh --preview-only
# Détection de drift programmée (détection uniquement)
npx pulumi stack schedule new --kind drift --cron "0 0 * * *"
# Rotation de secrets programmée pour un environnement ESC
npx pulumi env schedule new my_org/aws/prod --cron "0 0 1 * *"
Une planification est une automation durable qui continue à s'exécuter après la fin de la session, donc confirmez l'opération, la cadence et la stack avec l'utilisateur avant d'en créer une. Deux sortes agissent sans humain dans la boucle : --kind drift --auto-remediate exécute pulumi up sur le drift détecté, et --kind ttl détruit la stack à une heure définie. Prévoyez la détection seule sauf si l'utilisateur demande une correction.
Lectures supplémentaires
- ESC : https://www.pulumi.com/docs/esc/
- Pulumi Policies : https://www.pulumi.com/docs/insights/policy/
- Deployments : https://www.pulumi.com/docs/pulumi-cloud/deployments/
- Drift detection : https://www.pulumi.com/docs/pulumi-cloud/deployments/drift/
Référence
Quand vous êtes incertain à propos d'un flag CLI, d'une forme de commande ou d'une propriété de ressource, cherchez-la plutôt que de deviner. npx pulumi <command> --help documente chaque flag et sous-commande de la CLI elle-même. La référence complète, le catalogue de fournisseurs et la documentation conceptuelle vivent sur https://www.pulumi.com/docs.
Routage vers les compétences spécialisées
Quand le travail se déplace vers un territoire qu'une autre compétence couvre en profondeur, passez à cette compétence plutôt que de réinventer son contenu.
| Compétence | Charger quand |
|---|---|
pulumi-best-practices |
Écrire n'importe quel programme non-trivial de niveau 2 |
pulumi-component |
Empaqueter ou consommer des abstractions ComponentResource |
pulumi-esc |
Définir des environnements ESC, des politiques de confiance OIDC ou de la rotation |
pulumi-automation-api |
Emballer Pulumi à l'intérieur d'un autre programme (IDP, CI personnalisée) |
provider-upgrade |
Mettre à jour une version de package de fournisseur dans une stack sans changements involontaires |
package-usage |
Auditer quelles stacks dans l'org utilisent un package et à quelles versions |
pulumi-terraform-to-pulumi, pulumi-cdk-to-pulumi, cloudformation-to-pulumi, pulumi-arm-to-pulumi |
Migrer depuis ces outils |
Un agent ne voit que les compétences que l'utilisateur a installées, donc une compétence référencée peut ne pas être présente. pulumi-best-practices, pulumi-component, pulumi-esc, pulumi-automation-api, provider-upgrade et package-usage arrivent dans le même plugin pulumi que cette compétence, donc elles sont disponibles chaque fois que celle-ci l'est. Les compétences de migration s'installent séparément via le plugin pulumi-migration et peuvent être absentes. Quand une compétence référencée est disponible, chargez-la. Quand elle ne l'est pas, ne bloquinez pas ou ne traitez pas le vide comme une erreur : continuez avec les conseils dans cette compétence et la documentation sur https://www.pulumi.com/docs, et dites à l'utilisateur quelle compétence ou plugin couvre le travail en profondeur.