はじめに
皆様お疲れ様です!
株式会社TechoesインフラチームのTです!
今回は9/26にAmazon Aurora MySQL で RDS Data API のサポートを開始したようなので早速Terraformを使用して実践してみようと思います。
実行環境
- Windows : 11 Home 23H2
- Terraform : v1.9.7
- aws cli : 2.11.22
RDS Data APIについて
概要
RDS Data APIを利用することでHTTPSエンドポイントを介してRDS,Auroraに接続やDBドライバを管理することなくSQLの実行が可能になる。
接続時にSecret Managaerの情報を使用するため、認証情報を渡す必要がない
料金
最初の10億件のリクエストは100万回あたり0.42USD、10 億件を超えた場合は0.24USD
制約
- サポートしているエンジンが限定的
現時点で Aurora Mysqlと Aurora PostgreSQLのみをサポート - サポートしているインスタンスクラスが限定的
tクラス(db.t3など)がサポート外
Terraformについて
HashiCorp社によって開発されたIacツールでAWSやGCPなどのクラウドサービスをコードによって作成、管理できるツール。
事前準備
※ IAMユーザー,アクセスキーは発行済みとします。
※ AWS CLIはインストール済みとします。
Terraformのインストール
① 下記のリンクからファイルをダウンロード、解凍しましょう。
② 解凍完了後にデフォルトでPATHの通っているC:\Windows 配下にterraform.exeを配置
③ powershellを起動しterraform -v で確認
Terraform state用のS3バケットを作成とcloudshellのGIP確認
① AWSマネジメントコンソール上でS3バケットを作成
② CloudShell上で下記コマンドを実行
curl http://checkip.amazonaws.com/
※ バケット名、GIPは後々使うので控えておきましょう
AWSアクセスキーの設定
今回はTerraformをローカル環境で実行するためアクセスキーの設定を行います。
① aws configureコマンドを実行して発行したアクセスキーを設定
② aws s3 lsコマンドを使用して先ほど作成したバケット名が取得できていることを確認
実践
Terraformで環境構築
テンプレートは下記のものを使用します。
enviroments
バケット名とGIPは事前準備で取得したものを入力します。
terraform {
required_version = ">= 1.9.7"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.70.0"
}
}
backend "s3" {
bucket = "*****" #バケット名
key = "infra.tfstate" #パス
region = "ap-northeast-1"
}
}
provider "aws" {
region = "ap-northeast-1"
default_tags {
tags = {
Project = "RDS-DataAPI"
Environment = local.env
}
}
}
locals {
env = "test"
aws_region = "ap-northeast-1"
sysname = "rds-api-test"
vpc_cidr_block = "172.20.0.0/16"
private_subnet_cidr_block1 = "172.20.1.0/24"
private_subnet_cidr_block2 = "172.20.2.0/24"
cloudshell_gip = "***.***.***.***/32"
aws_az1 = "ap-northeast-1a"
aws_az2 = "ap-northeast-1c"
instance_class = "db.r6g.large"
db_name = "test_db"
engine = "aurora-mysql"
engine_version = "8.0.mysql_aurora.3.07.0"
}
module "resources" {
source = "../../modules"
sysname = local.sysname
env = local.env
vpc_cidr_block = local.vpc_cidr_block
private_subnet_cidr_block1 = local.private_subnet_cidr_block1
private_subnet_cidr_block2 = local.private_subnet_cidr_block2
aws_az1 = local.aws_az1
aws_az2 = local.aws_az2
instance_class = local.instance_class
cloudshell_gip = local.cloudshell_gip
db_name = local.db_name
engine = local.engine
engine_version = local.engine_version
}
module
# -----------------------------------------------------------------------------
# VPC
# -----------------------------------------------------------------------------
resource "aws_vpc" "vpc" {
cidr_block = var.vpc_cidr_block
}
# -----------------------------------------------------------------------------
# Subnet
# -----------------------------------------------------------------------------
resource "aws_subnet" "private-subnet-1" {
vpc_id = aws_vpc.vpc.id
cidr_block = var.private_subnet_cidr_block1
availability_zone = var.aws_az1
}
resource "aws_subnet" "private-subnet-2" {
vpc_id = aws_vpc.vpc.id
cidr_block = var.private_subnet_cidr_block2
availability_zone = var.aws_az2
}
# -----------------------------------------------------------------------------
# Subnet Group
# -----------------------------------------------------------------------------
resource "aws_db_subnet_group" "database_sg_group" {
name = "${var.sysname}-database-subnet-group"
subnet_ids = [aws_subnet.private-subnet-1.id, aws_subnet.private-subnet-2.id]
}
# -----------------------------------------------------------------------------
# Security Group
# -----------------------------------------------------------------------------
resource "aws_security_group" "database_sg" {
name = "${var.sysname}-database-sg"
vpc_id = aws_vpc.vpc.id
egress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = [var.cloudshell_gip]
}
}
# -----------------------------------------------------------------------------
# Secrets Manager
# -----------------------------------------------------------------------------
resource "aws_secretsmanager_secret" "aurora_credentials" {
name = "aurora-db-secret"
}
resource "random_password" "aurora_password" {
length = 41
special = true
override_special = "!()*+,-.;<=>?[]^_{|}~"
min_lower = 1
min_numeric = 1
min_special = 1
min_upper = 1
}
resource "aws_secretsmanager_secret_version" "aurora_credentials_version" {
secret_id = aws_secretsmanager_secret.aurora_credentials.id
secret_string = jsonencode({
username = "root",
password = random_password.aurora_password.result,
port = "3306",
dbname = var.db_name
authentication_plugin = "caching_sha2_password"
})
}
data "aws_secretsmanager_secret" "data_aurora_credentials" {
arn = aws_secretsmanager_secret.aurora_credentials.arn
}
data "aws_secretsmanager_secret_version" "data_aurora_credentials_version" {
secret_id = data.aws_secretsmanager_secret.data_aurora_credentials.id
}
locals {
secret_data = jsondecode(data.aws_secretsmanager_secret_version.data_aurora_credentials_version.secret_string)
}
# -----------------------------------------------------------------------------
# RDS
# -----------------------------------------------------------------------------
resource "aws_rds_cluster_parameter_group" "parameter_group" {
name = "${var.sysname}-database-cluster-parameter-group"
family = "aurora-mysql8.0"
parameter {
name = "time_zone"
value = "Asia/Tokyo"
}
}
resource "aws_rds_cluster" "rds_cluster" {
depends_on = [aws_secretsmanager_secret_version.aurora_credentials_version]
cluster_identifier = "${var.sysname}-cluster"
db_subnet_group_name = aws_db_subnet_group.database_sg_group.name
vpc_security_group_ids = [aws_security_group.database_sg.id]
availability_zones = [var.aws_az1, var.aws_az2]
engine = var.engine
engine_version = var.engine_version
database_name = local.secret_data.dbname
master_username = local.secret_data.username
master_password = local.secret_data.password
port = "3306"
enable_http_endpoint = true
skip_final_snapshot = true
db_cluster_parameter_group_name = aws_rds_cluster_parameter_group.parameter_group.name
lifecycle {
ignore_changes = [availability_zones]
}
}
resource "aws_rds_cluster_instance" "rds_instance" {
identifier = "${var.sysname}-instance"
cluster_identifier = aws_rds_cluster.rds_cluster.id
engine = aws_rds_cluster.rds_cluster.engine
engine_version = aws_rds_cluster.rds_cluster.engine_version
instance_class = var.instance_class
db_subnet_group_name = aws_rds_cluster.rds_cluster.db_subnet_group_name
}
下記の記述がRDS Data APIを有効にするものです
enable_http_endpoint = true
Terraform init と Terraform apply を実行して環境作成
RDS Data APIを使用してアクセス
環境を作成したのでさっそくCloudShellからアクセスしてみましょう。
接続にClusterのarnとSecretManagerのarnが必要になるのでコンソール上で確認しておきましょう。
Databaseの作成
aws rds-data execute-statement \
--resource-arn <クラスターARN> \
--secret-arn <シークレットARN> \
--sql "CREATE DATABASE <データベース名>"
テーブルの作成
aws rds-data execute-statement \
--resource-arn <クラスターARN> \
--secret-arn <シークレットARN> \
--database <データベース名> \
--sql "CREATE TABLE test_table (id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50));"
データの挿入
aws rds-data execute-statement \
--resource-arn <クラスターARN> \
--secret-arn <シークレットARN> \
--database <データベース名> \
--sql "INSERT INTO test_table (name) VALUES ('test1'), ('test2');"
データの取得
aws rds-data execute-statement \
--resource-arn <クラスターARN> \
--secret-arn <シークレットARN> \
--database <データベース名> \
--sql "SELECT * FROM test_table;"
所感
今回はTerraformでの環境構築でRDS Data APIを利用してみました。RDS Data APIを使用すればDBクライアントのインストールも必要ないのでデータベースへのアクセスがかなりシンプルになると思います。料金もリクエスト数によって課金されるので新規環境を作成する際は選択肢のひとつとして念頭に置いておきたいと思います。
参考記事