升级 Terraform 后出现的语法错误

93次阅读
没有评论

问题描述

在将 Terraform 从版本 v0.11 升级到 v0.12 之后,遇到了一些错误。特别是在代码块中出现的问题,其中涉及到 secrets 和 mounts 部分。用户提供了 v0.11 和 v0.12 的代码,以及相应的错误信息。

解决方案

请注意以下操作可能会涉及版本差异,请在操作前备份相关文件。

错误1:不支持的参数语法

错误信息示例:

Error: Unsupported argument on main.tf line 8, in resource "docker_service" "mysql-service":
  8:       secrets = {An argument named "secrets" is not expected here. Did you mean to define a block of type "secrets"?

这个错误是因为在 Terraform 0.12 中,参数 secrets 被定义为嵌套块的语法,而不是参数的语法。

为了解决这个问题,你需要使用块的语法来定义这些嵌套对象。例如:

secrets {
  secret_id   = docker_secret.mysql_root_password.id
  secret_name = docker_secret.mysql_root_password.name
  file_name   = "/run/secrets/${docker_secret.mysql_root_password.name}"
}
secrets {
  secret_id   = docker_secret.mysql_db_password.id
  secret_name = docker_secret.mysql_db_password.name
  file_name   = "/run/secrets/${docker_secret.mysql_db_password.name}"
}

同样的语法也适用于 mounts 部分:

mounts {
  target = "/var/lib/mysql"
  source = docker_volume.mysql_data_volume.name
  type   = "volume"
}

错误2:不正确的属性值类型

错误信息示例:

Error: Incorrect attribute value type on main.tf line 34, in resource "docker_service" "mysql-service":
  34:     networks = "docker_network.private_overlay_network.name"
Inappropriate value for attribute "networks": set of string required.

这个错误是因为 networks 参数需要一个字符串集合,而你提供的是一个单独的字符串。为了解决这个问题,你需要将引用表达式放在括号中,以构造一个单元素的序列,然后将这个序列转换为集合。

例如,将这行代码:

networks = docker_network.private_overlay_network.name

改为:

networks = [docker_network.private_overlay_network.name]

其他建议

另外,根据你提供的信息,你在代码中使用了引号来包裹变量引用,这可能会导致 Terraform 将其解析为字符串而不是引用。在需要使用变量值的地方,不需要使用引号。例如,将这行代码:

image = "docker_image.mysql_image.name"

改为:

image = docker_image.mysql_image.name

更新变量引用

你提到你已经有一个 secrets.tfvariables.tf 文件来存放这些变量。在主配置文件 main.tf 中引用这些变量时,你可以使用变量引用语法。例如,将这行代码:

secrets {
  secret_id   = "docker_secret.mysql_db_password.id"
  secret_name = "docker_secret.mysql_db_password.name"
  file_name   = "/run/secrets/${docker_secret.mysql_db_password.name}"
}

改为:

secrets {
  secret_id   = var.mysql_db_password_secret_id
  secret_name = var.mysql_db_password_secret_name
  file_name   = "/run/secrets/${var.mysql_db_password_secret_name}"
}

同样的方法也适用于其他变量的引用。

使用 locals 块

为了更好地管理变量,你可以使用 locals 块来定义一些常见的值,以便在主配置文件中引用。例如:

locals {
  mysql_db_password_secret_id   = "docker_secret.mysql_db_password.id"
  mysql_db_password_secret_name = "docker_secret.mysql_db_password.name"
  mysql_root_password_secret_id   = "docker_secret.mysql_root_password.id"
  mysql_root_password_secret_name = "docker_secret.mysql_root_password.name"
}

然后在主配置文件中可以这样引用:

secrets {
  secret_id   = local.mysql_db_password_secret_id
  secret_name = local.mysql_db_password_secret_name
  file_name   = "/run/secrets/${local.mysql_db_password_secret_name}"
}

错误排查

如果你遇到类似 Error response from daemon: rpc error: code = InvalidArgument desc = malformed secret reference 的 Docker 错误,这可能不是 Terraform 的问题。请确保你的 Docker 容器正常工作,并且相关的 Docker Secret 配置正确。

总结

升级 Terraform 到版本 v0.12 后,代码的语法可能会发生变化。主要的改变在于参数使用块的语法,需要注意正确引用变量并避免额外的引号。另外,注意 Docker 配置和 Docker Secret 的正确设置,以确保容器正常工作。通过逐步检查和调整代码,你应该能够解决这些问题。

正文完