Creating a Relational Database Service in AWS with Terraform
Introduction
In the ever-evolving landscape of cloud computing, managing databases efficiently is crucial for the success of any application. Amazon Web Services (AWS) offers a powerful and scalable solution in the form of Amazon RDS (Relational Database Service). This blog post will guide you through the process of creating an Amazon RDS instance using Terraform, a popular infrastructure-as-code tool.
Why Amazon RDS?
Before we dive into the technical details, let's briefly discuss why Amazon RDS is a preferred choice. Amazon RDS takes care of time-consuming database tasks, such as backups, software patching, and automatic failure detection, allowing developers to focus on building robust applications rather than managing database infrastructure.
Pre-Requisite Steps
Before starting with terraform, complet below steps .
1. Create an AWS access key and secret key with Administration Access.
2. Create a VPC and 2 subnets, both should be in different availability zones.
3. Create a Security Group with the neccesary inbound rules.
You’re good to go to start terraform code.
Setting Up Your Terraform Configuration
To get started, create a directory for your Terraform project.
* mkdir terraform_rds
* cd terraform_rds
Inside this directory, you'll need three essential files:
1. main.tf
2. variables.tf
3. terraform.tfvars
Name of the files shouldn’t be changed.
main.tf : This is the file consists of main terraform code which creates rds with given parametrs.
Paste the below code in ‘main.tf ’.
provider "aws" {
region = var.region
access_key = var.access_key
secret_key = var.secret_key
}
################################################################################
# DB subnet group
################################################################################
# Create a unique name for DB subnet group
# Gettings subnet_ids and availability_zones into a list from variable
locals {
db_subnet_group_name = "${var.project_name}_subnet_group_${formatdate("YYYYMMDDhhmmss", timestamp())}"
subnet_ids = [ for data in var.subnets : data["subnet_id"] ]
availability_zones = [ for data in var.subnets : data["availability_zone"] ]
}
resource "aws_db_subnet_group" "rds_mysql_subnet_group" {
name = local.db_subnet_group_name
subnet_ids = local.subnet_ids
}
################################################################################
# RDS MySQL Instance
################################################################################
resource "aws_db_instance" "rds_mysql_database_instance" {
identifier = "${var.project_name}-database-instance"
allocated_storage = var.database_allocated_storage
max_allocated_storage = var.database_max_storage
availability_zone = local.availability_zones[0]
db_subnet_group_name = aws_db_subnet_group.rds_mysql_subnet_group.name
vpc_security_group_ids = var.security_group_ids
db_name = var.initial_database_name
engine = var.engine
engine_version = var.engine_version
instance_class = var.database_instance_class
username = var.database_username
password = var.database_password
publicly_accessible = true
skip_final_snapshot = true
deletion_protection = false
backup_retention_period = 7
delete_automated_backups = false
ca_cert_identifier = var.ca_certificate
}
################################################################################
# Storing Data in variables
################################################################################
locals {
db_instance_name = aws_db_instance.rds_mysql_database_instance.identifier
db_resource_id = aws_db_instance.rds_mysql_database_instance.resource_id
db_instance_endpoint = aws_db_instance.rds_mysql_database_instance.address
}
################################################################################
# Writing all collected data inside a file 'rds_mysql_data.json'
################################################################################
resource "null_resource" "write_to_json" {
triggers = {
always_run = "${timestamp()}"
}
depends_on = [ aws_db_instance.rds_mysql_database_instance ]
provisioner "local-exec" {
command = <<-EOT
echo '{
"db_instance_name": "${local.db_instance_name}",
"db_resource_id": "${local.db_resource_id}",
"db_instance_endpoint": "${local.db_instance_endpoint}"
}' > rds_mysql_data.json
EOT
}
}
Above code takes variables which are defined in variables.tf file.
Paste the below code in ‘variables.tf ’.
“ “ “
variable "region" {
type = string
sensitive = true
}
variable "access_key" {
type = string
sensitive = true
}
variable "secret_key" {
type = string
sensitive = true
}
variable "project_name" {
type = string
}
variable "vpc_id" {
type = string
}
variable "subnets" {
type = list(map(string))
default = [ {
"subnet_id" : "value",
"availability_zone" : "value"
} ]
}
variable "security_group_ids" {
type = list(string)
}
variable "initial_database_name" {
type = string
default = "rds_mysql_db"
}
variable "database_username" {
type = string
sensitive = true
}
variable "database_password" {
type = string
sensitive = true
}
variable "engine" {
type = string
}
variable "engine_version" {
type = string
}
variable "database_instance_class" {
type = string
}
variable "database_allocated_storage" {
type = number
default = 10
}
variable "database_max_storage" {
type = number
default = 20
description = "It should be greater than database_allocated_storage"
}
variable "ca_certificate" {
type = string
default = "rds-ca-rsa2048-g1"
}
” ” ”
The actual values of this variables are stored in ‘terraform.tfvars’ file.
Paste the below lines in ‘terraform.tfvars’
# AWS Region
region = "REGION"
# AWS Access Key
access_key = "ACCESS_KEY"
# AWS Secret Key
secret_key = "SECRET_KEY"
# Any name, used as idetifiers for aws resources
project_name = "PROJECT_NAME"
# VPC ID
vpc_id = "VPC_ID"
# Subnet ID's with availability_zone in a list of map
# E.g. Here, 2 subnets are taken
# subnets = [
# {
# "subnet_id" : "subnet-023504",
# "availability_zone" : "ap-south-1a"
# },
# {
# "subnet_id" : "subnet-02355456",
# "availability_zone" : "ap-south-1b"
# }
# ]
subnets = SUBNETS
# Security Group IDs in a list
#E.g. security_group_ids = ["sg-02124","sg-21412","sg-2121"]
security_group_ids = SECURITY_GROUPS_IDS
# Database name created at the time of launching database instance
initial_database_name = "DATABASE_NAME"
# Database admin username
# Constraints: 1 to 32 alphanumeric characters. The first character must be a letter.
database_username = "DATABASE_USERNAME"
# Database admin password
# Constraints: At least 8 printable ASCII characters. Can't contain
# any of the following: / (slash), '(single quote), "(double quote) and @ (at sign).
database_password = "DATABASE_PASSWORD"
# Engine name,
# E.g. "mysql" for mysql and "postgres" for postgresql
engine = "ENGINE"
# Engine version for mysql
# E.g. "8.0"
engine_version = "ENGINE_VERSION"
# Instance type for database
# E.g. "db.t3.medium"
database_instance_class = "DATABASE_INSTANCE_CLASS"
# Database Storage in GBs
# This is the minimum storage database will have initially
# E.g. 15 (For 15GB)
database_allocated_storage = DATABASE_STORAGE
# Database Maximum storage
# It is the maximum limit of storage that a database can expand to
# It should be greater than database_allocated_storage
# E.g. 20 (For 20GB),
database_max_storage = MAX_DATABASE_STORAGE
Fill the variables in terarform.tfvars files . Example values are given here.
This is a critical file as it contains all the credentials, so take a note of that.
?
Till now, all the required files are created, and variabled are filled with their required values.
Let’s now create the actual Infrastucture.
Initialize the Directory as terraform project,
* terrform init
Apply the terraform code,
* terraform apply
Run above command, it will first show us what are the resource it is going to create and ask us for the confirmation, write ‘yes’ and press enter for proceed.
?
Now, When it completes, you will find a json file named as ‘rds_mysql_data.json’. This file contains three information :
Name of created RDS
ID of RDS
Endpoint of RDS to connect
Accessing Your RDS Instance
Once Terraform completes the provisioning, you can find the endpoint in the json file. Use these details to connect to your RDS instance using your preferred database client.
We have successfully connected to the RDS .
Conclusion?
In this blog post, we explored the process of creating an Amazon RDS instance using Terraform. Leveraging infrastructure as code allows for version control, repeatability, and collaboration in managing AWS resources efficiently.
Amazon RDS, combined with Terraform's simplicity and power, provides a seamless solution for handling relational databases in the AWS cloud. As you embark on your cloud journey, mastering tools like Terraform becomes essential for maintaining a scalable and manageable infrastructure.
Now, armed with your newly created RDS instance, you're ready to build and deploy applications that harness the full potential of a reliable and scalable database service in AWS. Happy coding!