Terraform を使用して Amazon Redshift SQL クエリを実行する - AWS 規範ガイダンス

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

Terraform を使用して Amazon Redshift SQL クエリを実行する

Amazon Web Services、Sylvia Qi、Aditya Ambati

概要

Amazon Redshift のデプロイと管理に Infrastructure as Code (IaC) を使用することは、DevOps 内での一般的なプラクティスです。IaC を使用すると、クラスター、スナップショット、パラメータグループなど、さまざまな Amazon Redshift リソースのデプロイと設定が簡単に行えます。ただし、IaC はテーブル、スキーマ、ビュー、ストアドプロシージャなどのデータベースリソースの管理までは対応していません。これらのデータベース要素は SQL クエリによって管理されるもので、IaC ツールでは直接サポートされていません。これらのリソースを管理するためのソリューションとツールがありますが、テクノロジースタックへの追加ツールの導入を回避したい場合があります。

このパターンでは、Terraform を使用してテーブル、スキーマ、ビュー、ストアドプロシージャなどの Amazon Redshift データベースリソースをデプロイする方法の概要を示します。パターンでは、2 種類の SQL クエリを区別します。

  • 再現不可能なクエリ – これらのクエリは、最初の Amazon Redshift デプロイ中に 1 回実行され、重要なデータベースコンポーネントを確立します。

  • 反復可能なクエリ – これらのクエリはイミュータブルであり、データベースに影響を与えることなく再実行できます。このソリューションは、Terraform を使用して反復可能なクエリの変更をモニタリングし、それに応じて適用します。

詳細については、「追加情報」の「ソリューションの詳細」を参照してください。

前提条件と制限

前提条件

をアクティブに AWS アカウント し、デプロイマシンに以下をインストールする必要があります。

制限事項

  • Terraform でのクラスター作成中はデータベースを 1 つしか作成できないため、このソリューションでは単一の Amazon Redshift データベースをサポートします。

  • このパターンには、反復可能なクエリへの変更を適用する前に検証するテストは含まれません。信頼性を高めるために、このようなテストを組み込むことをお勧めします。

  • このソリューションを説明するために、このパターンではローカル Terraform ステートファイルを使用するサンプル redshift.tf ファイルを用意しています。ただし、本番環境では、安定性とコラボレーションを強化するために、ロック機構を備えたリモートステートファイルを使用することを強くお勧めします。

  • 一部の AWS のサービス は では使用できません AWS リージョン。利用可能なリージョンについては、「AWS のサービス (リージョン別)」を参照してください。特定のエンドポイントについては、「Service endpoints and quotas」で、サービスのリンクを選択してご確認ください。

製品バージョン

このソリューションは、Amazon Redshift パッチ 179 で開発およびテストされています。

コードリポジトリ

このパターンのコードは、GitHub の「amazon-redshift-sql-deploy-terraform」リポジトリで入手できます。

アーキテクチャ

次の図に、Terraform が反復不可能な SQL クエリと反復不可能な SQL クエリの両方を処理することで Amazon Redshift データベースリソースを管理する方法を示します。

Terraform が SQL クエリを使用して Amazon Redshift データベースリソースを管理するプロセス。

図表に示す内容は以下のステップです。

  1. Amazon Redshift クラスターの初回デプロイ時に、Terraform が反復不可能な SQL クエリを適用します。

  2. 開発者が、反復可能な SQL クエリの変更をコミットします。

  3. Terraform が、反復可能な SQL クエリの変更をモニタリングします。

  4. Terraform が、反復可能な SQL クエリを Amazon Redshift データベースに適用します。

このパターンで提供するソリューションは、Amazon Redshift 用の Terraform モジュールに基づいて構築されています。Terraform モジュールは Amazon Redshift クラスターとデータベースをプロビジョニングします。モジュールを強化するために、ここでは terraform_data リソースを使用しています。ここで、カスタム Python スクリプトを呼び出し、Amazon Redshift ExecuteStatement API オペレーションを使用して SQL クエリを実行します。結果として、モジュールは以下を実行できます。

  • データベースのプロビジョニング後に SQL クエリを使用して、任意の数のデータベースリソースをデプロイする。

  • 反復可能な SQL クエリの変更を継続的にモニタリングし、Terraform を使用してそれらの変更を適用する。

詳細については、「追加情報」の「ソリューションの詳細」を参照してください。

ツール

AWS のサービス

  • Amazon Redshift は、フルマネージド型で、ペタバイトスケールのデータウェアハウスを提供する、 AWS クラウドのサービスです。

その他のツール

  • Terraform は HashiCorp の infrastructure as code (IaC) ツールで、クラウドとオンプレミスのリソースの作成と管理を支援します。

  • Python は、SQL クエリを実行するためにこのパターンで使用する汎用プログラミング言語です。

ベストプラクティス

エピック

タスク説明必要なスキル

リポジトリのクローンを作成します。

Amazon Redshift クラスターをプロビジョニングするための Terraform コードを含む Git リポジトリのクローンを作成するには、次のコマンドを実行します。

git clone https://github.com/aws-samples/amazon-redshift-sql-deploy-terraform.git
DevOps エンジニア

Terraform 変数を更新します。

特定の要件に従って Amazon Redshift クラスターのデプロイをカスタマイズするには、terraform.tfvars ファイル内の次のパラメータを更新します。

region = "<AWS_REGION>" cluster_identifier = "<REDSHIFT_CLUSTER_IDENTIFIER>" node_type = "<REDSHIFT_NODE_TYPE>" number_of_nodes = "<REDSHIFT_NODE_COUNT>" database_name = "<REDSHIFT_DB_NAME>" subnet_ids = "<REDSHIFT_SUBNET_IDS>" vpc_security_group_ids = "<REDSHIFT_SECURITY_GROUP_IDS>" run_nonrepeatable_queries = true run_repeatable_queries = true sql_path_bootstrap = "<BOOTSTRAP_SQLS_PATH>" sql_path_nonrepeatable = "<NON-REPEATABLE_SQLS_PATH>" sql_path_repeatable = "<REPEATABLE_SQLS_PATH>" sql_path_finalize = "<FINALIZE_SQLS_PATH>" create_random_password = false master_username = "<REDSHIFT_MASTER_USERNAME>"
DevOps エンジニア

Terraform を使用してリソースをデプロイします。

  1. デプロイプロセスを準備するには、次のコマンドを実行して、クローンされたリポジトリ内で Terraform を初期化します。

    terraform init
  2. Terraform がインフラストラクチャに適用する変更をプレビューするには、次のコマンドを実行して、実行プランを作成します。

    terraform plan -var-file terraform.tfvars
  3. Amazon Redshift クラスターと関連リソースをプロビジョニングするには、次のコマンドを実行して、Terraform 実行プランを適用します。

    terraform apply -var-file terraform.tfvars
DevOps エンジニア

(オプション) 追加の SQL クエリを実行します。

サンプルリポジトリには、デモ用の SQL クエリがいくつか用意されています。独自の SQL クエリを実行するには、それらを次のフォルダに追加します。

/bootstrap

/nonrepeatable

/repeatable

/finalize

タスク説明必要なスキル

SQL ステートメントのデプロイをモニタリングします。

Amazon Redshift クラスターに対する SQL 実行の結果をモニタリングできます。失敗した SQL 実行と成功した SQL 実行を示す出力の例については、「追加情報」の「SQL ステートメントの例」を参照してください。

DBA、DevOps エンジニア

リソースをクリーンアップします。

Terraform によってデプロイされたリソースをすべて削除するには、次のコマンドを実行します。

terraform destroy
DevOps エンジニア
タスク説明必要なスキル

Amazon Redshift クラスターのデータを検証します。

  1. にサインインし AWS マネジメントコンソール、Amazon Redshift コンソールを開きます。

  2. ナビゲーションメニューで [クラスター] を選択します。リストから関連するクラスターの名前を選択します。

  3. Amazon Redshift ドキュメントの「クエリエディタ v2 を使用してデータベースのクエリを実行する」の手順に従います。

DBA、AWS DevOps

関連リソース

AWS ドキュメント

その他のリソース

追加情報

ソリューションの詳細

このソリューションを使用するには、Amazon Redshift SQL クエリを特定の方法で配置する必要があります。すべての SQL クエリは、.sql 拡張子が付いたファイルに保存する必要があります。

このパターンで提供するコード例では、SQL クエリは次のフォルダ構造内に配置されます。独自のユースケースに適した任意の構造に対応するように、コード (sql-queries.tfsql-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 でのクエリ実行は次の順序で行われます。

  1. /bootstrap

  2. /nonrepeatable

  3. /repeatable

  4. /finalize

/repeatable フォルダには、/udf/table/view/stored-procedure の 4 つのサブフォルダがあります。これらのサブフォルダは、Terraform が SQL クエリを実行する順序を示しています。

SQL クエリを実行する Python スクリプトは sql-queries.py です。スクリプトは、まず sql_path_bootstrap パラメータなど、特定のソースディレクトリのすべてのファイルとサブフォルダを読み取ります。その次に、Amazon Redshift ExecuteStatement API オペレーションを呼び出してクエリを実行します。ファイル内に 1 つ以上の SQL クエリがある場合があります。次のコードスニペットは、ファイルに保存されている SQL ステートメントを Amazon Redshift クラスターに対して実行する Python 関数を示しています。

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_data リソースを作成します。/bootstrap/nonrepeatable,/repeatable,/finalize の 4 つのフォルダのそれぞれに 1 つの terraform_data リソースがあります。次のコードスニペットは、/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_bootstrapsql_path_nonrepeatablesql_path_repeatablesql_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 を再度実行できます。例えば、次のコマンドを実行すると、Terraform 状態から run_bootstrap_queries リソースが削除されます。

terraform state rm module.redshift.terraform_data.run_bootstrap_queries[0]

次のコード例は、run_repeatable_queries リソースが sha256 ハッシュを使用して repeatable フォルダでの変更をモニタリングする方法を示しています。フォルダ内のファイルが更新されると、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]

次の出力は、成功した SQL 実行を示しています。

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]