Terraform 生成器
概览
这个技能使得生成遵循最佳实践和当前标准的生产就绪Terraform配置(HCL文件)成为可能。在创建新的Terraform资源或构建Terraform项目时,请使用这项技能。
关键需求清单
停止:您必须按顺序完成所有步骤。不要跳过任何必需的步骤。
| 步骤 | 行动 | 必需 |
|---|---|---|
| 1 | 理解需求(提供者、资源、模块) | ✳️ 必需 |
| 2 | 检查自定义提供者/模块并查找文档 | ✳️ 必需 |
| 3 | 生成前咨询参考文件 | ✳️ 必需 |
| 4 | 使用所有最佳实践生成Terraform文件 | ✳️ 必需 |
| 5 | 包括数据源以获取动态值(区域、账户、AMI) | ✳️ 必需 |
| 6 | 在关键资源上添加生命周期规则(KMS、数据库) | ✳️ 必需 |
| 7 | 调用Skill(devops-skills:terraform-validator) |
✳️ 必需 |
| 8 | 修复所有验证/安全失败并重新验证 | ✳️ 必需 |
| 9 | 提供使用说明(文件、后续步骤、安全) | ✳️ 必需 |
**重要:**如果验证失败(terraform validate OR 安全扫描),您必须修复问题并重新运行验证,直到所有检查通过。不要在检查失败的情况下进入第9步。
核心工作流程
生成Terraform配置时,请遵循此工作流程:
步骤 1:理解需求
分析用户请求以确定:
- 需要创建哪些基础设施资源
- 需要哪些Terraform提供者(AWS、Azure、GCP、自定义等)
- 是否使用任何模块(官方、社区或自定义)
- 提供者和模块的版本约束
- 需要的变量输入和输出
- 状态后端配置(本地、S3、远程等)
步骤 2:检查自定义提供者/模块
在生成配置之前,确定是否涉及自定义或第三方提供者/模块:
标准提供者(无需查找):
- hashicorp/aws
- hashicorp/azurerm
- hashicorp/google
- hashicorp/kubernetes
- 其他官方HashiCorp提供者
自定义/第三方提供者/模块(需要文档查找):
- 第三方提供者(例如,datadog/datadog, mongodb/mongodbatlas)
- Terraform Registry中的自定义模块
- 私有或公司特定的模块
- 社区模块
当检测到自定义提供者/模块时:
-
使用WebSearch查找特定版本的文档:
搜索查询格式:"[提供者/模块名称] terraform [版本] documentation [特定资源]" 示例:"datadog terraform provider v3.30 monitor resource documentation" 示例:"terraform-aws-modules vpc version 5.0 documentation" -
搜索重点:
- 官方文档(registry.terraform.io, 提供者网站)
- 必需和可选参数
- 属性引用
- 示例用法
- 版本兼容性说明
-
如果Context7 MCP可用且支持该提供者/模块,则使用它作为替代方案:
mcp__context7__resolve-library-id → mcp__context7__get-library-docs
步骤 2.5:咨询参考文件(必需)
在生成配置之前,您必须阅读相关参考文件:
Read(file_path: ".claude/skills/terraform-generator/references/terraform_best_practices.md")
Read(file_path: ".claude/skills/terraform-generator/references/provider_examples.md")
何时咨询每个参考:
| 参考 | 阅读时 |
|---|---|
terraform_best_practices.md |
总是 - 包含必需的模式 |
common_patterns.md |
多环境、工作区或复杂设置 |
provider_examples.md |
生成AWS、Azure、GCP或K8s资源 |
步骤 3:生成Terraform配置
按照最佳实践生成HCL文件:
文件组织:
terraform-project/
├── main.tf # 主要资源定义
├── variables.tf # 输入变量声明
├── outputs.tf # 输出值声明
├── versions.tf # 提供者版本约束
├── terraform.tfvars # 变量值(可选,示例)
└── backend.tf # 后端配置(可选)
要遵循的最佳实践:
-
提供者配置:
terraform { required_version = ">= 1.10, < 2.0" required_providers { aws = { source = "hashicorp/aws" version = "~> 6.0" # 最新:v6.23.0 (2025年12月) } } } provider "aws" { region = var.aws_region } -
资源命名:
- 使用描述性资源名称
- 遵循snake_case约定
- 在有帮助时在名称中包含资源类型
resource "aws_instance" "web_server" { # ... } -
变量声明:
variable "instance_type" { description = "用于web服务器的EC2实例类型" type = string default = "t3.micro" validation { condition = contains(["t3.micro", "t3.small", "t3.medium"], var.instance_type) error_message = "实例类型必须是t3.micro、t3.small或t3.medium。" } } -
输出值:
output "instance_public_ip" { description = "web服务器的公共IP地址" value = aws_instance.web_server.public_ip } -
使用数据源进行引用:
data "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] } } -
模块使用:
module "vpc" { source = "terraform-aws-modules/vpc/aws" version = "5.0.0" name = "my-vpc" cidr = "10.0.0.0/16" azs = ["us-east-1a", "us-east-1b"] private_subnets = ["10.0.1.0/24", "10.0.2.0/24"] public_subnets = ["10.0.101.0/24", "10.0.102.0/24"] } -
使用locals计算值:
locals { common_tags = { Environment = var.environment ManagedBy = "Terraform" Project = var.project_name } } -
适当时添加生命周期规则:
resource "aws_instance" "example" { # ... lifecycle { create_before_destroy = true prevent_destroy = true ignore_changes = [tags] } } -
动态块用于重复配置:
resource "aws_security_group" "example" { # ... dynamic "ingress" { for_each = var.ingress_rules content { from_port = ingress.value.from_port to_port = ingress.value.to_port protocol = ingress.value.protocol cidr_blocks = ingress.value.cidr_blocks } } } -
注释和文档:
- 添加注释解释复杂逻辑
- 记录为什么使用某些值
- 在变量描述中包括示例
安全最佳实践:
- 永远不要硬编码敏感值(使用变量)
- 使用数据源获取AMI和其他动态值
- 实施最少权限IAM策略
- 默认启用加密
- 使用安全的后端配置
必需:动态值的数据源
您必须包括用于动态基础设施值的数据源。不要硬编码这些:
# 必需:当前AWS区域和账户信息
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}
# 在资源中使用
locals {
account_id = data.aws_caller_identity.current.account_id
region = data.aws_region.current.name
}
常见必需的数据源:
| 用例 | 数据源 |
|---|---|
| 当前区域 | data "aws_region" "current" {} |
| 当前账户 | data "aws_caller_identity" "current" {} |
| 可用AZ | data "aws_availability_zones" "available" {} |
| 最新AMI | data "aws_ami" "..." 带过滤器 |
| 现有VPC | data "aws_vpc" "..." |
必需:关键资源上的生命周期规则
您必须在可能会因意外销毁而导致数据丢失或服务中断的资源上添加生命周期规则:
# KMS密钥 - 始终保护免于删除
resource "aws_kms_key" "encryption" {
# ...
lifecycle {
prevent_destroy = true
}
}
# 数据库 - 始终保护免于删除
resource "aws_db_instance" "main" {
# ...
lifecycle {
prevent_destroy = true
}
}
# 包含数据的S3桶 - 保护免于删除
resource "aws_s3_bucket" "data" {
# ...
lifecycle {
prevent_destroy = true
}
}
必须有prevent_destroy = true的资源:
- KMS密钥(
aws_kms_key) - RDS数据库(
aws_db_instance,aws_rds_cluster) - 包含数据的S3桶
- DynamoDB表中的数据
- ElastiCache集群
- Secrets Manager机密
必需:S3生命周期最佳实践
创建具有生命周期配置的S3桶时,始终包括一条规则以中止不完整的多部分上传:
resource "aws_s3_bucket_lifecycle_configuration" "main" {
bucket = aws_s3_bucket.main.id
# 必需:中止不完整的多部分上传以防止存储成本
rule {
id = "abort-incomplete-uploads"
status = "Enabled"
# 过滤器适用于所有对象(空过滤器=所有对象)
filter {}
abort_incomplete_multipart_upload {
days_after_initiation = 7
}
}
# 其他生命周期规则(例如,转换为IA)
rule {
id = "transition-to-ia"
status = "Enabled"
filter {
prefix = "" # 适用于所有对象
}
transition {
days = 90
storage_class = "STANDARD_IA"
}
noncurrent_version_transition {
noncurrent_days = 30
storage_class = "STANDARD_IA"
}
noncurrent_version_expiration {
noncurrent_days = 365
}
}
}
为什么? 不完整的多部分上传会消耗存储并产生成本。Checkov检查
CKV_AWS_300强制执行此规则。始终包括这条规则。
步骤 4:验证生成的配置(必需)
生成Terraform文件后,始终使用devops-skills:terraform-validator技能进行验证:
Invoke: Skill(devops-skills:terraform-validator)
devops-skills:terraform-validator技能将:
- 使用
terraform fmt -check检查HCL语法 - 使用
terraform init初始化配置 - 使用
terraform validate验证配置 - 使用Checkov进行安全扫描
- 如果请求,使用
terraform plan进行干运行测试
关键:修复和重新验证循环
如果任何验证或安全检查失败,您必须:
- 查看错误 - 了解失败的原因
- 修复问题 - 编辑生成的文件以解决问题
- 重新运行验证 - 再次调用
Skill(devops-skills:terraform-validator) - 重复直到所有检查通过 - 不要带着失败的检查继续
┌─────────────────────────────────────────────────────────┐
│ 验证失败了吗? │
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────────────────┐ │
│ │ 修复 │───▶│ 重新运行 │───▶│ 所有检查都通过了? │ │
│ │ 问题 │ │ 技能 │ │ YES → 第5步 │ │
│ └─────────┘ └─────────┘ │ NO → 循环回去 │ │
│ ▲ └─────────────────────┘ │
│ │ │ │
│ └────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
常见验证失败及修复:
| 检查 | 问题 | 修复 |
|---|---|---|
CKV_AWS_300 |
缺少中止多部分上传 | 添加abort_incomplete_multipart_upload规则 |
CKV_AWS_24 |
SSH对0.0.0.0/0开放 | 限制为特定CIDR |
CKV_AWS_16 |
RDS加密被禁用 | 添加storage_encrypted = true |
terraform validate |
无效的资源参数 | 查看提供者文档 |
如果验证期间检测到自定义提供者:
- devops-skills:terraform-validator技能将自动获取文档
- 使用获取的文档修复任何问题
步骤 5:提供使用说明(必需)
成功生成和验证所有检查通过后,您必须向用户提供:
必需输出格式:
## 生成的文件
| 文件 | 描述 |
|------|-------------|
| `path/to/main.tf` | 主要资源定义 |
| `path/to/variables.tf` | 输入变量 |
| `path/to/outputs.tf` | 输出值 |
| `path/to/versions.tf` | 提供者版本约束 |
## 后续步骤
1. 审查并自定义`terraform.tfvars`中的值
2. 初始化Terraform:
```bash
terraform init
- 审查执行计划:
terraform plan - 应用配置:
terraform apply
自定义说明
- [ ] 在terraform.tfvars中更新
variable_name - [ ] 在backend.tf中配置后端以进行远程状态
- [ ] 根据需要调整资源名称/标签
安全提醒
⚠️ 在应用之前:
- 审查IAM策略和权限
- 确保敏感值不提交到版本控制
- 使用启用加密的状态后端配置
- 设置状态锁定以进行团队协作
> **重要:**不要跳过第5步。用户需要可操作的指导,了解如何使用生成的配置。
## 常见生成模式
### 模式1:简单资源创建
用户请求:"创建一个带有版本控制的AWS S3桶"
生成的文件:
- `main.tf` - 启用版本控制的S3桶资源
- `variables.tf` - 桶名称、标签变量
- `outputs.tf` - 桶ARN和名称输出
- `versions.tf` - AWS提供者版本约束
### 模式2:基于模块的基础设施
用户请求:"使用官方AWS VPC模块设置VPC"
操作:
1. 确定模块:terraform-aws-modules/vpc/aws
2. 网络搜索最新版本和文档
3. 使用模块及适当输入生成配置
4. 使用devops-skills:terraform-validator进行验证
### 模式3:多提供者配置
用户请求:"在AWS和Datadog上创建跨基础设施"
操作:
1. 确定标准提供者(AWS)和自定义提供者(Datadog)
2. 网络搜索Datadog提供者文档及版本
3. 生成配置,正确配置两个提供者
4. 如有需要,确保提供者别名
5. 使用devops-skills:terraform-validator进行验证
### 模式4:具有依赖关系的复杂资源
用户请求:"创建一个带有ALB和自动扩展的ECS集群"
生成结构:
- 多个资源块,具有适当的依赖关系
- 数据源用于AMI、可用区域等
- 用于计算配置的本地值
- 综合变量和输出
- 使用隐式引用进行适当的依赖管理
## 错误处理
**常见问题及解决方案:**
1. **提供者未找到:**
- 确保提供者在`required_providers`块中列出
- 验证源地址格式:`namespace/name`
- 检查版本约束语法
2. **无效的资源参数:**
- 为自定义提供者参考网络搜索结果
- 检查必需与可选参数
- 验证属性值类型(字符串、数字、布尔值、列表、映射)
3. **循环依赖:**
- 审查资源引用
- 如有需要,使用`depends_on`显式依赖
- 考虑拆分为单独的模块
4. **验证失败:**
- 运行devops-skills:terraform-validator技能以获取详细错误
- 一次修复一个问题
- 每次修复后重新验证
## 版本意识
始终考虑版本兼容性:
1. **Terraform版本:**
- 使用`required_version`约束,具有下界和上界
- 默认使用`>= 1.10, < 2.0`以获得现代功能(临时资源、只写)
- 使用`>= 1.14, < 2.0`以获得最新功能(动作、查询命令)
- 文档化使用的任何版本特定功能(见下文)
2. **提供者版本(截至2025年12月):**
- AWS:`~> 6.0`(最新:v6.23.0)
- Azure:`~> 4.0`(最新:v4.54.0)
- GCP:`~> 7.0`(最新:v7.12.0)- 7.0包括临时资源和只写属性
- Kubernetes:`~> 2.23`
- 使用`~>`进行次要版本灵活性,固定主版本
3. **模块版本:**
- 始终固定模块版本
- 查阅模块文档以了解版本兼容性
- 首先在非生产环境中测试模块更新
### Terraform版本功能矩阵
| 功能 | 最低版本 |
|---------|-----------------|
| `terraform_data`资源 | 1.4+ |
| `import {}`块 | 1.5+ |
| `check {}`块 | 1.5+ |
| 本机测试(`.tftest.hcl`) | 1.6+ |
| 测试模拟 | 1.7+ |
| `removed {}`块 | 1.7+ |
| 提供者定义的函数 | 1.8+ |
| 跨类型重构 | 1.8+ |
| 增强型变量验证 | 1.9+ |
| `templatestring`函数 | 1.9+ |
| 临时资源 | 1.10+ |
| 只写参数 | 1.11+ |
| S3本机状态锁定 | 1.11+ |
| 带有`for_each`的导入块 | 1.12+ |
| 动作块 | 1.14+ |
| 列表资源(`tfquery.hcl`) | 1.14+ |
| `terraform query`命令 | 1.14+ |
## 现代Terraform功能(1.8+)
### 提供者定义的函数(Terraform 1.8+)
提供者定义的函数扩展了Terraform的内置函数,提供了特定于提供者的逻辑。
**语法:** `provider::<provider_name>::<function_name>(arguments)`
```hcl
# AWS提供者函数(v5.40+)
locals {
# 将ARN解析为组件
parsed_arn = provider::aws::arn_parse(aws_instance.web.arn)
account_id = local.parsed_arn.account
region = local.parsed_arn.region
# 从组件构建ARN
custom_arn = provider::aws::arn_build({
partition = "aws"
service = "s3"
region = ""
account = ""
resource = "my-bucket/my-key"
})
}
# Google Cloud提供者函数(v5.23+)
locals {
# 从区域提取区域
region = provider::google::region_from_zone(var.zone) # "us-west1-a" → "us-west1"
}
# Kubernetes提供者函数(v2.28+)
locals {
# 将HCL编码为Kubernetes清单YAML
manifest_yaml = provider::kubernetes::manifest_encode(local.deployment_config)
}
临时资源(Terraform 1.10+)
临时资源提供临时值,这些值从不在状态或计划文件中持久化。对于安全处理机密至关重要。
# 生成一个永不接触状态的密码
ephemeral "random_password" "db_password" {
length = 16
special = true
override_special = "!#$%&*()-_=+[]{}<>:?"
}
# 从AWS Secrets Manager临时获取机密
ephemeral "aws_secretsmanager_secret_version" "api_key" {
secret_id = aws_secretsmanager_secret.api_key.id
}
# 临时变量(声明为ephemeral = true)
variable "temporary_token" {
type = string
ephemeral = true # 值不会存储在状态中
}
# 临时输出
output "session_token" {
value = ephemeral.aws_secretsmanager_secret_version.api_key.secret_string
ephemeral = true # 不会存储在状态中
}
只写参数(Terraform 1.11+)
只写参数接受临时值,并且永远不会持久化。它们使用_wo后缀,并需要版本属性。
# 安全处理数据库密码
ephemeral "random_password" "db_password" {
length = 16
}
resource "aws_db_instance" "main" {
identifier = "mydb"
instance_class = "db.t3.micro"
allocated_storage = 20
engine = "postgres"
username = "admin"
# 只写密码 - 永远不会存储在状态中!
password_wo = ephemeral.random_password.db_password.result
password_wo_version = 1 # 增加以触发密码轮换
skip_final_snapshot = true
}
# Secrets Manager使用只写
resource "aws_secretsmanager_secret_version" "db_password" {
secret_id = aws_secretsmanager_secret.db_password.id
# 只写机密字符串
secret_string_wo = ephemeral.random_password.db_password.result
secret_string_wo_version = 1
}
增强型变量验证(Terraform 1.9+)
验证条件现在可以引用其他变量、数据源和局部值。
# 在验证中引用数据源
data "aws_ec2_instance_type_offerings" "available" {
filter {
name = "location"
values = [var.availability_zone]
}
}
variable "instance_type" {
type = string
description = "EC2实例类型"
validation {
# NEW: 可以引用数据源
condition = contains(
data.aws_ec2_instance_type_offerings.available.instance_types,
var.instance_type
)
error_message = "实例类型${var.instance_type}在选定的AZ中不可用。"
}
}
# 跨变量验证
variable "min_instances" {
type = number
default = 1
}
variable "max_instances" {
type = number
default = 10
validation {
# NEW: 可以引用其他变量
condition = var.max_instances >= var.min_instances
error_message = "max_instances必须>= min_instances"
}
}
S3本机状态锁定(Terraform 1.11+)
S3现在支持无需DynamoDB的本机状态锁定。
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "project/terraform.tfstate"
region = "us-east-1"
encrypt = true
# NEW: S3本机锁定(Terraform 1.11+)
use_lockfile = true
# DEPRECATED: DynamoDB锁定(仍然有效但不再需要)
# dynamodb_table = "terraform-locks"
}
}
导入块(Terraform 1.5+)
无需命令行操作即可声明性地导入资源。
# 声明性导入现有资源
import {
to = aws_instance.web
id = "i-1234567890abcdef0"
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
# ...配置必须与现有资源匹配
}
# 使用for_each导入
import {
for_each = var.existing_bucket_names
to = aws_s3_bucket.imported[each.key]
id = each.value
}
移动和移除块
在不销毁它们的情况下安全地重构资源。
# 重命名资源
moved {
from = aws_instance.old_name
to = aws_instance.new_name
}
# 移动到模块
moved {
from = aws_vpc.main
to = module.networking.aws_vpc.main
}
# 跨类型重构(1.8+)
moved {
from = null_resource.example
to = terraform_data.example
}
# 从不在状态中移除资源(1.7+)
removed {
from = aws_instance.legacy
lifecycle {
destroy = false # 保留实际资源,只从状态中移除
}
}
使用for_each的导入块(Terraform 1.12+)
使用for_each元参数导入多个资源。
# 使用映射导入多个S3桶
locals {
buckets = {
"staging" = "bucket1"
"uat" = "bucket2"
"prod" = "bucket3"
}
}
import {
for_each = local.buckets
to = aws_s3_bucket.this[each.key]
id = each.value
}
resource "aws_s3_bucket" "this" {
for_each = local.buckets
}
# 跨模块实例使用对象列表导入
locals {
module_buckets = [
{ group = "one", key = "bucket1", id = "one_1" },
{ group = "one", key = "bucket2", id = "one_2" },
{ group = "two", key = "bucket1", id = "two_1" },
]
}
import {
for_each = local.module_buckets
id = each.value.id
to = module.group[each.value.group].aws_s3_bucket.this[each.value.key]
}
动作块(Terraform 1.14+)
动作使提供者定义的操作超出了标准的CRUD模型。用于操作如Lambda调用、缓存失效或数据库备份。
# 调用Lambda函数(示例语法)
action "aws_lambda_invoke" "process_data" {
function_name = aws_lambda_function.processor.function_name
payload = jsonencode({ action = "process" })
}
# 创建CloudFront失效
action "aws_cloudfront_create_invalidation" "invalidate_cache" {
distribution_id = aws_cloudfront_distribution.main.id
paths = ["/*"]
}
# 动作支持for_each
action "aws_lambda_invoke" "batch_process" {
for_each = toset(["task1", "task2", "task3"])
function_name = aws_lambda_function.processor.function_name
payload = jsonencode({ task = each.value })
}
通过生命周期触发动作:
使用资源的生命周期块中的action_trigger自动调用动作:
resource "aws_lambda_function" "example" {
function_name = "my-function"
# ...其他配置...
lifecycle {
action_trigger {
events = [after_create, after_update]
actions = [action.aws_lambda_invoke.process_data]
}
}
}
action "aws_lambda_invoke" "process_data" {
function_name = aws_lambda_function.example.function_name
payload = jsonencode({ action = "initialize" })
}
手动调用:
动作也可以通过CLI手动调用:
terraform apply -invoke action.aws_lambda_invoke.process_data
列表资源和查询命令(Terraform 1.14+)
使用.tfquery.hcl文件和terraform query命令查询和过滤现有基础设施。
# my-resources.tfquery.hcl
# 定义要查询现有基础设施的列表资源
list "aws_instance" "web_servers" {
filter {
name = "tag:Environment"
values = [var.environment]
}
include_resource = true # 包括完整的资源详细信息
}
list "aws_s3_bucket" "data_buckets" {
filter {
name = "tag:Purpose"
values = ["data-storage"]
}
}
# 查询基础设施并输出结果
terraform query
# 从查询结果生成导入配置
terraform query -generate-config-out="import_config.tf"
# 以JSON格式输出
terraform query -json
# 与变量一起使用
terraform query -var 'environment=prod'
先决条件和后置条件(Terraform 1.5+)
在资源生命周期中添加自定义验证。
resource "aws_instance" "example" {
instance_type = "t3.micro"
ami = data.aws_ami.example.id
lifecycle {
# 创建前的检查
precondition {
condition = data.aws_ami.example.architecture == "x86_64"
error_message = "选定的AMI必须是x86_64架构。"
}
# 创建后的验证
postcondition {
condition = self.public_dns != ""
error_message = "EC2实例必须在启用了公共DNS主机名的VPC中。"
}
}
}
# 输出上的先决条件
output "web_url" {
value = "https://${aws_instance.web.public_dns}"
precondition {
condition = aws_instance.web.public_dns != ""
error_message = "实例必须具有公共DNS名称。"
}
}
资源
references/
references/目录包含详细文档供参考:
terraform_best_practices.md- 综合最佳实践指南common_patterns.md- 常见Terraform模式和示例provider_examples.md- 流行提供者的示例配置
加载参考时,请使用Read工具:
Read(file_path: ".claude/skills/terraform-generator/references/[filename].md")
assets/
assets/目录包含模板文件:
minimal-project/- 最小Terraform项目模板aws-web-app/- AWS Web应用程序基础设施模板multi-env/- 多环境配置模板
模板可以复制并根据用户的特定需求进行自定义。
注释
- 生成后始终运行devops-skills:terraform-validator
- 网络搜索对于自定义提供者/模块至关重要
- 在配置中遵循最少惊讶原则
- 使配置易于阅读和维护
- 包括有帮助的注释和文档
- 如有帮助,请在terraform.tfvars中生成现实示例