本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 Terraform 执行 Amazon Redshift SQL 查询
Sylvia Qi 和 Aditya Ambati, Amazon Web Services
Summary
使用基础设施即代码 (IaC) 来部署和管理 Amazon Redshift 是一种普遍的做法。 DevOpsIaC 有助于部署和配置各种 Amazon Redshift 资源,例如集群、快照和参数组。但是,IaC 并未扩展到管理数据库资源,例如表、架构、视图和存储过程。这些数据库元素通过 SQL 查询进行管理,并且不受 IaC 工具支持,无法直接进行处理。尽管有用于管理这些资源的解决方案和工具,但您可能不希望在技术堆栈中引入其他工具。
此模式概述了一种使用 Terraform 部署 Amazon Redshift 数据库资源(包括表、架构、视图和存储过程)的方法。该模式区分了两种类型的 SQL 查询:
不可重复查询 – 这些查询在最初的 Amazon Redshift 部署期间执行一次,以建立基本的数据库组件。
可重复查询 – 这些查询是不可变的,可以在不影响数据库的情况下重新运行。该解决方案使用 Terraform 来监控可重复查询中的变化并相应地应用它们。
有关更多详细信息,请参阅其他信息中的解决方案演练。
先决条件和限制
先决条件
您必须激活 AWS 账户 并在部署计算机上安装以下内容:
AWS Command Line Interface (AWS CLI)
AWS CLI 配置了亚马逊 Redshi read/write ft 权限的个人资料
Terraform
版本 1.6.2 或更高版本
限制
此解决方案支持单个 Amazon Redshift 数据库,因为 Terraform 只允许在创建集群期间创建一个数据库。
此模式不包括在应用对可重复查询的更改之前验证该更改的测试。我们建议您采用此类测试以增强可靠性。
为了说明该解决方案,此模式提供了一个使用本地 Terraform 状态文件的示例
redshift.tf文件。但是,对于生产环境,我们强烈建议您使用带有锁定机制的远程状态文件,以增强稳定性和协作性。有些 AWS 服务 并非全部可用 AWS 区域。有关区域可用性,请参阅按区域划分的AWS 服务
。有关特定端点,请参阅服务端点和配额,然后选择相应服务的链接。
产品版本
该解决方案是在 Amazon Redshift 补丁 179 上开发和测试的。
代码存储库
此模式的代码可在 GitHub amazon-redshift-sql-deploy-terraform
架构
下图阐明了 Terraform 如何通过处理不可重复和可重复的 SQL 查询来管理 Amazon Redshift 数据库资源。

图中显示以下步骤:
在最初的 Amazon Redshift 集群部署期间,Terraform 会应用不可重复的 SQL 查询。
开发人员提交对可重复的 SQL 查询的更改。
Terraform 监控可重复的 SQL 查询中的变化。
Terraform 将可重复的 SQL 查询应用到 Amazon Redshift 数据库。
此模式提供的解决方案是基于适用于 Amazon Redshift 的 Terraform 模块terraform_data资源,这些资源调用自定义 Python 脚本来使用 Amazon ExecuteStatementRedshift API 操作执行 SQL 查询。因此,该模块可以执行以下操作:
预调配数据库后,使用 SQL 查询部署任意数量的数据库资源。
持续监控可重复的 SQL 查询中的更改,并使用 Terraform 应用这些更改。
有关更多详细信息,请参阅其他信息中的解决方案演练。
工具
AWS 服务
Amazon Redshift 是 AWS Cloud中的一项完全托管式 PB 级数据仓库服务。
其他工具
最佳实践
操作说明
| Task | 说明 | 所需技能 |
|---|---|---|
克隆存储库。 | 要克隆包含用于预调配 Amazon Redshift 集群的 Terraform 代码的 Git 存储库,请使用以下命令。
| DevOps 工程师 |
更新 Terraform 变量。 | 要根据您的特定要求自定义 Amazon Redshift 集群部署,请更新
| DevOps 工程师 |
使用 Terraform 部署资源。 |
| DevOps 工程师 |
(可选)执行其他 SQL 查询。 | 示例存储库提供了几个 SQL 查询用于演示。要执行您自己的 SQL 查询,请将其添加到以下文件夹:
|
| Task | 说明 | 所需技能 |
|---|---|---|
监控 SQL 语句的部署。 | 您可以监控 Amazon Redshift 集群的 SQL 执行结果。有关显示 SQL 执行失败和成功执行的输出示例,请参阅其他信息中的 SQL 语句示例。 | 数据库管理员、工程师 DevOps |
清理资源。 | 要删除 Terraform 部署的所有资源,请运行以下命令。
| DevOps 工程师 |
| Task | 说明 | 所需技能 |
|---|---|---|
验证 Amazon Redshift 集群中的数据。 |
| DBA、AWS DevOps |
相关资源
AWS 文档
其他资源
命令:应用
(Terraform 文档)
附加信息
解决方案演练
要使用该解决方案,您必须以特定的方式组织您的 Amazon Redshift SQL 查询。所有 SQL 查询都必须存储在以 .sql 为扩展名的文件中。
在此模式提供的代码示例中,SQL 查询按以下文件夹结构进行组织。您可以修改代码(sql-queries.tf 和 sql-queries.py),使其适用于适合您独特使用案例的任何结构。
/bootstrap |- Any # of files |- Any # of sub-folders /nonrepeatable |- Any # of files |- Any # of sub-folders /repeatable /udf |- Any # of files |- Any # of sub-folders /table |- Any # of files |- Any # of sub-folders /view |- Any # of files |- Any # of sub-folders /stored-procedure |- Any # of files |- Any # of sub-folders /finalize |- Any # of files |- Any # of sub-folders
鉴于上述文件夹结构,在 Amazon Redshift 集群部署期间,Terraform 按以下顺序执行查询:
/bootstrap/nonrepeatable/repeatable/finalize
/repeatable 文件夹包含四个子文件夹:/udf、/table、/view 和 /stored-procedure。这些子文件夹指示 Terraform 执行 SQL 查询的顺序。
执行 SQL 查询的 Python 脚本是 sql-queries.py。首先,该脚本读取特定源目录的所有文件和子文件夹,例如 sql_path_bootstrap 参数。然后,该脚本通过调用 Amazon ExecuteStatementRedshift API 操作来执行查询。一个文件中可能有一个或多个 SQL 查询。以下代码片段显示了 Python 函数,该函数针对 Amazon Redshift 集群执行存储在文件中的 SQL 语句。
def execute_sql_statement(filename, cluster_id, db_name, secret_arn, aws_region): """Execute SQL statements in a file""" redshift_client = boto3.client( 'redshift-data', region_name=aws_region) contents = get_contents_from_file(filename), response = redshift_client.execute_statement( Sql=contents[0], ClusterIdentifier=cluster_id, Database=db_name, WithEvent=True, StatementName=filename, SecretArn=secret_arn ) ...
Terraform 脚本 sql-queries.tf 创建用于调用 sql-queries.py 脚本的 terraform_dataterraform_data 资源:/bootstrap、/nonrepeatable、/repeatable、和/finalize。以下代码片段显示了在 /bootstrap 文件夹中执行 SQL 查询的 terraform_data 资源。
locals { program = "${path.module}/sql-queries.py" redshift_cluster_name = try(aws_redshift_cluster.this[0].id, null) } resource "terraform_data" "run_bootstrap_queries" { count = var.create && var.run_nonrepeatable_queries && (var.sql_path_bootstrap != "") && (var.snapshot_identifier == null) ? 1 : 0 depends_on = [aws_redshift_cluster.this[0]] provisioner "local-exec" { command = "python3 ${local.program} ${var.sql_path_bootstrap} ${local.redshift_cluster_name} ${var.database_name} ${var.redshift_secret_arn} ${local.aws_region}" } }
您可以使用以下变量控制是否运行这些查询。如果您不想在 sql_path_bootstrap、sql_path_nonrepeatable、sql_path_repeatable 或 sql_path_finalize 中运行查询 ,请将其值设置为 ""。
run_nonrepeatable_queries = true run_repeatable_queries = true sql_path_bootstrap = "src/redshift/bootstrap" sql_path_nonrepeatable = "src/redshift/nonrepeatable" sql_path_repeatable = "src/redshift/repeatable" sql_path_finalize = "src/redshift/finalize"
运行 terraform apply 时,无论脚本的结果如何,Terraform 都会考虑脚本完成后添加的 terraform_data 资源。如果某些 SQL 查询失败,而您想重新运行它们,则可以手动将该资源从 Terraform 状态中移除,然后重新运行 terraform apply。例如,以下命令将 run_bootstrap_queries 资源从 Terraform 状态中移除。
terraform state rm module.redshift.terraform_data.run_bootstrap_queries[0]
以下代码示例显示了 run_repeatable_queries 资源如何使用 sha256 哈希值repeatable文件夹中的变化。如果更新了文件夹中的任何文件,Terraform 会将整个目录标记为更新。然后,Terraform 在下一 terraform apply 期间运行目录中的查询。
resource "terraform_data" "run_repeatable_queries" { count = var.create_redshift && var.run_repeatable_queries && (var.sql_path_repeatable != "") ? 1 : 0 depends_on = [terraform_data.run_nonrepeatable_queries] # Continuously monitor and apply changes in the repeatable folder triggers_replace = { dir_sha256 = sha256(join("", [for f in fileset("${var.sql_path_repeatable}", "**") : filesha256("${var.sql_path_repeatable}/${f}")])) } provisioner "local-exec" { command = "python3 ${local.sql_queries} ${var.sql_path_repeatable} ${local.redshift_cluster_name} ${var.database_name} ${var.redshift_secret_arn}" } }
要完善代码,您可以实施一种机制,以检测并仅对 repeatable 文件夹中已更新的文件应用更改,而不是任意地将更改应用于所有文件。
SQL 语句示例
以下输出显示了 SQL 执行失败以及错误消息。
module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): Executing: ["/bin/sh" "-c" "python3 modules/redshift/sql-queries.py src/redshift/nonrepeatable testcluster-1 db1 arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXX:secret:/redshift/master_user/password-8RapGH us-east-1"] module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): ------------------------------------------------------------------- module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): src/redshift/nonrepeatable/table/admin/admin.application_family.sql module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): ------------------------------------------------------------------- module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): Status: FAILED module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): SQL execution failed. module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): Error message: ERROR: syntax error at or near ")" module.redshift.terraform_data.run_nonrepeatable_queries[0] (local-exec): Position: 244 module.redshift.terraform_data.run_nonrepeatable_queries[0]: Creation complete after 3s [id=ee50ba6c-11ae-5b64-7e2f-86fd8caa8b76]
以下为成功执行后的输出示例。
module.redshift.terraform_data.run_bootstrap_queries[0]: Provisioning with 'local-exec'... module.redshift.terraform_data.run_bootstrap_queries[0] (local-exec): Executing: ["/bin/sh" "-c" "python3 modules/redshift/sql-queries.py src/redshift/bootstrap testcluster-1 db1 arn:aws:secretsmanager:us-east-1:XXXXXXXXXXXX:secret:/redshift/master_user/password-8RapGH us-east-1"] module.redshift.terraform_data.run_bootstrap_queries[0] (local-exec): ------------------------------------------------------------------- module.redshift.terraform_data.run_bootstrap_queries[0] (local-exec): src/redshift/bootstrap/db.sql module.redshift.terraform_data.run_bootstrap_queries[0] (local-exec): ------------------------------------------------------------------- module.redshift.terraform_data.run_bootstrap_queries[0] (local-exec): Status: FINISHED module.redshift.terraform_data.run_bootstrap_queries[0] (local-exec): SQL execution successful. module.redshift.terraform_data.run_bootstrap_queries[0]: Creation complete after 2s [id=d565ef6d-be86-8afd-8e90-111e5ea4a1be]