pulumi-python

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Pulumi Python Skill

Pulumi Python 技能指南

Development Workflow

开发工作流

1. Project Setup

1. 项目设置

bash
undefined
bash
undefined

Create new Python project

创建新的Python项目

pulumi new python
pulumi new python

Or with a cloud-specific template

或者使用云服务商特定模板

pulumi new aws-python pulumi new azure-python pulumi new gcp-python

**Project structure:**
my-project/ ├── Pulumi.yaml ├── Pulumi.dev.yaml # Stack config (use ESC instead) ├── main.py ├── requirements.txt # or pyproject.toml └── venv/ # Virtual environment
undefined
pulumi new aws-python pulumi new azure-python pulumi new gcp-python

**项目结构:**
my-project/ ├── Pulumi.yaml ├── Pulumi.dev.yaml # 栈配置(建议使用ESC替代) ├── main.py ├── requirements.txt # 或pyproject.toml └── venv/ # 虚拟环境
undefined

2. Pulumi ESC Integration

2. Pulumi ESC 集成

Instead of using
pulumi config set
or stack config files, use Pulumi ESC for centralized secrets and configuration.
Link ESC environment to stack:
bash
undefined
建议使用Pulumi ESC集中管理密钥和配置,替代
pulumi config set
命令或栈配置文件。
将ESC环境关联到栈:
bash
undefined

Create ESC environment

创建ESC环境

pulumi env init myorg/myproject-dev
pulumi env init myorg/myproject-dev

Edit environment

编辑环境

pulumi env edit myorg/myproject-dev
pulumi env edit myorg/myproject-dev

Link to Pulumi stack

关联到Pulumi栈

pulumi config env add myorg/myproject-dev

**ESC environment definition (YAML):**
```yaml
values:
  # Static configuration
  pulumiConfig:
    aws:region: us-west-2
    myapp:instanceType: t3.medium

  # Dynamic OIDC credentials for AWS
  aws:
    login:
      fn::open::aws-login:
        oidc:
          roleArn: arn:aws:iam::123456789:role/pulumi-oidc
          sessionName: pulumi-deploy

  # Pull secrets from AWS Secrets Manager
  secrets:
    fn::open::aws-secrets:
      region: us-west-2
      login: ${aws.login}
      get:
        dbPassword:
          secretId: prod/database/password

  # Expose to environment variables
  environmentVariables:
    AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
    AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
    AWS_SESSION_TOKEN: ${aws.login.sessionToken}
pulumi config env add myorg/myproject-dev

**ESC环境定义(YAML):**
```yaml
values:
  # 静态配置
  pulumiConfig:
    aws:region: us-west-2
    myapp:instanceType: t3.medium

  # 用于AWS的动态OIDC凭证
  aws:
    login:
      fn::open::aws-login:
        oidc:
          roleArn: arn:aws:iam::123456789:role/pulumi-oidc
          sessionName: pulumi-deploy

  # 从AWS Secrets Manager拉取密钥
  secrets:
    fn::open::aws-secrets:
      region: us-west-2
      login: ${aws.login}
      get:
        dbPassword:
          secretId: prod/database/password

  # 暴露为环境变量
  environmentVariables:
    AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
    AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
    AWS_SESSION_TOKEN: ${aws.login.sessionToken}

3. Python Patterns

3. Python 编程模式

Basic resource creation:
python
import pulumi
import pulumi_aws as aws
基础资源创建:
python
import pulumi
import pulumi_aws as aws

Get configuration from ESC

从ESC获取配置

config = pulumi.Config() instance_type = config.require("instanceType")
config = pulumi.Config() instance_type = config.require("instanceType")

Create resources with proper tagging

创建带合适标签的资源

bucket = aws.s3.Bucket( "my-bucket", versioning=aws.s3.BucketVersioningArgs( enabled=True, ), server_side_encryption_configuration=aws.s3.BucketServerSideEncryptionConfigurationArgs( rule=aws.s3.BucketServerSideEncryptionConfigurationRuleArgs( apply_server_side_encryption_by_default=aws.s3.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs( sse_algorithm="AES256", ), ), ), tags={ "Environment": pulumi.get_stack(), "ManagedBy": "Pulumi", }, )
bucket = aws.s3.Bucket( "my-bucket", versioning=aws.s3.BucketVersioningArgs( enabled=True, ), server_side_encryption_configuration=aws.s3.BucketServerSideEncryptionConfigurationArgs( rule=aws.s3.BucketServerSideEncryptionConfigurationRuleArgs( apply_server_side_encryption_by_default=aws.s3.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs( sse_algorithm="AES256", ), ), ), tags={ "Environment": pulumi.get_stack(), "ManagedBy": "Pulumi", }, )

Export outputs

导出输出

pulumi.export("bucket_name", bucket.id) pulumi.export("bucket_arn", bucket.arn)

**Using dictionary literals (concise alternative):**
```python
import pulumi
import pulumi_aws as aws

bucket = aws.s3.Bucket(
    "my-bucket",
    versioning={"enabled": True},
    server_side_encryption_configuration={
        "rule": {
            "apply_server_side_encryption_by_default": {
                "sse_algorithm": "AES256",
            },
        },
    },
    tags={
        "Environment": pulumi.get_stack(),
        "ManagedBy": "Pulumi",
    },
)
Component resources for reusability:
python
import pulumi
from pulumi_aws import lb


class WebServiceArgs:
    def __init__(self, port: pulumi.Input[int], image_uri: pulumi.Input[str]):
        self.port = port
        self.image_uri = image_uri


class WebService(pulumi.ComponentResource):
    url: pulumi.Output[str]

    def __init__(self, name: str, args: WebServiceArgs, opts: pulumi.ResourceOptions = None):
        super().__init__("custom:app:WebService", name, {}, opts)

        # Create child resources with parent=self
        load_balancer = lb.LoadBalancer(
            f"{name}-lb",
            load_balancer_type="application",
            # ... configuration
            opts=pulumi.ResourceOptions(parent=self),
        )

        self.url = load_balancer.dns_name

        self.register_outputs({
            "url": self.url,
        })
Stack references for cross-stack dependencies:
python
import pulumi
pulumi.export("bucket_name", bucket.id) pulumi.export("bucket_arn", bucket.arn)

**使用字典字面量(简洁写法):**
```python
import pulumi
import pulumi_aws as aws

bucket = aws.s3.Bucket(
    "my-bucket",
    versioning={"enabled": True},
    server_side_encryption_configuration={
        "rule": {
            "apply_server_side_encryption_by_default": {
                "sse_algorithm": "AES256",
            },
        },
    },
    tags={
        "Environment": pulumi.get_stack(),
        "ManagedBy": "Pulumi",
    },
)
可复用的组件资源:
python
import pulumi
from pulumi_aws import lb


class WebServiceArgs:
    def __init__(self, port: pulumi.Input[int], image_uri: pulumi.Input[str]):
        self.port = port
        self.image_uri = image_uri


class WebService(pulumi.ComponentResource):
    url: pulumi.Output[str]

    def __init__(self, name: str, args: WebServiceArgs, opts: pulumi.ResourceOptions = None):
        super().__init__("custom:app:WebService", name, {}, opts)

        # 创建子资源并指定parent=self
        load_balancer = lb.LoadBalancer(
            f"{name}-lb",
            load_balancer_type="application",
            # ... 配置内容
            opts=pulumi.ResourceOptions(parent=self),
        )

        self.url = load_balancer.dns_name

        self.register_outputs({
            "url": self.url,
        })
跨栈依赖的栈引用:
python
import pulumi

Reference outputs from networking stack

引用网络栈的输出

networking_stack = pulumi.StackReference("myorg/networking/prod") vpc_id = networking_stack.get_output("vpc_id") subnet_ids = networking_stack.get_output("private_subnet_ids")

**Working with Outputs:**
```python
import pulumi
networking_stack = pulumi.StackReference("myorg/networking/prod") vpc_id = networking_stack.get_output("vpc_id") subnet_ids = networking_stack.get_output("private_subnet_ids")

**处理Output对象:**
```python
import pulumi

Apply transformation

应用转换

uppercase_name = bucket.id.apply(lambda id: id.upper())
uppercase_name = bucket.id.apply(lambda id: id.upper())

Combine multiple outputs

合并多个输出

combined = pulumi.Output.all(bucket.id, bucket.arn).apply( lambda args: f"Bucket {args[0]} has ARN {args[1]}" )
combined = pulumi.Output.all(bucket.id, bucket.arn).apply( lambda args: f"Bucket {args[0]} 的ARN为 {args[1]}" )

Using Output.concat for string interpolation

使用Output.concat进行字符串插值

message = pulumi.Output.concat("Bucket ARN: ", bucket.arn)
message = pulumi.Output.concat("Bucket ARN: ", bucket.arn)

Conditional resources

条件化资源

is_prod = pulumi.get_stack() == "prod" if is_prod: alarm = aws.cloudwatch.MetricAlarm( "alarm", # ... configuration )
undefined
is_prod = pulumi.get_stack() == "prod" if is_prod: alarm = aws.cloudwatch.MetricAlarm( "alarm", # ... 配置内容 )
undefined

4. Using ESC with pulumi env run

4. 结合ESC使用 pulumi env run

Run any command with ESC environment variables injected:
bash
undefined
运行任意命令时注入ESC环境变量:
bash
undefined

Run pulumi commands with ESC credentials

使用ESC凭证运行pulumi命令

pulumi env run myorg/aws-dev -- pulumi up
pulumi env run myorg/aws-dev -- pulumi up

Run tests with secrets

使用密钥运行测试

pulumi env run myorg/test-env -- pytest
pulumi env run myorg/test-env -- pytest

Open environment and export to shell

打开环境并导出到shell

pulumi env open myorg/myproject-dev --format shell
undefined
pulumi env open myorg/myproject-dev --format shell
undefined

5. Async Patterns

5. 异步编程模式

python
import pulumi
import asyncio
python
import pulumi
import asyncio

Pulumi programs are single-threaded

Pulumi程序是单线程的

Use Output.from_input for async-like patterns

使用Output.from_input实现类异步模式

async def fetch_data(): # Async operation return {"key": "value"}
async def fetch_data(): # 异步操作 return {"key": "value"}

Convert async result to Output

将异步结果转换为Output

data = pulumi.Output.from_input(asyncio.get_event_loop().run_until_complete(fetch_data()))
undefined
data = pulumi.Output.from_input(asyncio.get_event_loop().run_until_complete(fetch_data()))
undefined

6. Multi-Language Components

6. 多语言组件

Create components in Python that can be consumed from any Pulumi language (TypeScript, Go, C#, Java, YAML).
Project structure for multi-language component:
my-component/
├── PulumiPlugin.yaml      # Required for multi-language
├── pyproject.toml         # or requirements.txt
└── __main__.py            # Component + entry point
PulumiPlugin.yaml:
yaml
runtime: python
Component with proper Args class (main.py):
python
from typing import Optional
import pulumi
from pulumi import Input, Output, ResourceOptions
from pulumi.provider.experimental import component_provider_host
import pulumi_aws as aws


class SecureBucketArgs:
    """Args class - use Input types for all properties."""

    def __init__(
        self,
        bucket_name: Input[str],
        enable_versioning: Optional[Input[bool]] = None,
        tags: Optional[Input[dict]] = None,
    ):
        self.bucket_name = bucket_name
        self.enable_versioning = enable_versioning or True
        self.tags = tags


class SecureBucket(pulumi.ComponentResource):
    """A secure S3 bucket with encryption and versioning."""

    bucket_id: Output[str]
    bucket_arn: Output[str]

    # Constructor must have 'args' parameter with type annotation
    def __init__(
        self,
        name: str,
        args: SecureBucketArgs,
        opts: Optional[ResourceOptions] = None,
    ):
        super().__init__("myorg:storage:SecureBucket", name, {}, opts)

        bucket = aws.s3.Bucket(
            f"{name}-bucket",
            bucket=args.bucket_name,
            versioning={"enabled": args.enable_versioning},
            server_side_encryption_configuration={
                "rule": {
                    "apply_server_side_encryption_by_default": {
                        "sse_algorithm": "AES256",
                    },
                },
            },
            tags=args.tags,
            opts=ResourceOptions(parent=self),
        )

        self.bucket_id = bucket.id
        self.bucket_arn = bucket.arn

        self.register_outputs({
            "bucket_id": self.bucket_id,
            "bucket_arn": self.bucket_arn,
        })
创建Python编写的组件,可被任意Pulumi支持的语言(TypeScript、Go、C#、Java、YAML)调用。
多语言组件的项目结构:
my-component/
├── PulumiPlugin.yaml      # 多语言支持必填
├── pyproject.toml         # 或requirements.txt
└── __main__.py            # 组件代码+入口
PulumiPlugin.yaml:
yaml
runtime: python
带Args类的组件实现(main.py):
python
from typing import Optional
import pulumi
from pulumi import Input, Output, ResourceOptions
from pulumi.provider.experimental import component_provider_host
import pulumi_aws as aws


class SecureBucketArgs:
    """Args类 - 所有属性使用Input类型"""

    def __init__(
        self,
        bucket_name: Input[str],
        enable_versioning: Optional[Input[bool]] = None,
        tags: Optional[Input[dict]] = None,
    ):
        self.bucket_name = bucket_name
        self.enable_versioning = enable_versioning or True
        self.tags = tags


class SecureBucket(pulumi.ComponentResource):
    """带加密和版本控制的安全S3存储桶"""

    bucket_id: Output[str]
    bucket_arn: Output[str]

    # 构造函数必须包含带类型注解的'args'参数
    def __init__(
        self,
        name: str,
        args: SecureBucketArgs,
        opts: Optional[ResourceOptions] = None,
    ):
        super().__init__("myorg:storage:SecureBucket", name, {}, opts)

        bucket = aws.s3.Bucket(
            f"{name}-bucket",
            bucket=args.bucket_name,
            versioning={"enabled": args.enable_versioning},
            server_side_encryption_configuration={
                "rule": {
                    "apply_server_side_encryption_by_default": {
                        "sse_algorithm": "AES256",
                    },
                },
            },
            tags=args.tags,
            opts=ResourceOptions(parent=self),
        )

        self.bucket_id = bucket.id
        self.bucket_arn = bucket.arn

        self.register_outputs({
            "bucket_id": self.bucket_id,
            "bucket_arn": self.bucket_arn,
        })

Entry point for multi-language support

多语言支持入口

if name == "main": component_provider_host( name="python-components", components=[SecureBucket], )

**Publishing for multi-language consumption:**
```bash
if name == "main": component_provider_host( name="python-components", components=[SecureBucket], )

**发布供多语言调用的组件:**
```bash

Consume from git repository

从Git仓库引入组件

pulumi package add github.com/myorg/my-component
pulumi package add github.com/myorg/my-component

With version tag

指定版本标签

pulumi package add github.com/myorg/my-component@v1.0.0
pulumi package add github.com/myorg/my-component@v1.0.0

Local development

本地开发时引入

pulumi package add /path/to/local/my-component

**Multi-language Args requirements:**
- Use `pulumi.Input[T]` type hints for all properties
- Args class must have `__init__` with typed parameters
- Constructor must have `args` parameter with type annotation
- Use `Optional[Input[T]]` for optional properties
pulumi package add /path/to/local/my-component

**多语言Args类要求:**
- 所有属性使用`pulumi.Input[T]`类型提示
- Args类必须包含带类型参数的`__init__`方法
- 组件构造函数必须包含带类型注解的`args`参数
- 可选属性使用`Optional[Input[T]]`

Best Practices

最佳实践

Security

安全

  • Use Pulumi ESC for all secrets - never commit secrets to stack config files
  • Enable OIDC authentication instead of static credentials
  • Use dynamic secrets with short TTLs when possible
  • Apply least-privilege IAM policies
  • 使用Pulumi ESC管理所有密钥 - 切勿将密钥提交到栈配置文件
  • 启用OIDC认证替代静态凭证
  • 尽可能使用带短TTL的动态密钥
  • 应用最小权限原则的IAM策略

Code Organization

代码组织

  • Use ComponentResources for reusable infrastructure patterns
  • Leverage Python's type hints for better IDE support
  • Keep stack-specific config in ESC environments
  • Use stack references for cross-stack dependencies
  • Prefer Args classes for type safety, or dict literals for brevity
  • 使用ComponentResource实现可复用的基础设施模式
  • 利用Python类型提示获得更好的IDE支持
  • 将栈特定配置存储在ESC环境中
  • 使用栈引用处理跨栈依赖
  • 优先使用Args类保证类型安全,或使用字典字面量简化代码

Deployment

部署

  • Always run
    pulumi preview
    before
    pulumi up
  • Use ESC environment versioning and tags for releases
  • Implement proper tagging strategy for all resources
  • 执行
    pulumi up
    前务必先运行
    pulumi preview
  • 对ESC环境使用版本控制和标签管理发布
  • 为所有资源实现规范的标签策略

Virtual Environments

虚拟环境

  • Always use virtual environments (
    venv
    ,
    poetry
    , or
    uv
    )
  • Specify toolchain in Pulumi.yaml for consistency
  • 始终使用虚拟环境(
    venv
    poetry
    uv
  • 在Pulumi.yaml中指定工具链以保证一致性

Common Commands

常用命令

bash
undefined
bash
undefined

Environment Commands (pulumi env)

环境命令(pulumi env)

pulumi env init <org>/<project>/<env> # Create environment pulumi env edit <org>/<env> # Edit environment pulumi env open <org>/<env> # View resolved values pulumi env run <org>/<env> -- <command> # Run with env vars pulumi env version tag <org>/<env> <tag> # Tag version
pulumi env init <org>/<project>/<env> # 创建环境 pulumi env edit <org>/<env> # 编辑环境 pulumi env open <org>/<env> # 查看解析后的值 pulumi env run <org>/<env> -- <command> # 注入环境变量运行命令 pulumi env version tag <org>/<env> <tag> # 为版本打标签

Pulumi Commands

Pulumi核心命令

pulumi new python # New project pulumi config env add <org>/<env> # Link ESC environment pulumi preview # Preview changes pulumi up # Deploy pulumi stack output # View outputs pulumi destroy # Tear down
pulumi new python # 创建新项目 pulumi config env add <org>/<env> # 关联ESC环境 pulumi preview # 预览变更 pulumi up # 部署 pulumi stack output # 查看输出 pulumi destroy # 销毁资源

Dependency Management

依赖管理

pip install -r requirements.txt # Install deps (pip) poetry add pulumi-aws # Add dep (poetry) uv add pulumi-aws # Add dep (uv)
undefined
pip install -r requirements.txt # 安装依赖(pip) poetry add pulumi-aws # 添加依赖(poetry) uv add pulumi-aws # 添加依赖(uv)
undefined

Python-Specific Considerations

Python特定注意事项

Virtual Environment Setup

虚拟环境设置

Using pip (default):
yaml
undefined
使用pip(默认):
yaml
undefined

Pulumi.yaml

Pulumi.yaml

runtime: name: python options: toolchain: pip virtualenv: venv

**Using poetry:**
```yaml
runtime: name: python options: toolchain: pip virtualenv: venv

**使用poetry:**
```yaml

Pulumi.yaml

Pulumi.yaml

runtime: name: python options: toolchain: poetry

**Using uv:**
```yaml
runtime: name: python options: toolchain: poetry

**使用uv:**
```yaml

Pulumi.yaml

Pulumi.yaml

runtime: name: python options: toolchain: uv virtualenv: .venv
undefined
runtime: name: python options: toolchain: uv virtualenv: .venv
undefined

Type Checking

类型检查

yaml
undefined
yaml
undefined

Pulumi.yaml - Enable type checking

Pulumi.yaml - 启用类型检查

runtime: name: python options: typechecker: mypy # or pyright
undefined
runtime: name: python options: typechecker: mypy # 或pyright
undefined

Input Type Options

输入类型选项

python
undefined
python
undefined

Using Args classes (type-safe)

使用Args类(类型安全)

bucket = aws.s3.Bucket( "bucket", versioning=aws.s3.BucketVersioningArgs(enabled=True), )
bucket = aws.s3.Bucket( "bucket", versioning=aws.s3.BucketVersioningArgs(enabled=True), )

Using dict literals (concise)

使用字典字面量(简洁)

bucket = aws.s3.Bucket( "bucket", versioning={"enabled": True}, )
undefined
bucket = aws.s3.Bucket( "bucket", versioning={"enabled": True}, )
undefined

References

参考链接

  • references/pulumi-esc.md - ESC patterns and commands
  • references/pulumi-patterns.md - Common infrastructure patterns
  • references/pulumi-python.md - Python-specific guidance
  • references/pulumi-best-practices-aws.md - AWS best practices
  • references/pulumi-best-practices-azure.md - Azure best practices
  • references/pulumi-best-practices-gcp.md - GCP best practices
  • references/pulumi-esc.md - ESC模式与命令
  • references/pulumi-patterns.md - 常见基础设施模式
  • references/pulumi-python.md - Python特定指南
  • references/pulumi-best-practices-aws.md - AWS最佳实践
  • references/pulumi-best-practices-azure.md - Azure最佳实践
  • references/pulumi-best-practices-gcp.md - GCP最佳实践