问题描述
在将 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.tf
和 variables.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 的正确设置,以确保容器正常工作。通过逐步检查和调整代码,你应该能够解决这些问题。