Skip to content

Terraform Level 1, Task 17: Provisioning a NoSQL Database (DynamoDB)

Today's task was a fantastic introduction to the world of serverless databases. I used Terraform to provision an AWS DynamoDB table. This was a significant conceptual leap from traditional servers and storage, as DynamoDB is a fully managed NoSQL database service where I don't have to worry about servers, patching, or scaling.

I learned how to define a DynamoDB table in code, including its most critical components: the primary key (or "hash key") and the billing mode. This document is my very detailed, first-person guide to that entire process, with a deep dive into the code and the core concepts of NoSQL databases in the cloud.

Table of Contents


The Task

My objective was to use Terraform to create a new AWS DynamoDB table with a specific configuration. The requirements were: 1. All code had to be in a single main.tf file. 2. The table's name had to be datacenter-users. 3. The primary key for the table must be datacenter_id, and its data type must be a String. 4. The table had to use the PAY_PER_REQUEST billing mode.


My Step-by-Step Solution

The process involved writing a Terraform file that defined the DynamoDB table resource and then running the standard three-step workflow.

Phase 1: Writing the Code

In the /home/bob/terraform directory, I created my main.tf file. I wrote the following declarative code to define my DynamoDB table exactly as requested.

# 1. Configure the AWS Provider to set the region
provider "aws" {
  region = "us-east-1"
}

# 2. Define the DynamoDB Table Resource
resource "aws_dynamodb_table" "users_table_resource" {
  name           = "datacenter-users"
  billing_mode   = "PAY_PER_REQUEST"
  hash_key       = "datacenter_id"

  attribute {
    name = "datacenter_id"
    type = "S" # "S" stands for String
  }

  tags = {
    Name = "datacenter-users"
  }
}

Phase 2: The Terraform Workflow

From my terminal in the same directory, I executed the three core commands.

  1. Initialize: terraform init (to download the AWS provider).
  2. Plan: terraform plan. The output showed me that Terraform would create one aws_dynamodb_table resource with all my specified settings.
  3. Apply: terraform apply. After I confirmed with yes, Terraform created the DynamoDB table in my AWS account. The success message confirmed the task was done.

Why Did I Do This? (The "What & Why")

- AWS DynamoDB: This is a fully managed, serverless, NoSQL key-value and document database. - Fully Managed & Serverless: This is the most important part. I don't have to provision, patch, or manage any servers. AWS handles all the underlying infrastructure, scaling, and high availability for me. - NoSQL: This is a different paradigm from traditional relational databases like MySQL. Instead of a rigid schema with tables, rows, and columns, a NoSQL database like DynamoDB is more flexible. It stores "items" (like rows) which are collections of "attributes" (like columns). - Primary Key / Hash Key: In DynamoDB, the primary key is how you uniquely identify an item. The simplest form of a primary key is a partition key (which Terraform calls the hash_key). DynamoDB uses this key to distribute data across multiple storage partitions, which is how it achieves massive scalability. For my table, datacenter_id is the partition key. - Billing Mode (PAY_PER_REQUEST): This is a key feature of DynamoDB's serverless nature. - PROVISIONED (The old way): You would have to guess your traffic and pay for a fixed amount of "read and write capacity units" per second, whether you used them or not. - PAY_PER_REQUEST (On-Demand): This is the modern, flexible option. I don't have to provision any capacity. I simply pay for the exact number of read and write requests my application makes. This is perfect for new applications with unpredictable traffic patterns.


Deep Dive: A Line-by-Line Explanation of My main.tf Script

Understanding the arguments for the aws_dynamodb_table resource was the core of this task.

[Image of a DynamoDB table structure]

# Standard provider configuration block.
provider "aws" {
  region = "us-east-1"
}

# This is the resource block that defines my DynamoDB table.
# "aws_dynamodb_table" is the Resource TYPE.
# "users_table_resource" is the local NAME I use to refer to this table.
resource "aws_dynamodb_table" "users_table_resource" {

  # The 'name' argument sets the unique name for the table within my AWS account and region.
  name = "datacenter-users"

  # The 'billing_mode' argument is required. I set it to 'PAY_PER_REQUEST'
  # for on-demand, serverless-style billing.
  billing_mode = "PAY_PER_REQUEST"

  # The 'hash_key' argument specifies the name of the attribute that will serve
  # as the primary key (partition key) for the table.
  hash_key = "datacenter_id"

  # A DynamoDB table requires you to define the name and type of any attributes
  # that are used in its keys.
  attribute {
    # The name of the attribute, which must match the 'hash_key' name.
    name = "datacenter_id"
    # The data type of the attribute. "S" stands for String, "N" for Number,
    # and "B" for Binary.
    type = "S"
  }

  # Standard tagging to give the table a recognizable name.
  tags = {
    Name = "datacenter-users"
  }
}

Common Pitfalls

- Forgetting the attribute Block: A very common mistake is to define the hash_key but forget to add the corresponding attribute block that defines its data type. Terraform would fail with an error because DynamoDB requires all key attributes to be explicitly defined. - Choosing the Wrong Primary Key: The choice of a primary key (hash key) is a critical architectural decision in DynamoDB. A poorly chosen key can lead to "hot partitions" and performance issues at scale. - Billing Mode Costs: While PAY_PER_REQUEST is great for unpredictable traffic, for a workload with very stable and predictable high traffic, the PROVISIONED mode can sometimes be more cost-effective.


Exploring the Essential Terraform Commands

This task used the main workflow, but here's a more complete list of the essential commands I'm learning.

  • terraform init: Initializes the working directory. It downloads provider plugins, sets up the backend for storing state, and prepares the directory for other commands. This is always the first command you run.
  • terraform validate: Checks the syntax of your Terraform files. It's a very fast way to find typos or structural errors in your code.
  • terraform fmt: Auto-formats your Terraform code according to the standard conventions. This keeps your code clean, consistent, and easy to read.
  • terraform plan: A "dry run" or preview. It reads your code, compares it to the current state of your real-world infrastructure, and shows you a detailed execution plan of what it will create, change, or destroy.
  • terraform apply: Executes the plan generated by terraform plan. This is the command that actually makes changes to your cloud infrastructure.
  • terraform show: Shows the current state of your managed infrastructure, as recorded in the Terraform state file.
  • terraform state list: Lists all the resources that Terraform is currently managing in its state file.
  • terraform destroy: The opposite of apply. It creates a plan to destroy all the infrastructure that this configuration manages. It will ask for confirmation before deleting anything.