⭐ 가시다(gasida) 님이 진행하는 Terraform T101 4기 실습 스터디 게시글입니다.
책 '테라폼으로 시작하는 IaC'을 참고했습니다!
게시글 상 소스코드, 사진에서 **굵게** 혹은 '''코드쉘''' 에 대한 부분이 들어가있을수도 있습니다.
Terraform 으로 사용 가능한 Provider를 찾다가
Confluent Cloud 를 참조하는 자료가 없는 것 같아, 직접 공부하며 정리한 자료입니다.
게시글에 틀린 내용이 있을수 있습니다!
실습상 방화벽, 권한과 Network 에 대한 문제가 있을 수 있습니다. 실습시 주의가 필요합니다.
CDC
데이터베이스와 관련하여 요즘 뜨고있는 주제 중 하나는 CDC에 대한 내용입니다.
CDC는 Change-Data-Capture 의 약자로 한국말로 변경데이터캡쳐 라는 뜻입니다.
CDC가 정확히 뭘까요?
CDC는 데이터베이스 내 데이터에 대한 변경을 식별해 필요한 후속처리를 자동화하는 설계 기법이자 구조라고 합니다.
이렇게만 보면 뭔지 잘 모르겠지만, 실제 예시를 통해서 감을 잡아봅시다.
가장 일반적으로 사용하는 예제는 바로 두개의 다른 이기종 데이터베이스간 동기화입니다. 데이터베이스를 크게 2종류로 구분한다면, RDB와 NoSQL로 구분됩니다. RDB는 일반적으로 구조화된 데이터를 저장하는데 큰 장점을 보이고, NoSQL은 대용량 데이터처리와 유연한 데이터구조가 필요한경우에 적합합니다.
따라서, RDB와 NoSQL은 데이터를 저장하는 형태가 다르며, RDB 의 데이터를 NoSQL로 변환하여 적재하려는 요구사항이 있을경우 찾는것이 바로 CDC입니다(반대의 경우도 동일합니다).
이때 사용하는게 Kafka 이며, Database와 Kafka 사이에 Connector 를 사용하게됩니다.
CDC는 전체 시스템 흐름상 Database1 → Kafka → Database2 형태를 갖게되는데, Kafka 앞뒤로 Connector 가 배치됩니다.
Database1→ Source Connector → Kafka → Sink Connector → Database2 형태로 구성됩니다.
출발지 데이터베이스를 Source 로 표현하며, 출발지 데이터베이스에서 Kafka Topic 으로 전달할때 사용하는 Connector 를 Source Connector 로 지칭합니다.
도착지 데이터베이스를 Sink 로 표현하며, Kafka Topic 에서 도착지 데이터베이스로 전달할때 사용하는 Connector 를 Sink Connector 로 지칭합니다.
Debezium
CDC목적으로 가장 많이 사용하는 오픈소스로 가장 유명한 건 Debezium 입니다.
- 공식링크: https://debezium.io/
Debezium은 오픈소스로, 다양한 Connector 를 지원하고 있습니다. 지원하는 항목은 https://debezium.io/releases/ 여기에서 확인 가능합니다.
이번게시글에서는 Debezium에 대한 설명보단
Terraform 을 사용한 Confluent Cloud + Debezium Connector를 배포하는 실습을 진행합니다.
MySQL
데이터 다운로드
- 데이터는 MySQL 에서 공식 제공하고 있는 Employee 예제데이터를 사용한다.
- 이번게시글에서 test_db 디렉토리의 경로는
/Users/jjongguet/test_db
를 기준으로 합니다.
git clone https://github.com/datacharmer/test_db.git
cd test_db
mysql 설치
brew install mysql
brew services start mysql
#보안설정
mysql_secure_installation
#root password 를 설정하고, 원격지에서의 root 접근을 허용해주세요.
예제 데이터 적재
mysql -u root -p -t < employees.sql
#password: root password 입력
적재된 데이터베이스를 확인한다.
bash-5.1# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 11
Server version: 9.0.0 MySQL Community Server - GPL
Copyright (c) 2000, 2024, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| employees |
| information_schema |
| mysql |
| performance_schema |
| sys |
| testdb |
+--------------------+
6 rows in set (0.01 sec)
mysql> use employees;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+----------------------+
| Tables_in_employees |
+----------------------+
| current_dept_emp |
| departments |
| dept_emp |
| dept_emp_latest_date |
| dept_manager |
| employees |
| salaries |
| titles |
+----------------------+
8 rows in set (0.00 sec)
Kafka Cluster 배포(with sql connector)
sql connector 를 포함한 예제 코드를 사용하겠습니다.
terraform-provider-confluent/examples/configurations/connectors/sql-server-cdc-debezium-source-connector at master · confluenti
Terraform Provider for Confluent. Contribute to confluentinc/terraform-provider-confluent development by creating an account on GitHub.
github.com
내용수정
먼저 내 아이피를 확인해줍니다. 초록창에 내 아이피
를 검색합니다.
먼저 코드를 적절하게 수정해줍니다.
main.tf수정
#변경 전
provider "confluent" {
cloud_api_key = var.confluent_cloud_api_key
cloud_api_secret = var.confluent_cloud_api_secret
}
#변경 후
provider "confluent" {
}
variables.tf수정
variable "db_user" {
default = "root"
}
variable "db_password" {
default = {위에서 설정한 패스워드}
}
variable "mysql_hostname" {
default = {내 아이피주소}
}
variable "mysql_port" {
default = "3306"
}
variable "mysql_dbname" {
default = {employees}
}
main.tf
추가수정
- MySQL Database에 대한 내용을 수정합니다.
resource "confluent_connector" "sql-server-cdc-source" {
environment {
id = confluent_environment.staging.id
}
kafka_cluster {
id = confluent_kafka_cluster.basic.id
}
// Block for custom *sensitive* configuration properties that are labelled with "Type: password" under "Configuration Properties" section in the docs:
// https://docs.confluent.io/cloud/current/connectors/cc-microsoft-sql-server-source-cdc-debezium.html#configuration-properties
config_sensitive = {
"database.password" = "***REDACTED***"
}
// Block for custom *nonsensitive* configuration properties that are *not* labelled with "Type: password" under "Configuration Properties" section in the docs:
// https://docs.confluent.io/cloud/current/connectors/cc-microsoft-sql-server-source-cdc-debezium.html#configuration-properties
config_nonsensitive = {
"connector.class" = "SqlServerCdcSource"
"name" = "SqlServerCdcSourceConnector_0"
"kafka.auth.mode" = "SERVICE_ACCOUNT"
"kafka.service.account.id" = confluent_service_account.app-connector.id
"database.hostname" = var.mysql_hostname
"database.port" = var.mysql_port
"database.user" = var.db_user
"database.dbname" = var.mysql_dbname
"database.server.name" = local.database_server_name
"snapshot.mode" = "initial"
"output.data.format" = "JSON"
"tasks.max" = "1"
}
depends_on = [
confluent_kafka_acl.app-connector-describe-on-cluster,
confluent_kafka_acl.app-connector-write-on-prefix-topics,
confluent_kafka_acl.app-connector-create-on-prefix-topics,
confluent_kafka_acl.app-connector-write-on-dbhistory-prefix-topics,
confluent_kafka_acl.app-connector-create-on-dbhistory-prefix-topics,
confluent_kafka_acl.app-consumer-read-on-group,
]
}
locals {
database_server_name = "sql"
}
주요 설정값을 variables.tf
에 있는 값으로 대체했습니다.
이러한 방식의 장점은 변수관리의 편의성이 증가한다는 점입니다.
내용확인
배포되는 내용 중 중요한 내용만 확인해봅니다.
confluent_kafka_cluster
사용하는 kafka_cluster 의 타입은 basic입니다. 클라우드는 AWS 를 사용하는 예제로 되어있습니다.
resource "confluent_kafka_cluster" "basic" {
display_name = "inventory"
availability = "SINGLE_ZONE"
cloud = "AWS"
region = "us-east-1"
basic {}
environment {
id = confluent_environment.staging.id
}
}
confluent_kafka_topic
topic 이름으로 orders 라는 토픽을 생성합니다. 이때 partition 갯수를 지정하지 않았으므로, 이 경우 default값으로 지정됩니다.
resource "confluent_kafka_topic" "orders" {
kafka_cluster {
id = confluent_kafka_cluster.basic.id
}
topic_name = "orders"
rest_endpoint = confluent_kafka_cluster.basic.rest_endpoint
credentials {
key = confluent_api_key.app-manager-kafka-api-key.id
secret = confluent_api_key.app-manager-kafka-api-key.secret
}
}
confluent_connector
connector 를 생성합니다. 이때 sql-server-cdc-source 로 생성됩니다.
resource "confluent_connector" "sql-server-cdc-source" {
environment {
id = confluent_environment.staging.id
}
kafka_cluster {
id = confluent_kafka_cluster.basic.id
}
// Block for custom *sensitive* configuration properties that are labelled with "Type: password" under "Configuration Properties" section in the docs:
// https://docs.confluent.io/cloud/current/connectors/cc-microsoft-sql-server-source-cdc-debezium.html#configuration-properties
config_sensitive = {
"database.password" = "***REDACTED***"
}
// Block for custom *nonsensitive* configuration properties that are *not* labelled with "Type: password" under "Configuration Properties" section in the docs:
// https://docs.confluent.io/cloud/current/connectors/cc-microsoft-sql-server-source-cdc-debezium.html#configuration-properties
config_nonsensitive = {
"connector.class" = "SqlServerCdcSource"
"name" = "SqlServerCdcSourceConnector_0"
"kafka.auth.mode" = "SERVICE_ACCOUNT"
"kafka.service.account.id" = confluent_service_account.app-connector.id
"database.hostname" = var.mysql_hostname
"database.port" = var.mysql_port
"database.user" = var.db_user
"database.dbname" = var.mysql_dbname
"database.server.name" = local.database_server_name
"snapshot.mode" = "initial"
"output.data.format" = "JSON"
"tasks.max" = "1"
}
depends_on = [
confluent_kafka_acl.app-connector-describe-on-cluster,
confluent_kafka_acl.app-connector-write-on-prefix-topics,
confluent_kafka_acl.app-connector-create-on-prefix-topics,
confluent_kafka_acl.app-connector-write-on-dbhistory-prefix-topics,
confluent_kafka_acl.app-connector-create-on-dbhistory-prefix-topics,
confluent_kafka_acl.app-consumer-read-on-group,
]
}
locals {
database_server_name = "sql"
}
사용하려는 카프카의 모드와 계정, hostname(ip주소) 와 포트 및 계정을 지정합니다.
테라폼 배포
이제 배포를 진행합니다.
terraform init
→ API Key 입력 → terraform plan
→ terraform apply
순서로 구성됩니다.
terraform init
terraform init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of confluentinc/confluent from the dependency lock file
- Using previously-installed confluentinc/confluent v1.78.0
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
API Key 입력
- 터미널에서 , 에 API KEY값을 입력합니다.
- 이전 게시글 https://jjongguet.tistory.com/215 을 참고해주세요.
export CONFLUENT_CLOUD_API_KEY="<cloud_api_key>"
export CONFLUENT_CLOUD_API_SECRET="<cloud_api_secret>"
terraform plan
terraform plan
data.confluent_schema_registry_region.essentials: Reading...
confluent_environment.staging: Refreshing state... [id=env-7q78n2]
confluent_service_account.app-producer: Refreshing state... [id=sa-rx675k]
confluent_service_account.app-connector: Refreshing state... [id=sa-02yr96]
confluent_service_account.app-manager: Refreshing state... [id=sa-8pdzw7]
confluent_service_account.app-consumer: Refreshing state... [id=sa-2nywry]
confluent_kafka_cluster.basic: Refreshing state... [id=lkc-6zo088]
data.confluent_schema_registry_region.essentials: Read complete after 1s [id=sgreg-22]
confluent_schema_registry_cluster.essentials: Refreshing state... [id=lsrc-d8grw1]
confluent_role_binding.app-manager-kafka-cluster-admin: Refreshing state... [id=rb-XyX339]
confluent_api_key.app-producer-kafka-api-key: Refreshing state... [id=6QDSUDLHHPQG4NH4]
confluent_api_key.app-consumer-kafka-api-key: Refreshing state... [id=HSYUCO3XNSLXN5MI]
confluent_api_key.app-manager-kafka-api-key: Refreshing state... [id=UEPI72S6ICXJQNVR]
confluent_kafka_acl.app-connector-write-on-dbhistory-prefix-topics: Refreshing state... [id=lkc-6zo088/TOPIC#dbhistory.sql.lcc-#PREFIXED#User:sa-02yr96#*#WRITE#ALLOW]
confluent_kafka_acl.app-consumer-read-on-group: Refreshing state... [id=lkc-6zo088/GROUP#sql-dbhistory#LITERAL#User:sa-02yr96#*#READ#ALLOW]
confluent_kafka_acl.app-connector-create-on-prefix-topics: Refreshing state... [id=lkc-6zo088/TOPIC#sql#PREFIXED#User:sa-02yr96#*#CREATE#ALLOW]
confluent_kafka_acl.app-connector-describe-on-cluster: Refreshing state... [id=lkc-6zo088/CLUSTER#kafka-cluster#LITERAL#User:sa-02yr96#*#DESCRIBE#ALLOW]
confluent_kafka_acl.app-connector-write-on-prefix-topics: Refreshing state... [id=lkc-6zo088/TOPIC#sql#PREFIXED#User:sa-02yr96#*#WRITE#ALLOW]
confluent_kafka_acl.app-connector-create-on-dbhistory-prefix-topics: Refreshing state... [id=lkc-6zo088/TOPIC#dbhistory.sql.lcc-#PREFIXED#User:sa-02yr96#*#CREATE#ALLOW]
confluent_kafka_topic.orders: Refreshing state... [id=lkc-6zo088/orders]
confluent_connector.sql-server-cdc-source: Refreshing state... [id=lcc-20395m]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# confluent_connector.sql-server-cdc-source will be created
+ resource "confluent_connector" "sql-server-cdc-source" {
+ config_nonsensitive = {
+ "connector.class" = "SqlServerCdcSource"
+ "database.dbname" = "testdb"
+ "database.hostname" = ""
+ "database.port" = "3306"
+ "database.server.name" = "sql"
+ "database.user" = "root"
+ "kafka.auth.mode" = "SERVICE_ACCOUNT"
+ "kafka.service.account.id" = "sa-02yr96"
+ "name" = "SqlServerCdcSourceConnector_0"
+ "output.data.format" = "JSON"
+ "snapshot.mode" = "initial"
+ "tasks.max" = "1"
}
+ config_sensitive = (sensitive value)
+ id = (known after apply)
+ status = (known after apply)
+ environment {
+ id = "env-7q78n2"
}
+ kafka_cluster {
+ id = "lkc-6zo088"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
╷
│ Warning: Deprecated Resource
│
│ with data.confluent_schema_registry_region.essentials,
│ on main.tf line 21, in data "confluent_schema_registry_region" "essentials":
│ 21: data "confluent_schema_registry_region" "essentials" {
│
│ The "schema_registry_region" data source has been deprecated and will be removed in the next major version of the provider (2.0.0). Refer to the Upgrade Guide at
│ https://registry.terraform.io/providers/confluentinc/confluent/latest/docs/guides/version-2-upgrade for more details. The guide will be published once version 2.0.0 is released.
│
│ (and 3 more similar warnings elsewhere)
╵
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
terraform apply -auto-approve
이후 배포를 진행하면 Debezium Connector 와 싱글카프카 클러스터가 배포됩니다.