Pulumi Automation API
Quand Utiliser Cette Skill
Invoquez cette skill quand :
- Orchestrer des déploiements sur plusieurs stacks Pulumi
- Intégrer des opérations Pulumi dans des applications personnalisées
- Créer des plateformes d'infrastructure en libre-service
- Remplacer des scripts d'orchestration fragiles en Bash/Makefile
- Créer des CLIs personnalisées pour la gestion d'infrastructure
- Construire des applications web qui provisionent l'infrastructure
Qu'est-ce que l'Automation API
L'Automation API fournit un accès programmatique aux opérations Pulumi. Au lieu d'exécuter pulumi up depuis le CLI, vous appelez des fonctions dans votre code qui effectuent les mêmes opérations.
import * as automation from "@pulumi/pulumi/automation";
// Créer ou sélectionner une stack
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-project",
program: async () => {
// Votre programme Pulumi ici
},
});
// Exécuter pulumi up programmatiquement
const upResult = await stack.up({ onOutput: console.log });
console.log(`Update summary: ${JSON.stringify(upResult.summary)}`);
Quand Utiliser l'Automation API
Bons Cas d'Usage
Orchestration multi-stack :
Quand vous divisez l'infrastructure en plusieurs projets ciblés, l'Automation API aide à compenser la complexité ajoutée en orchestrant les opérations sur les stacks :
infrastructure → platform → application
↓ ↓ ↓
(VPC) (Kubernetes) (Services)
L'Automation API garantit un séquençage correct sans intervention manuelle.
Plateformes en libre-service :
Créez des outils internes où les développeurs demandent l'infrastructure sans apprendre Pulumi :
- Portails web pour le provisionnement d'environnements
- Bots Slack qui créent/détruisent des ressources
- CLIs personnalisées adaptées à votre organisation
Infrastructure intégrée :
Applications qui provisionent leur propre infrastructure :
- Plateformes SaaS créant des ressources par tenant
- Frameworks de test créant des environnements de test
- Systèmes CI/CD avec des besoins d'infrastructure dynamiques
Remplacer des scripts fragiles :
Si vous avez des scripts Bash ou des Makefiles assemblant plusieurs commandes pulumi, l'Automation API fournit :
- Une gestion d'erreur appropriée
- La sécurité des types
- Un accès programmatique aux sorties
Quand NE PAS L'Utiliser
- Projet unique avec des besoins de déploiement standards
- Quand vous n'avez pas besoin de contrôle programmatique sur les opérations
Choix Architecturaux
Source Locale vs Source Inline
Source Locale - Programme Pulumi dans des fichiers séparés :
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
workDir: "./infrastructure", // Pointe vers un projet Pulumi existant
});
Quand l'utiliser :
- Des équipes différentes maintiennent l'orchestrateur vs les programmes Pulumi
- Les programmes Pulumi existent déjà
- Vouloir des cycles de contrôle de version et de publication indépendants
- L'équipe de plateforme orchestrant l'infrastructure de l'équipe d'application
Source Inline - Programme Pulumi intégré dans l'orchestrateur :
import * as aws from "@pulumi/aws";
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-project",
program: async () => {
const bucket = new aws.s3.Bucket("my-bucket");
return { bucketName: bucket.id };
},
});
Quand l'utiliser :
- Une seule équipe possède tout
- L'étroite liaison entre l'orchestration et l'infrastructure est désirée
- Distribution comme binaire compilé (aucun fichier source nécessaire)
- Artefact de déploiement plus simple
Indépendance de Langage
Le programme Automation API peut utiliser un langage différent des programmes Pulumi qu'il orchestre :
Orchestrator (Go) → manages → Pulumi Program (TypeScript)
Cela permet aux équipes de plateforme d'utiliser leur langage préféré tandis que les équipes d'application utilisent le leur.
Patterns Courants
Orchestration Multi-Stack
Déployer plusieurs stacks dans l'ordre des dépendances :
import * as automation from "@pulumi/pulumi/automation";
async function deploy() {
const stacks = [
{ name: "infrastructure", dir: "./infra" },
{ name: "platform", dir: "./platform" },
{ name: "application", dir: "./app" },
];
for (const stackInfo of stacks) {
console.log(`Deploying ${stackInfo.name}...`);
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
await stack.up({ onOutput: console.log });
console.log(`${stackInfo.name} deployed successfully`);
}
}
async function destroy() {
// Destroy in reverse order
const stacks = [
{ name: "application", dir: "./app" },
{ name: "platform", dir: "./platform" },
{ name: "infrastructure", dir: "./infra" },
];
for (const stackInfo of stacks) {
console.log(`Destroying ${stackInfo.name}...`);
const stack = await automation.LocalWorkspace.selectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
await stack.destroy({ onOutput: console.log });
}
}
Passer la Configuration
Définissez la configuration de stack programmatiquement :
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "dev",
workDir: "./infrastructure",
});
// Définir les valeurs de configuration
await stack.setConfig("aws:region", { value: "us-west-2" });
await stack.setConfig("dbPassword", { value: "secret", secret: true });
// Puis déployer
await stack.up();
Lire les Sorties
Accédez aux sorties de stack après le déploiement :
const upResult = await stack.up();
// Obtenir toutes les sorties
const outputs = await stack.outputs();
console.log(`VPC ID: ${outputs["vpcId"].value}`);
// Ou à partir du résultat de up
console.log(`Outputs: ${JSON.stringify(upResult.outputs)}`);
Gestion d'Erreurs
Gérez les échecs de déploiement gracieusement :
try {
const result = await stack.up({ onOutput: console.log });
if (result.summary.result === "failed") {
console.error("Deployment failed");
process.exit(1);
}
} catch (error) {
console.error(`Deployment error: ${error}`);
throw error;
}
Opérations Parallèles sur les Stacks
Quand les stacks sont indépendantes, déployez en parallèle :
const independentStacks = [
{ name: "service-a", dir: "./service-a" },
{ name: "service-b", dir: "./service-b" },
{ name: "service-c", dir: "./service-c" },
];
await Promise.all(independentStacks.map(async (stackInfo) => {
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: "prod",
workDir: stackInfo.dir,
});
return stack.up({ onOutput: (msg) => console.log(`[${stackInfo.name}] ${msg}`) });
}));
Bonnes Pratiques
Séparer la Configuration du Code
Externalisez la configuration dans des fichiers ou des variables d'environnement :
import * as fs from "fs";
interface DeployConfig {
stacks: Array<{ name: string; dir: string; }>;
environment: string;
}
const config: DeployConfig = JSON.parse(
fs.readFileSync("./deploy-config.json", "utf-8")
);
for (const stackInfo of config.stacks) {
const stack = await automation.LocalWorkspace.createOrSelectStack({
stackName: config.environment,
workDir: stackInfo.dir,
});
await stack.up();
}
Cela permet de distribuer des binaires compilés sans exposer le code source.
Diffuser la Sortie pour les Opérations Longues
Utilisez le callback onOutput pour un retour en temps réel :
await stack.up({
onOutput: (message) => {
process.stdout.write(message);
// Ou envoyer à un système de journalisation, websocket, etc.
},
});
Référence Rapide
| Scénario | Approche |
|---|---|
| Projets Pulumi existants | Source locale avec workDir |
| Infrastructure intégrée nouvelle | Source inline avec fonction program |
| Équipes différentes | Source locale pour l'indépendance |
| Distribution de binaire compilé | Source inline ou locale groupée |
| Dépendances multi-stack | Déploiement séquentiel dans l'ordre |
| Stacks indépendantes | Déploiement parallèle avec Promise.all |
Skills Associées
- pulumi-best-practices: Patterns au niveau du code pour les programmes Pulumi