

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Terraform을 사용하여 Amazon Redshift SQL 쿼리 실행
<a name="execute-redshift-sql-queries-using-terraform"></a>

*Sylvia Qi 및 Aditya Ambati, Amazon Web Services*

## 요약
<a name="execute-redshift-sql-queries-using-terraform-summary"></a>

Amazon Redshift의 배포 및 관리에 코드형 인프라(IaC)를 사용하는 것은 DevOps 내에서 널리 사용되는 관행입니다. IaC는 클러스터, 스냅샷 및 파라미터 그룹과 같은 다양한 Amazon Redshift 리소스의 배포 및 구성을 용이하게 합니다. 그러나 IaC는 테이블, 스키마, 뷰 및 저장 프로시저와 같은 데이터베이스 리소스의 관리로 확장되지 않습니다. 이러한 데이터베이스 요소는 SQL 쿼리를 통해 관리되며 IaC 도구에서 직접 지원되지 않습니다. 이러한 리소스를 관리하기 위한 솔루션과 도구가 있지만 기술 스택에 추가 도구를 도입하지 않는 것이 좋습니다.

이 패턴은 Terraform을 사용하여 테이블, 스키마, 뷰 및 저장 프로시저를 포함한 Amazon Redshift 데이터베이스 리소스를 배포하는 방법론을 간략하게 설명합니다. 패턴은 두 가지 유형의 SQL 쿼리를 구분합니다.
+ **반복할 수 없는 쿼리** - 이러한 쿼리는 초기 Amazon Redshift 배포 중에 한 번 실행되어 필수 데이터베이스 구성 요소를 설정합니다.
+ **반복 가능한 쿼리** - 이러한 쿼리는 변경할 수 없으며 데이터베이스에 영향을 주지 않고 다시 실행할 수 있습니다. 이 솔루션은 Terraform을 사용하여 반복 가능한 쿼리의 변경 사항을 모니터링하고 그에 따라 적용합니다.

자세한 내용은 [추가 정보의](#execute-redshift-sql-queries-using-terraform-additional) *솔루션 안내서*를 참조하세요.

## 사전 조건 및 제한 사항
<a name="execute-redshift-sql-queries-using-terraform-prereqs"></a>

**사전 조건 **

가 활성화되어 AWS 계정 있어야 하며 배포 시스템에 다음을 설치해야 합니다.
+ [AWS Command Line Interface](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) (AWS CLI)
+ Amazon Redshift 읽기/쓰기 권한으로 구성된 [AWS CLI 프로필](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html) 
+ Terraform 버전 1.6.2 이상
+ [Python3](https://www.python.org/downloads/)
+ [Boto3](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)

**제한 사항 **
+ Terraform은 클러스터 생성 중에 하나의 데이터베이스만 생성할 수 있으므로이 솔루션은 단일 Amazon Redshift 데이터베이스를 지원합니다.
+ 이 패턴에는 반복 가능한 쿼리를 적용하기 전에 변경 사항을 검증하는 테스트가 포함되지 않습니다. 신뢰성 향상을 위해 이러한 테스트를 통합하는 것이 좋습니다.
+ 솔루션을 설명하기 위해이 패턴은 로컬 Terraform 상태 `redshift.tf` 파일을 사용하는 샘플 파일을 제공합니다. 그러나 프로덕션 환경의 경우 향상된 안정성과 협업을 위해 잠금 메커니즘이 있는 원격 상태 파일을 사용하는 것이 좋습니다.
+ 일부 AWS 서비스 는 전혀 사용할 수 없습니다 AWS 리전. 리전 가용성은 [리전별AWS 서비스](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services/) 섹션을 참조하세요. 구체적인 엔드포인트는 [서비스 엔드포인트 및 할당량](https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html)을 참조하고 서비스 링크를 선택합니다.

**제품 버전**

이 솔루션은 [Amazon Redshift 패치 179](https://docs.aws.amazon.com/redshift/latest/mgmt/cluster-versions.html#cluster-version-179)에서 개발 및 테스트되었습니다.

**코드 리포지토리**

이 패턴의 코드는 GitHub [amazon-redshift-sql-deploy-terraform](https://github.com/aws-samples/amazon-redshift-sql-deploy-terraform) 리포지토리에서 사용할 수 있습니다.

## 아키텍처
<a name="execute-redshift-sql-queries-using-terraform-architecture"></a>

다음 다이어그램은 Terraform이 반복 불가능한 SQL 쿼리와 반복 가능한 SQL 쿼리를 모두 처리하여 Amazon Redshift 데이터베이스 리소스를 관리하는 방법을 보여줍니다.

![\[Terraform이 SQL 쿼리를 사용하여 Amazon Redshift 데이터베이스 리소스를 관리하는 프로세스입니다.\]](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/patterns/images/pattern-img/0f4467ac-761b-4b6b-a32f-e18a2ca2245d/images/3b6ff9e8-e3d1-48ed-9fa1-4b14f7d3d65b.png)


이 다이어그램은 다음 단계를 보여 줍니다.

1. Terraform은 초기 Amazon Redshift 클러스터 배포 중에 반복할 수 없는 SQL 쿼리를 적용합니다.

1. 개발자는 반복 가능한 SQL 쿼리에 변경 사항을 커밋합니다.

1. Terraform은 반복 가능한 SQL 쿼리의 변경 사항을 모니터링합니다.

1. Terraform은 반복 가능한 SQL 쿼리를 Amazon Redshift 데이터베이스에 적용합니다.

이 패턴에서 제공하는 솔루션은 [Amazon Redshift용 Terraform 모듈을](https://registry.terraform.io/modules/terraform-aws-modules/redshift/aws/latest) 기반으로 구축되었습니다. Terraform 모듈은 Amazon Redshift 클러스터와 데이터베이스를 프로비저닝합니다. 모듈을 개선하기 위해 Amazon Redshift [ExecuteStatement](https://docs.aws.amazon.com/redshift-data/latest/APIReference/API_ExecuteStatement.html) API 작업을 사용하여 SQL 쿼리를 실행하기 위해 사용자 지정 Python 스크립트를 간접적으로 호출하는 `terraform_data` 리소스를 사용했습니다. 따라서 모듈은 다음을 수행할 수 있습니다.
+ 데이터베이스를 프로비저닝한 후 SQL 쿼리를 사용하여 원하는 수의 데이터베이스 리소스를 배포합니다.
+ 반복 가능한 SQL 쿼리의 변경 사항을 지속적으로 모니터링하고 Terraform을 사용하여 해당 변경 사항을 적용합니다.

자세한 내용은 [추가 정보의](#execute-redshift-sql-queries-using-terraform-additional) *솔루션 안내서*를 참조하세요.

## 도구
<a name="execute-redshift-sql-queries-using-terraform-tools"></a>

**AWS 서비스**
+ [Amazon Redshift](https://docs.aws.amazon.com/redshift/latest/mgmt/welcome.html)는의 완전관리형 페타바이트 규모의 데이터 웨어하우스 서비스입니다 AWS 클라우드.

**기타 도구**
+ [Terraform](https://www.terraform.io/)은 HashiCorp의 코드형 인프라(IaC) 도구로, 클라우드 및 온프레미스 리소스를 생성하고 관리하는 데 도움이 됩니다.
+ [Python](https://www.python.org/)은이 패턴에서 SQL 쿼리를 실행하는 데 사용되는 범용 프로그래밍 언어입니다.

## 모범 사례
<a name="execute-redshift-sql-queries-using-terraform-best-practices"></a>
+ [Amazon Redshift 모범 사례](https://docs.aws.amazon.com/redshift/latest/dg/best-practices.html)
+ [Amazon Redshift 데이터 API를 사용하여 Amazon Redshift 클러스터와 상호 작용](https://aws.amazon.com/blogs/big-data/using-the-amazon-redshift-data-api-to-interact-with-amazon-redshift-clusters/)

## 에픽
<a name="execute-redshift-sql-queries-using-terraform-epics"></a>

### Terraform을 사용하여 솔루션을 배포
<a name="deploy-the-solution-using-terraform"></a>


| 작업 | 설명 | 필요한 기술 | 
| --- | --- | --- | 
| **리포지토리를 복제합니다.** | Amazon Redshift 클러스터 프로비저닝을 위한 Terraform 코드가 포함된 Git 리포지토리를 복제하려면 다음 명령을 사용합니다.<pre>git clone https://github.com/aws-samples/amazon-redshift-sql-deploy-terraform.git</pre> | DevOps 엔지니어 | 
| **Terraform 변수를 업데이트합니다.** | 특정 요구 사항에 따라 Amazon Redshift 클러스터 배포를 사용자 지정하려면 `terraform.tfvars` 파일에서 다음 파라미터를 업데이트합니다.<pre>region                    = "<AWS_REGION>"<br />cluster_identifier        = "<REDSHIFT_CLUSTER_IDENTIFIER>"<br />node_type                 = "<REDSHIFT_NODE_TYPE>"<br />number_of_nodes           = "<REDSHIFT_NODE_COUNT>"<br />database_name             = "<REDSHIFT_DB_NAME>"<br />subnet_ids                = "<REDSHIFT_SUBNET_IDS>"<br />vpc_security_group_ids    = "<REDSHIFT_SECURITY_GROUP_IDS>"<br />run_nonrepeatable_queries = true<br />run_repeatable_queries    = true<br />sql_path_bootstrap        = "<BOOTSTRAP_SQLS_PATH>"<br />sql_path_nonrepeatable    = "<NON-REPEATABLE_SQLS_PATH>"<br />sql_path_repeatable       = "<REPEATABLE_SQLS_PATH>"<br />sql_path_finalize         = "<FINALIZE_SQLS_PATH>"<br />create_random_password    = false<br />master_username           = "<REDSHIFT_MASTER_USERNAME>"</pre> | DevOps 엔지니어 | 
| Terraform을 사용하여 리소스를 배포합니다. | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/patterns/execute-redshift-sql-queries-using-terraform.html) | DevOps 엔지니어 | 
| (선택 사항) 추가 SQL 쿼리를 실행합니다. | 샘플 리포지토리는 데모용으로 여러 SQL 쿼리를 제공합니다. 자체 SQL 쿼리를 실행하려면 다음 폴더에 추가합니다.`/bootstrap` `/nonrepeatable` `/repeatable` `/finalize` |  | 

### 실행 상태를 모니터링합니다.
<a name="monitor-the-execution-of-sql-statements"></a>


| 작업 | 설명 | 필요한 기술 | 
| --- | --- | --- | 
| SQL 문의 배포를 모니터링합니다. | Amazon Redshift 클러스터에 대한 SQL 실행 결과를 모니터링할 수 있습니다. 실패 및 성공적인 SQL 실행을 보여주는 출력의 예는 [추가 정보의](#execute-redshift-sql-queries-using-terraform-additional) *예시 SQL 문*을 참조하세요. | DBA, DevOps 엔지니어 | 
| 리소스를 정리합니다. | 모든 AWS 리소스를 배포하려면 다음 명령을 실행합니다.<pre>terraform destroy</pre> | DevOps 엔지니어 | 

### 결과 검증
<a name="validate-the-results"></a>


| 작업 | 설명 | 필요한 기술 | 
| --- | --- | --- | 
| Amazon Redshift 클러스터 검증 | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/prescriptive-guidance/latest/patterns/execute-redshift-sql-queries-using-terraform.html) | DBA, AWS DevOps | 

## 관련 리소스
<a name="execute-redshift-sql-queries-using-terraform-resources"></a>

**AWS 설명서**
+ [Amazon Redshift 프로비저닝된 클러스터](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html)
+ [Amazon Redshift Data API 문제 해결](https://docs.aws.amazon.com/redshift/latest/mgmt/data-api-troubleshooting.html)

**기타 리소스**
+ [명령: 적용](https://developer.hashicorp.com/terraform/cli/commands/apply)(Terraform 설명서)

## 추가 정보
<a name="execute-redshift-sql-queries-using-terraform-additional"></a>

**솔루션 연습**

솔루션을 사용하려면 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은 다음 순서로 쿼리를 실행합니다.

1. `/bootstrap`

1. `/nonrepeatable`

1. `/repeatable`

1. `/finalize`

`/repeatable`, `/udf` 및 `/table` 폴더에는 `/view`, 및 하위 폴더가 들어 있습니다. 이러한 하위 폴더는 Terraform이 SQL 쿼리를 실행하는 순서를 나타냅니다.

SQL 쿼리를 실행하는 Python 스크립트는 입니다`sql-queries.py`. 먼저 스크립트는 `sql_path_bootstrap` 파라미터와 같은 특정 소스 디렉터리의 모든 파일과 하위 폴더를 읽습니다. 그런 다음 스크립트는 Amazon Redshift [ExecuteStatement](https://docs.aws.amazon.com/redshift-data/latest/APIReference/API_ExecuteStatement.html) API 작업을 직접적으로 호출하여 쿼리를 실행합니다. 파일에 SQL 쿼리가 하나 이상 있을 수 있습니다. 다음 코드 조각은 Amazon Redshift 클러스터에 대해 파일에 저장된 SQL 문을 실행하는 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\$1data](https://developer.hashicorp.com/terraform/language/resources/terraform-data) 리소스를 생성합니다. , `/bootstrap`, `/nonrepeatable` `/repeatable`및 네 개의 폴더 각각에 대한 `terraform_data` 리소스가 있습니다`/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` 다시 실행할 수 있습니다. 예를 들어 다음 명령은 Terraform 상태에서 `run_bootstrap_queries` 리소스를 제거합니다.

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

다음 코드 예에서는 `run_repeatable_queries` 리소스가 [sha256 해시](https://developer.hashicorp.com/terraform/language/functions/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]
```

다음 출력은 성공적인 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]
```