📦
Amazon Aurora から Google Cloud BigQuery へのデータ移行をTerraformを中心に実装してみた話
はじめに
弊社におけるデータベースはAmazon Auroraを使用しており、 シンプルなデータ閲覧はEC2で構築したRedashを用いて、Auroraインスタンスに対してクエリを実行しています。
最近、プロダクトチームから「Looker Studioを用いてリッチなレポート閲覧を行いたい」という要望があり、GoogleCloudにおけるBigQueryへのデータ連携を実施することになりました。
今回は実装にあたっての構成と環境構築の手順をご紹介します。
実装にあたっての要件
- リアルタイム性は求められず、任意のタイミングでデータ連携を行えれば良い。
- 秘匿性のあるデータはなく、特段マスキングの必要はない。
- 国内リージョンにデータを保存すること。(AWS:ap-northeast-1 GoogleCloud:asia-northeast1)
構成図
AWS側
- Aurora (System Snapshot)
- S3 (Snapshot Export の保存先)
- IAMロール (Snapshot Export 使用時の権限)
- IAMユーザ (GoogleCloud Data Transfer Service 使用時の権限)
- KMS (Snapshot Export 使用時の暗号化キー)
GoogleCloud側
- API有効化 (BigQuery API / BigQuery Data Transfer Service API)
- サービスアカウント作成 (BigQuery Data Transfer Service用)
- Data Transfer Service (AuroraからBigQueryへのデータ移行を実施)
- BigQuery (データ格納先)
実装手順
AWS側
################################################################################
# S3
################################################################################
module "s3_google_cloud_bigquery" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "4.5.0"
bucket = "hogehoge-aurora-to-bigquery"
server_side_encryption_configuration = {
rule = {
bucket_key_enabled = false
apply_server_side_encryption_by_default = {
sse_algorithm = "AES256"
}
}
}
}
################################################################################
# IAMロール
################################################################################
module "iam_role_aurora_s3_export" {
source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role"
version = "5.52.2"
create_role = true
role_name = "aurora-s3-export"
create_custom_role_trust_policy = true
custom_role_trust_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = ["export.rds.amazonaws.com"]
}
},
]
})
inline_policy_statements = [
{
actions = ["s3:ListAllMyBuckets"]
effect = "Allow"
resources = ["*"]
},
{
actions = [
"s3:ListBucket",
"s3:GetBucketLocation",
]
effect = "Allow"
resources = [module.s3_google_cloud_bigquery.s3_bucket_arn]
},
{
actions = [
"s3:GetObject",
"s3:PutObject",
"s3:DeleteObject",
]
effect = "Allow"
resources = ["${module.s3_google_cloud_bigquery.s3_bucket_arn}/*"]
},
]
}
################################################################################
# IAMユーザー
################################################################################
module "iam_user_google_cloud_for_bigquery_data_transfer" {
source = "terraform-aws-modules/iam/aws//modules/iam-user"
version = "5.52.2"
name = "google-cloud_for_bigquery-data-transfer"
create_iam_user_login_profile = false
}
module "iam_policy_google_cloud_for_bigquery_data_transfer" {
source = "terraform-aws-modules/iam/aws//modules/iam-policy"
version = "5.52.2"
name = "google-cloud_for_bigquery-data-transfer"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "S3ReadOnlyAccessForBucket"
Action = [
"s3:Listbucket",
]
Effect = "Allow"
Resource = [module.s3_google_cloud_bigquery.s3_bucket_arn]
},
{
Sid = "S3ReadOnlyAccessForBigQuery"
Action = [
"s3:GetObject",
]
Effect = "Allow"
Resource = ["${module.s3_google_cloud_bigquery.s3_bucket_arn}/*"]
},
{
Action = [
"kms:Decrypt",
]
Effect = "Allow"
Resource = [module.kms_for_aurora_s3_export.key_arn]
}
]
})
}
resource "aws_iam_user_policy_attachment" "google_cloud_for_bigquery_data_transfer" {
user = module.iam_user_google_cloud_for_bigquery_data_transfer.iam_user_name
policy_arn = module.iam_policy_google_cloud_for_bigquery_data_transfer.arn
}
################################################################################
# KMS
################################################################################
module "kms_for_aurora_s3_export" {
source = "terraform-aws-modules/kms/aws"
version = "3.1.1"
description = "for Aurora S3 Export"
}
################################################################################
# RDS(Aurora)
################################################################################
data "aws_db_cluster_snapshot" "this" {
db_cluster_identifier = "aurora-cluster"
db_cluster_snapshot_identifier = "rds:aurora-cluster-test-YYYY-MM-DD-hh-mm"
}
resource "aws_rds_export_task" "this" {
export_task_identifier = "hodehoge-test"
source_arn = data.aws_db_cluster_snapshot.this.db_cluster_snapshot_arn
s3_bucket_name = module.s3_google_cloud_bigquery.s3_bucket_id
iam_role_arn = module.iam_role_for_aurora_s3_export.iam_role_arn
kms_key_id = module.kms_for_aurora_s3_export.key_arn
}
################################################################################
# (GoogleCloud側への連携パラメータ)
################################################################################
output "iam_user_google_cloud_for_bigquery_data_transfer_iam_access_key_id" {
value = module.iam_user_google_cloud_for_bigquery_data_transfer.iam_access_key_id
}
output "iam_user_google_cloud_for_bigquery_data_transfer_iam_access_key_secret" {
value = module.iam_user_google_cloud_for_bigquery_data_transfer.iam_access_key_secret
sensitive = true
}
GoogleCloud側
################################################################################
# Other
################################################################################
data "terraform_remote_state" "aws_account_1" {
backend = "s3"
config = {
bucket = "{aws_account_1においてterraformのstateを保存するS3バケット名}"
key = "{上記S3バケットに格納しているterraformのstateファイル名}"
region = "ap-northeast-1"
}
}
locals {
aws_aurora = {
database_1 = {
table_1 = {}
table_2 = {}
}
database_2 = {
table_1 = {}
table_2 = {}
}
}
# データセットとテーブルの構造を平坦化
aws_aurora_tables = merge([
for dataset_name, tables in local.aws_aurora : {
for table_name, table_config in tables : "${dataset_name}_${table_name}" => {
dataset_name = dataset_name
table_name = table_name
schema = table_config
}
}
]...)
}
###############################################################################
# Project
###############################################################################
resource "google_project" "this" {
name = "hogehoge"
project_id = data.google_client_config.self.project
}
data "google_client_config" "self" {}
###############################################################################
# Service Account
###############################################################################
resource "google_service_account" "aws_aurora" {
account_id = "aws-aurora"
display_name = "aws-aurora"
project = google_project.this.project_id
}
###############################################################################
# BigQuery
###############################################################################
resource "google_bigquery_dataset" "aws_aurora" {
for_each = local.aws_aurora
dataset_id = each.key
location = "asia-northeast1"
}
resource "google_bigquery_table" "aws_aurora" {
for_each = local.aws_aurora_tables
dataset_id = each.value.dataset_name
table_id = each.value.table_name
depends_on = [
google_bigquery_dataset.aws_aurora
]
}
###############################################################################
# BigQuery Data Transfer Service
###############################################################################
resource "google_bigquery_data_transfer_config" "aws_aurora" {
for_each = local.aws_aurora_tables
location = "asia-northeast1"
data_source_id = "amazon_s3"
display_name = google_bigquery_table.aws_aurora[each.key].table_id
schedule_options {
disable_auto_scheduling = true
}
destination_dataset_id = each.value.dataset_name
service_account_name = google_service_account.aws_aurora.email
params = {
destination_table_name_template = google_bigquery_table.aws_aurora[each.key].table_id
data_path = "s3://${data.terraform_remote_state.kidsna_sitter_stg.outputs.s3_google_cloud_bigquery_bucket_id}/*/${each.value.dataset_name}/${each.value.dataset_name}.${google_bigquery_table.aws_aurora[each.key].table_id}/1/*.parquet"
access_key_id = data.terraform_remote_state.kidsna_sitter_stg.outputs.iam_user_google_cloud_for_bigquery_data_transfer_iam_access_key_id
file_format = "PARQUET"
}
sensitive_params {
secret_access_key = data.terraform_remote_state.kidsna_sitter_stg.outputs.iam_user_google_cloud_for_bigquery_data_transfer_iam_access_key_secret
}
depends_on = [
google_bigquery_dataset.aws_aurora
]
}
補足事項
Aurora S3 Export
- BigQueryに連携する時点で都度実施します。
data "aws_db_cluster_snapshot" "test" {
db_cluster_identifier = aws_rds_cluster.cluster_stg_2.id
db_cluster_snapshot_identifier = "{その時点で最新のシステムスナップショット名}"
}
resource "aws_rds_export_task" "test" {
export_task_identifier = "test-${formatdate("YYYYMMDDHHmmss", timestamp())}"
source_arn = data.aws_db_cluster_snapshot.test.db_cluster_snapshot_arn
s3_bucket_name = module.s3_google_cloud_bigquery.s3_bucket_id
iam_role_arn = module.iam_role_for_aurora_s3_export.iam_role_arn
kms_key_id = module.kms_for_aurora_s3_export.key_arn
}
BigQuery
- 最終的にデータベースのテーブル単位で”google_bigquery_table”を作成する必要があるため、for_eachを用いて再帰的に各テーブルを作成できるようしている。
locals {
aws_aurora = {
database_1 = {
table_1 = {}
table_2 = {}
new_table_1 = {} // 新規追加
}
database_2 = {
table_1 = {}
table_2 = {}
}
new_database_1 = { // 新規追加
new_table_1 = {}
}
}
}
BigQuery Data Transfer
-
GoogleCloud Consoleにログインし、該当のプロジェクトを選択したうえで、BigQueryの画面に遷移します。
-
連携するテーブル名のデータ転送を選択し、「今すぐ転送を実行」 -> 「OK」をクリックします。
-
ログ上、「Summary: succeeded 1 jobs, failed 0 jobs.」となっていれば成功です。
-
該当のBigQueryテーブルにデータが取り込まれていることを確認します。
最後に
今回はβ版的な扱いでベースとなる環境構築の手順をご紹介しました。次回は週次・日次でデータ連携を行う場合に必要な環境構築などをご紹介できればと思います。
Discussion