pulumi-best-practices
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePulumi Best Practices
Pulumi 最佳实践
When to Use This Skill
何时使用此技能
Invoke this skill when:
- Writing new Pulumi programs or components
- Reviewing Pulumi code for correctness
- Refactoring existing Pulumi infrastructure
- Debugging resource dependency issues
- Setting up configuration and secrets
在以下场景调用此技能:
- 编写新的Pulumi程序或组件
- 评审Pulumi代码的正确性
- 重构现有Pulumi基础设施
- 调试资源依赖问题
- 配置设置与密钥管理
Practices
实践要点
1. Never Create Resources Inside apply()
apply()1. 切勿在apply()
内部创建资源
apply()Why: Resources created inside don't appear in , making changes unpredictable. Pulumi cannot properly track dependencies, leading to race conditions and deployment failures.
apply()pulumi previewDetection signals:
- or other resource constructors inside
new aws.callbacks.apply() - Resource creation inside
pulumi.all([...]).apply() - Dynamic resource counts determined at runtime inside apply
Wrong:
typescript
const bucket = new aws.s3.Bucket("bucket");
bucket.id.apply(bucketId => {
// WRONG: This resource won't appear in preview
new aws.s3.BucketObject("object", {
bucket: bucketId,
content: "hello",
});
});Right:
typescript
const bucket = new aws.s3.Bucket("bucket");
// Pass the output directly - Pulumi handles the dependency
const object = new aws.s3.BucketObject("object", {
bucket: bucket.id, // Output<string> works here
content: "hello",
});When apply is appropriate:
- Transforming output values for use in tags, names, or computed strings
- Logging or debugging (not resource creation)
- Conditional logic that affects resource properties, not resource existence
原因:在内部创建的资源不会出现在中,导致变更不可预测。Pulumi无法正确跟踪依赖关系,从而引发竞争条件和部署失败。
apply()pulumi preview检测信号:
- 回调中存在
.apply()或其他资源构造函数new aws. - 在内部创建资源
pulumi.all([...]).apply() - 在apply中通过运行时动态确定资源数量
错误示例:
typescript
const bucket = new aws.s3.Bucket("bucket");
bucket.id.apply(bucketId => {
// 错误:此资源不会出现在预览中
new aws.s3.BucketObject("object", {
bucket: bucketId,
content: "hello",
});
});正确示例:
typescript
const bucket = new aws.s3.Bucket("bucket");
// 直接传递输出值 - Pulumi会处理依赖关系
const object = new aws.s3.BucketObject("object", {
bucket: bucket.id, // Output<string>可直接使用
content: "hello",
});apply的适用场景:
- 转换输出值以用于标签、名称或计算字符串
- 日志记录或调试(非资源创建)
- 影响资源属性而非资源存在性的条件逻辑
2. Pass Outputs Directly as Inputs
2. 直接将Output作为Input传递
Why: Pulumi builds a directed acyclic graph (DAG) based on input/output relationships. Passing outputs directly ensures correct creation order. Unwrapping values manually breaks the dependency chain, causing resources to deploy in wrong order or reference values that don't exist yet.
Detection signals:
- Variables extracted from used later as resource inputs
.apply() - on output values outside of apply
await - String concatenation with outputs instead of
pulumi.interpolate
Wrong:
typescript
const vpc = new aws.ec2.Vpc("vpc", { cidrBlock: "10.0.0.0/16" });
// WRONG: Extracting the value breaks the dependency chain
let vpcId: string;
vpc.id.apply(id => { vpcId = id; });
const subnet = new aws.ec2.Subnet("subnet", {
vpcId: vpcId, // May be undefined, no tracked dependency
cidrBlock: "10.0.1.0/24",
});Right:
typescript
const vpc = new aws.ec2.Vpc("vpc", { cidrBlock: "10.0.0.0/16" });
const subnet = new aws.ec2.Subnet("subnet", {
vpcId: vpc.id, // Pass the Output directly
cidrBlock: "10.0.1.0/24",
});For string interpolation:
typescript
// WRONG
const name = bucket.id.apply(id => `prefix-${id}-suffix`);
// RIGHT - use pulumi.interpolate for template literals
const name = pulumi.interpolate`prefix-${bucket.id}-suffix`;
// RIGHT - use pulumi.concat for simple concatenation
const name = pulumi.concat("prefix-", bucket.id, "-suffix");原因:Pulumi基于输入/输出关系构建有向无环图(DAG)。直接传递Output可确保正确的创建顺序。手动解包值会破坏依赖链,导致资源部署顺序错误或引用尚未存在的值。
检测信号:
- 从提取的变量后续用作资源输入
.apply() - 在apply外部对输出值使用
await - 使用字符串拼接而非处理输出值
pulumi.interpolate
错误示例:
typescript
const vpc = new aws.ec2.Vpc("vpc", { cidrBlock: "10.0.0.0/16" });
// 错误:提取值会破坏依赖链
let vpcId: string;
vpc.id.apply(id => { vpcId = id; });
const subnet = new aws.ec2.Subnet("subnet", {
vpcId: vpcId, // 可能未定义,无跟踪的依赖关系
cidrBlock: "10.0.1.0/24",
});正确示例:
typescript
const vpc = new aws.ec2.Vpc("vpc", { cidrBlock: "10.0.0.0/16" });
const subnet = new aws.ec2.Subnet("subnet", {
vpcId: vpc.id, // 直接传递Output
cidrBlock: "10.0.1.0/24",
});字符串插值的正确方式:
typescript
// 错误
const name = bucket.id.apply(id => `prefix-${id}-suffix`);
// 正确 - 使用pulumi.interpolate处理模板字符串
const name = pulumi.interpolate`prefix-${bucket.id}-suffix`;
// 正确 - 使用pulumi.concat进行简单拼接
const name = pulumi.concat("prefix-", bucket.id, "-suffix");3. Use Components for Related Resources
3. 使用组件管理相关资源
Why: ComponentResource classes group related resources into reusable, logical units. Without components, your resource graph is flat, making it hard to understand which resources belong together, reuse patterns across stacks, or reason about your infrastructure at a higher level.
Detection signals:
- Multiple related resources created at top level without grouping
- Repeated resource patterns across stacks that should be abstracted
- Hard to understand resource relationships from the Pulumi console
Wrong:
typescript
// Flat structure - no logical grouping, hard to reuse
const bucket = new aws.s3.Bucket("app-bucket");
const bucketPolicy = new aws.s3.BucketPolicy("app-bucket-policy", {
bucket: bucket.id,
policy: policyDoc,
});
const originAccessIdentity = new aws.cloudfront.OriginAccessIdentity("app-oai");
const distribution = new aws.cloudfront.Distribution("app-cdn", { /* ... */ });Right:
typescript
interface StaticSiteArgs {
domain: string;
content: pulumi.asset.AssetArchive;
}
class StaticSite extends pulumi.ComponentResource {
public readonly url: pulumi.Output<string>;
constructor(name: string, args: StaticSiteArgs, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:StaticSite", name, args, opts);
// Resources created here - see practice 4 for parent setup
const bucket = new aws.s3.Bucket(`${name}-bucket`, {}, { parent: this });
// ...
this.url = distribution.domainName;
this.registerOutputs({ url: this.url });
}
}
// Reusable across stacks
const site = new StaticSite("marketing", {
domain: "marketing.example.com",
content: new pulumi.asset.FileArchive("./dist"),
});Component best practices:
- Use a consistent type URN pattern:
organization:module:ComponentName - Call at the end of the constructor
registerOutputs() - Expose outputs as class properties for consumers
- Accept to allow callers to set providers, aliases, etc.
ComponentResourceOptions
For in-depth component authoring guidance (args design, multi-language support, testing, distribution), use skill .
pulumi-component原因:ComponentResource类将相关资源分组为可复用的逻辑单元。如果不使用组件,资源图会是扁平结构,难以理解哪些资源属于同一组、在多个栈中复用模式,或从更高层面推理基础设施。
检测信号:
- 多个相关资源在顶层创建而未分组
- 多个栈中存在重复的资源模式,应进行抽象
- 从Pulumi控制台难以理解资源关系
错误示例:
typescript
// 扁平结构 - 无逻辑分组,难以复用
const bucket = new aws.s3.Bucket("app-bucket");
const bucketPolicy = new aws.s3.BucketPolicy("app-bucket-policy", {
bucket: bucket.id,
policy: policyDoc,
});
const originAccessIdentity = new aws.cloudfront.OriginAccessIdentity("app-oai");
const distribution = new aws.cloudfront.Distribution("app-cdn", { /* ... */ });正确示例:
typescript
interface StaticSiteArgs {
domain: string;
content: pulumi.asset.AssetArchive;
}
class StaticSite extends pulumi.ComponentResource {
public readonly url: pulumi.Output<string>;
constructor(name: string, args: StaticSiteArgs, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:StaticSite", name, args, opts);
// 在此处创建资源 - 请参阅实践4了解父级设置
const bucket = new aws.s3.Bucket(`${name}-bucket`, {}, { parent: this });
// ...
this.url = distribution.domainName;
this.registerOutputs({ url: this.url });
}
}
// 可在多个栈中复用
const site = new StaticSite("marketing", {
domain: "marketing.example.com",
content: new pulumi.asset.FileArchive("./dist"),
});组件最佳实践:
- 使用一致的类型URN模式:
organization:module:ComponentName - 在构造函数末尾调用
registerOutputs() - 将输出暴露为类属性供使用者调用
- 接受以允许调用者设置提供者、别名等
ComponentResourceOptions
如需深入的组件创作指南(参数设计、多语言支持、测试、分发),请使用技能。
pulumi-component4. Always Set parent: this
in Components
parent: this4. 在组件中始终设置parent: this
parent: thisWhy: When you create resources inside a ComponentResource without setting , those resources appear at the root level of your stack's state. This breaks the logical hierarchy, makes the Pulumi console hard to navigate, and can cause issues with aliases and refactoring. The parent relationship is what makes the component actually group its children.
parent: thisDetection signals:
- ComponentResource classes that don't pass to child resources
{ parent: this } - Resources inside a component appearing at root level in the console
- Unexpected behavior when adding aliases to components
Wrong:
typescript
class MyComponent extends pulumi.ComponentResource {
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:MyComponent", name, {}, opts);
// WRONG: No parent set - this bucket appears at root level
const bucket = new aws.s3.Bucket(`${name}-bucket`);
}
}Right:
typescript
class MyComponent extends pulumi.ComponentResource {
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:MyComponent", name, {}, opts);
// RIGHT: Parent establishes hierarchy
const bucket = new aws.s3.Bucket(`${name}-bucket`, {}, {
parent: this
});
const policy = new aws.s3.BucketPolicy(`${name}-policy`, {
bucket: bucket.id,
policy: policyDoc,
}, {
parent: this
});
}
}What parent: this provides:
- Resources appear nested under the component in Pulumi console
- Deleting the component deletes all children
- Aliases on the component automatically apply to children
- Clear ownership in state files
原因:如果在ComponentResource内部创建资源时未设置,这些资源会出现在栈状态的根级别。这会破坏逻辑层次结构,使Pulumi控制台难以导航,并可能导致别名和重构问题。父级关系是组件实际分组其子资源的关键。
parent: this检测信号:
- ComponentResource类未将传递给子资源
{ parent: this } - 组件内部的资源在控制台中显示在根级别
- 为组件添加别名时出现意外行为
错误示例:
typescript
class MyComponent extends pulumi.ComponentResource {
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:MyComponent", name, {}, opts);
// 错误:未设置父级 - 此存储桶会出现在根级别
const bucket = new aws.s3.Bucket(`${name}-bucket`);
}
}正确示例:
typescript
class MyComponent extends pulumi.ComponentResource {
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:MyComponent", name, {}, opts);
// 正确:父级建立层次结构
const bucket = new aws.s3.Bucket(`${name}-bucket`, {}, {
parent: this
});
const policy = new aws.s3.BucketPolicy(`${name}-policy`, {
bucket: bucket.id,
policy: policyDoc,
}, {
parent: this
});
}
}parent: this- 资源在Pulumi控制台中显示为组件的子项
- 删除组件会删除所有子资源
- 组件上的别名自动应用于子资源
- 状态文件中所有权清晰
5. Encrypt Secrets from Day One
5. 从第一天起加密密钥
Why: Secrets marked with are encrypted in state files, masked in CLI output, and tracked through transformations. Starting with plaintext config and converting later requires credential rotation, reference updates, and audit of leaked values in logs and state history.
--secretDetection signals:
- Passwords, API keys, tokens stored as plain config
- Connection strings with embedded credentials
- Private keys or certificates in plaintext
Wrong:
bash
undefined原因:使用标记的密钥会在状态文件中加密,在CLI输出中被屏蔽,并通过转换进行跟踪。先使用明文配置再转换,需要轮换凭证、更新引用,并审核日志和状态历史中泄露的值。
--secret检测信号:
- 密码、API密钥、令牌以明文配置存储
- 包含嵌入式凭证的连接字符串
- 明文形式的私钥或证书
错误示例:
bash
undefinedPlaintext - will be visible in state and logs
明文 - 会在状态和日志中可见
pulumi config set databasePassword hunter2
pulumi config set apiKey sk-1234567890
**Right**:
```bashpulumi config set databasePassword hunter2
pulumi config set apiKey sk-1234567890
**正确示例**:
```bashEncrypted from the start
从一开始就加密
pulumi config set --secret databasePassword hunter2
pulumi config set --secret apiKey sk-1234567890
**In code**:
```typescript
const config = new pulumi.Config();
// This retrieves a secret - the value stays encrypted
const dbPassword = config.requireSecret("databasePassword");
// Creating outputs from secrets preserves secrecy
const connectionString = pulumi.interpolate`postgres://user:${dbPassword}@host/db`;
// connectionString is also a secret Output
// Explicitly mark values as secret
const computed = pulumi.secret(someValue);Use Pulumi ESC for centralized secrets:
yaml
undefinedpulumi config set --secret databasePassword hunter2
pulumi config set --secret apiKey sk-1234567890
**代码中的处理**:
```typescript
const config = new pulumi.Config();
// 检索密钥 - 值保持加密状态
const dbPassword = config.requireSecret("databasePassword");
// 从密钥创建输出会保留保密性
const connectionString = pulumi.interpolate`postgres://user:${dbPassword}@host/db`;
// connectionString也是一个保密的Output
// 显式将值标记为密钥
const computed = pulumi.secret(someValue);使用Pulumi ESC进行集中式密钥管理:
yaml
undefinedPulumi.yaml
Pulumi.yaml
environment:
- production-secrets # Pull from ESC environment
```bashenvironment:
- production-secrets # 从ESC环境拉取
```bashESC manages secrets centrally across stacks
ESC跨栈集中管理密钥
esc env set production-secrets db.password --secret "hunter2"
**What qualifies as a secret**:
- Passwords and passphrases
- API keys and tokens
- Private keys and certificates
- Connection strings with credentials
- OAuth client secrets
- Encryption keys
**References**:
- https://www.pulumi.com/docs/concepts/secrets/
- https://www.pulumi.com/docs/esc/
---esc env set production-secrets db.password --secret "hunter2"
**属于密钥的内容**:
- 密码和密码短语
- API密钥和令牌
- 私钥和证书
- 包含凭证的连接字符串
- OAuth客户端密钥
- 加密密钥
**参考文档**:
- https://www.pulumi.com/docs/concepts/secrets/
- https://www.pulumi.com/docs/esc/
---6. Use Aliases When Refactoring
6. 重构时使用别名
Why: Renaming resources, moving them into components, or changing parents causes Pulumi to see them as new resources. Without aliases, refactoring destroys and recreates resources, potentially causing downtime or data loss. Aliases preserve resource identity through refactors.
Detection signals:
- Resource rename without alias
- Moving resource into or out of a ComponentResource
- Changing the parent of a resource
- Preview shows delete+create when update was intended
Wrong:
typescript
// Before: resource named "my-bucket"
const bucket = new aws.s3.Bucket("my-bucket");
// After: renamed without alias - DESTROYS THE BUCKET
const bucket = new aws.s3.Bucket("application-bucket");Right:
typescript
// After: renamed with alias - preserves the existing bucket
const bucket = new aws.s3.Bucket("application-bucket", {}, {
aliases: [{ name: "my-bucket" }],
});Moving into a component:
typescript
// Before: top-level resource
const bucket = new aws.s3.Bucket("my-bucket");
// After: inside a component - needs alias with old parent
class MyComponent extends pulumi.ComponentResource {
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:MyComponent", name, {}, opts);
const bucket = new aws.s3.Bucket("bucket", {}, {
parent: this,
aliases: [{
name: "my-bucket",
parent: pulumi.rootStackResource, // Was at root
}],
});
}
}Alias types:
typescript
// Simple name change
aliases: [{ name: "old-name" }]
// Parent change
aliases: [{ name: "resource-name", parent: oldParent }]
// Full URN (when you know the exact previous URN)
aliases: ["urn:pulumi:stack::project::aws:s3/bucket:Bucket::old-name"]Lifecycle:
- Add alias during refactor
- Run on all stacks
pulumi up - Remove alias after all stacks updated (optional, but keeps code clean)
原因:重命名资源、将其移入组件或更改父级会导致Pulumi将其视为新资源。如果不使用别名,重构会销毁并重新创建资源,可能导致停机或数据丢失。别名可在重构过程中保留资源标识。
检测信号:
- 重命名资源但未使用别名
- 将资源移入或移出ComponentResource
- 更改资源的父级
- 预览显示删除+创建,但预期是更新
错误示例:
typescript
// 之前:资源名为"my-bucket"
const bucket = new aws.s3.Bucket("my-bucket");
// 之后:未使用别名重命名 - 会销毁存储桶
const bucket = new aws.s3.Bucket("application-bucket");正确示例:
typescript
// 之后:使用别名重命名 - 保留现有存储桶
const bucket = new aws.s3.Bucket("application-bucket", {}, {
aliases: [{ name: "my-bucket" }],
});移入组件的情况:
typescript
// 之前:顶层资源
const bucket = new aws.s3.Bucket("my-bucket");
// 之后:在组件内部 - 需要包含旧父级的别名
class MyComponent extends pulumi.ComponentResource {
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("myorg:components:MyComponent", name, {}, opts);
const bucket = new aws.s3.Bucket("bucket", {}, {
parent: this,
aliases: [{
name: "my-bucket",
parent: pulumi.rootStackResource, // 之前在根级别
}],
});
}
}别名类型:
typescript
// 简单名称变更
aliases: [{ name: "old-name" }]
// 父级变更
aliases: [{ name: "resource-name", parent: oldParent }]
// 完整URN(当你知道确切的之前URN时)
aliases: ["urn:pulumi:stack::project::aws:s3/bucket:Bucket::old-name"]生命周期:
- 重构时添加别名
- 在所有栈上运行
pulumi up - 所有栈更新后可移除别名(可选,但可保持代码整洁)
7. Preview Before Every Deployment
7. 每次部署前先预览
Why: shows exactly what will be created, updated, or destroyed. Surprises in production come from skipping preview. A resource showing "replace" when you expected "update" means imminent destruction and recreation.
pulumi previewDetection signals:
- Running interactively without reviewing changes
pulumi up --yes - No preview step anywhere in the CI/CD workflow for a given change
- Preview output not reviewed before merge or deployment approval
Wrong:
bash
undefined原因:会准确显示将创建、更新或销毁的内容。生产环境中的意外情况源于跳过预览。当你预期是"更新"但资源显示为"替换"时,意味着即将销毁并重新创建资源。
pulumi preview检测信号:
- 交互式运行而未评审变更
pulumi up --yes - CI/CD工作流中针对特定变更无预览步骤
- 预览输出在合并或部署审批前未被评审
错误示例:
bash
undefinedDeploying blind
盲目部署
pulumi up --yes
**Right**:
```bashpulumi up --yes
**正确示例**:
```bashAlways preview first
始终先预览
pulumi preview
pulumi preview
Review the output, then deploy
评审输出后再部署
pulumi up
**What to look for in preview**:
- `+ create` - New resource will be created
- `~ update` - Existing resource will be modified in place
- `- delete` - Resource will be destroyed
- `+-replace` - Resource will be destroyed and recreated (potential downtime)
- `~+-replace` - Resource will be updated, then replaced
**Warning signs**:
- Unexpected `replace` operations (check for immutable property changes)
- Resources being deleted that shouldn't be
- More changes than expected from your code diff
**CI/CD integration**:
```yamlpulumi up
**预览中需要关注的内容**:
- `+ create` - 将创建新资源
- `~ update` - 将原地修改现有资源
- `- delete` - 将销毁资源
- `+-replace` - 将销毁并重新创建资源(可能导致停机)
- `~+-replace` - 将先更新,再替换资源
**警告信号**:
- 意外的`replace`操作(检查是否更改了不可变属性)
- 不应被删除的资源被标记为删除
- 变更数量超出代码差异的预期
**CI/CD集成示例**:
```yamlGitHub Actions example
GitHub Actions示例
jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Pulumi Preview
uses: pulumi/actions@v5
with:
command: preview
stack-name: production
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
deploy:
needs: preview
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Pulumi Up
uses: pulumi/actions@v5
with:
command: up
stack-name: production
**PR workflow**:
- Run preview on every PR
- Post preview output as PR comment
- Require preview review before merge
- Deploy only on merge to main
**References**:
- https://www.pulumi.com/docs/cli/commands/pulumi_preview/
- https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/github-actions/
---jobs:
preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Pulumi Preview
uses: pulumi/actions@v5
with:
command: preview
stack-name: production
env:
PULUMI_ACCESS_TOKEN: ${{ secrets.PULUMI_ACCESS_TOKEN }}
deploy:
needs: preview
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Pulumi Up
uses: pulumi/actions@v5
with:
command: up
stack-name: production
**PR工作流**:
- 对每个PR运行预览
- 将预览输出作为PR评论发布
- 要求在合并前评审预览
- 仅在合并到main分支时部署
**参考文档**:
- https://www.pulumi.com/docs/cli/commands/pulumi_preview/
- https://www.pulumi.com/docs/iac/packages-and-automation/continuous-delivery/github-actions/
---Quick Reference
快速参考
| Practice | Key Signal | Fix |
|---|---|---|
| No resources in apply | | Move resource outside, pass Output directly |
| Pass outputs directly | Extracted values used as inputs | Use Output objects, |
| Use components | Flat structure, repeated patterns | Create ComponentResource classes |
| Set parent: this | Component children at root level | Pass |
| Secrets from day one | Plaintext passwords/keys in config | Use |
| Aliases when refactoring | Delete+create in preview | Add alias with old name/parent |
| Preview before deploy | | Always run |
| 实践要点 | 关键信号 | 修复方案 |
|---|---|---|
| 不在apply中创建资源 | | 将资源移到外部,直接传递Output |
| 直接传递输出值 | 提取的值用作输入 | 使用Output对象、 |
| 使用组件 | 扁平结构、重复模式 | 创建ComponentResource类 |
| 设置parent: this | 组件子资源在根级别 | 向所有子资源传递 |
| 从第一天起使用密钥 | 配置中存在明文密码/密钥 | 使用 |
| 重构时使用别名 | 预览中显示删除+创建 | 添加包含旧名称/父级的别名 |
| 部署前先预览 | 使用 | 始终先运行 |
Validation Checklist
验证检查清单
When reviewing Pulumi code, verify:
- No resource constructors inside callbacks
apply() - Outputs passed directly to dependent resources
- Related resources grouped in ComponentResource classes
- Child resources have
{ parent: this } - Sensitive values use or
config.requireSecret()--secret - Refactored resources have aliases preserving identity
- Deployment process includes preview step
评审Pulumi代码时,请验证:
- 回调中无资源构造函数
apply() - 输出值直接传递给依赖资源
- 相关资源分组在ComponentResource类中
- 子资源设置了
{ parent: this } - 敏感值使用或
config.requireSecret()--secret - 重构后的资源有保留标识的别名
- 部署流程包含预览步骤
Related Skills
相关技能
- pulumi-component: Deep guide to authoring ComponentResource classes, designing args interfaces, multi-language support, testing, and distribution. Use skill .
pulumi-component - pulumi-automation-api: Programmatic orchestration of multiple stacks. Use skill .
pulumi-automation-api - pulumi-esc: Centralized secrets and configuration management. Use skill .
pulumi-esc
- pulumi-component:ComponentResource类创作、参数接口设计、多语言支持、测试和分发的深度指南。使用技能。
pulumi-component - pulumi-automation-api:多栈的程序化编排。使用技能。
pulumi-automation-api - pulumi-esc:集中式密钥和配置管理。使用技能。
pulumi-esc