CDKTF C#跨栈引用报Unable to Find remote state问题求助
问题现象
接触C#与Terraform CDKTF时间不长,对生成的云环境栈执行plan操作时执行失败,初步定位问题和不同栈之间的资源跨引用有关,暂未找到有效修复方案。
按资源职责拆分独立TerraformStack,存储账户栈StorageAccounts代码定义如下:
internal class StorageAccounts : TerraformStack { internal readonly StorageAccount _storageAccount; internal readonly StorageShare _storageShare; /// <summary> /// The StorageAccounts class contains all the definitions of the Azure resources which are directly related to StorageAccounts /// </summary> /// <param name="scope">an object of class Construct</param> /// <param name="id">a string identifier</param> /// <param name="nameGenerator">an object of class NameGenerator</param> /// <param name="networking">an object of class Networking</param> /// <param name="resourceGroup">an object of class ResourceGroups</param> internal StorageAccounts(Construct scope, string id, NameGenerator nameGenerator, ResourceGroups resourceGroup ) : base(scope, id) { string[] _ips = new string[] { "111.111.111.000", "111.111.111.001" }; AzurermProvider azurermProvider = new(this, "AzureRm", new AzurermProviderConfig { Features = new AzurermProviderFeatures(), }); StorageAccount storageAccount = new StorageAccount(this, "azurerm_storage_account", new StorageAccountConfig { Name = nameGenerator.GetResNames()["Storage"], ResourceGroupName = resourceGroup._resourceGroup.Name, Location = nameGenerator._region[1], AccountTier = "Standard", AccountKind = "StorageV2", AccountReplicationType = "RAGRS", AllowBlobPublicAccess = true, NetworkRules = new StorageAccountNetworkRules { DefaultAction = "Deny", VirtualNetworkSubnetIds = new string[] { "test" }, IpRules = _ips } }); StorageShare storageShare = new StorageShare(this, "azurerm_storage_share", new StorageShareConfig { Name = "authtickets", StorageAccountName = storageAccount.Name, Quota = 5 }); _storageAccount = storageAccount; _storageShare = storageShare; } }
设计逻辑为StorageAccounts类构造函数额外接收ResourceGroups类实例,用于获取所需的资源组名称属性。通过如下代码完成所有栈的合成,原逻辑认为直接传入栈实例即可自动完成跨栈属性的正确引用:
internal static void Synthesise(NameGenerator nameGen) { HashiCorp.Cdktf.App app = new(); ResourceGroups resourceGroup = new(app, "ResourceGroup", nameGen); StorageAccounts storageAccounts = new(app, "Storage", nameGen, resourceGroup); Networking networking = new(app, "Network", nameGen, resourceGroup, storageAccounts); Kubernetes kubernetes = new(app, "Kubernetes", nameGen, networking, resourceGroup); app.Synth(); }
执行Synth后生成的JSON配置内容符合预期,资源命名、属性值均正确;单独对ResourceGroups栈执行terraform init、terraform plan均可成功完成。但尝试对StorageAccounts栈执行初始化与计划操作时,抛出如下错误:
data.terraform_remote_state.Storage_crossstackreferenceinputResourceGroup_C0FA14C2:
Reading...
data.terraform_remote_state.Storage_crossstackreferenceinputResourceGroup_C0FA14C2:
Still reading... [10s elapsed]
╷
│ Error: Unable to find remote state
│
│ with data.terraform_remote_state.Storage_crossstackreferenceinputResourceGroup_C0FA14C2,
│ on cdk.tf.json line 21, in data.terraform_remote_state.Storage_crossstackreferenceinputResourceGroup_C0FA14C2:
│ 21: "workspace": "${terraform.workspace}"
│
│ No stored state was found for the given workspace in the given backend.
查阅Terraform官方文档寻找修复方案时,多数示例基于AWS、HCL、TypeScript实现,难以适配当前C#开发场景;目前针对C#的Remote Backend、Remote State相关参考资料极少,配置逻辑理解成本高。
根因分析
CDKTF跨栈引用的默认实现逻辑为:当Stack A直接引用Stack B的资源属性时,CDKTF会自动在Stack A中添加terraform_remote_state数据源,从配置的后端拉取Stack B的状态文件读取对应属性值。
报错核心原因是被引用的ResourceGroups栈仅完成了本地init/plan操作,从未执行apply将状态推送到配置的远程后端;或是未给所有栈配置统一的远程后端,使用默认本地后端时路径不匹配,导致跨栈读取时找不到对应状态文件。
修复方案
生产环境标准方案
- 首先为所有
TerraformStack配置统一的Azure Blob Storage远程后端(适配当前Azure云场景),弃用默认本地后端,避免本地路径不一致导致跨栈状态读取失败。 - 严格按照栈依赖顺序执行部署:
- 第一步进入
ResourceGroups栈目录,依次执行terraform init、terraform plan、terraform apply,等待资源组部署完成、状态成功推送到远程后端 - 第二步进入
StorageAccounts栈目录执行init/plan/apply,此时remote_state数据源可正常读取ResourceGroups栈的已存储状态 - 后续按照
Networking->Kubernetes的依赖顺序依次部署即可
- 第一步进入
- 现有代码中传入栈实例引用属性的写法无需修改,CDKTF会自动处理跨栈输出与
remote_state的配置映射。
本地调试临时方案
本地开发调试阶段如果不想提前部署依赖栈,可以显式关闭跨栈远程状态引用,将跨栈属性转换为固定Terraform变量传递。该方案会丢失栈之间的隐式依赖关联,禁止在生产环境使用。
内容的提问来源于stack exchange,提问作者CCG

