Skip to content

Creating an Relation Database Service (RDS) instance with Terraform

RDS is one of the managed database services on AWS, many of the most common relational databases can be easily provisioned via RDS, including MySQL, Oracle and SQL Server.

Getting Started

Again we start with a new Scaffold.

$ scaffold RDS-starter
git clone --depth=1 git@github.com:JamesWoolfenden/tf-scaffold.git RDS-starter
Cloning into 'RDS-starter'...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 11 (delta 0), reused 6 (delta 0), pack-reused 0
Receiving objects: 100% (11/11), done.

Now that you have the scaffold you can add your components.

Provision a basic RDS instance

Add this RDS resource to RDS-starter as aws_db_instance.employee.tf

resource "aws_db_instance" "employee" {
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t2.micro"
  name                 = "mydb"
  skip_final_snapshot  = true
  publicly_accessible  = false
  username             = "Sleepycat"
  password             = "thr33littlew0rds"
  parameter_group_name = "default.mysql5.7"
}

And try out the template:

$ terraform plan
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  + aws_db_instance.employee
      id:                         <computed>
      address:                    <computed>
      allocated_storage:          "20"
      apply_immediately:          <computed>
      arn:                        <computed>
      auto_minor_version_upgrade: "true"
      availability_zone:          <computed>
      backup_retention_period:    <computed>
      backup_window:              <computed>
      ca_cert_identifier:         <computed>
      character_set_name:         <computed>
      copy_tags_to_snapshot:      "false"
      db_subnet_group_name:       <computed>
      endpoint:                   <computed>
      engine:                     "mysql"
      engine_version:             "5.7"
      hosted_zone_id:             <computed>
      identifier:                 <computed>
      identifier_prefix:          <computed>
      instance_class:             "db.t2.micro"
      kms_key_id:                 <computed>
      license_model:              <computed>
      maintenance_window:         <computed>
      monitoring_interval:        "0"
      monitoring_role_arn:        <computed>
      multi_az:                   <computed>
      name:                       "employee"
      option_group_name:          <computed>
      parameter_group_name:       "default.mysql5.7"
      password:                   <sensitive>
      port:                       <computed>
      publicly_accessible:        "false"
      replicas.#:                 <computed>
      resource_id:                <computed>
      skip_final_snapshot:        "false"
      status:                     <computed>
      storage_type:               "gp2"
      timezone:                   <computed>
      username:                   "Sleepycat"
      vpc_security_group_ids.#:   <computed>


Plan: 1 to add, 0 to change, 0 to destroy.

Before you apply add an output to outputs.tf

output "endpoint" {
    value=aws_db_instance.employee.endpoint
}

Applying that should succeed, mine took around 4mins in my testing, and finally the output of the DBs endpoint:

endpoint = employee.ch6wpf7x4jbf.eu-west-1.rds.amazonaws.com:3306

There are a large number of properties other than the ones we have supplied, so many defaults are being assumed. So far we haven't specified the VPC or even a Subnet. Provisioning will add your DB instance in with many of the defaults.

Terraform displays that the instance has been provisioned, but we do need to verify.

Testing DB Instance

Get will need to get the client MySQL tools installed:

choco install mysql-cli

or

brew install mysql

Now connecting to the instance is the proof:

$ mysql -h employee.ch6wpf7x4jbf.eu-west-1.rds.amazonaws.com -P 3306 -u Sleepycat -p
Enter password: ****************
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 6
Server version: 5.7.23 Source distribution

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

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>

Now you have a connected SQL prompt so you can run your now SQL against the db.

Warning

Earlier I set a property - publicly_accessible="true" that made your db public, we wouldn't normally allow a db to be public.

Multiple DBs

How can I provision 2 databases of the same type? This is done by using the count variable and adding it to your resource:

  count="2"

Additionally you will need to change the name so that it can be unique.

name                   = "employee${count.index}"

When you plan again, it now raises this issue:

* output.endpoint: Resource 'aws_db_instance.employee' not found for variable 'aws_db_instance.employee.endpoint'

This is because aws_db_instance.employee is now a list, the output reference now needs to support the blat array reference like this:

aws_db_instance.employee.*.endpoint

Now try plan again and you'll find this plans just fine but it but you'll see that it will make 2 databases instances.

Sample data from https://dev.mysql.com/doc/employee/en/employees-installation.html

Terraform RDS https://www.terraform.io/docs/providers/aws/r/db_instance.html

AWS RDS terraform module example https://github.com/terraform-aws-modules/terraform-aws-rds/tree/master/examples/complete-mysql

Warning

Delete you DB's and Clusters after you've finished as they cost ££££