terraform aws lightsail

Last time we setup an AWS account. Today we’ll setup a Lightsail site using Terraform!

Pre-requisites:

  1. An AWS Account. See previous post for more details.
  2. AWS CLI.
  3. Terraform CLI.

There are three parts to this:

  1. Creating a Lightsail Instance
  2. Setting up Route53/DNS
  3. Setting up a remote S3 bucket state store for Terraform

We’ll walk through each section in detail, and all the code can be found here.

Creating a Lightsail Instance

First, let’s talk a about the directory structure of our Terraform:

├── README.md
├── main.tf
├── modules
│   └── lightsail
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── terraform.tfvars
└── variables.tf

At the top level, we have our main.tf along with our variables files. The variables.tf defines the vars we can set in terraform.tfvars and reference in main.tf. Note, I do not have terraform.tfvars checked into my public repo because it’s specific to each environment.

Additionally, we create a modules directory and add a lightsail module within it. This is where our generic lightsail definition will live defined by the main.tf and variables.tf. Later, we’ll want to use some of the data generated by this module in another module, so we need to specify our outputs.tf.

Lightsail Module

├── README.md
├── main.tf
├── modules
│   └── lightsail
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── terraform.tfvars
└── variables.tf

Let’s work our way from the lightsail module up to the top level main.tf. First and foremost, we need to be able to pass down values into the module, so we need to define our variables.

# modules/lightsail/variables.tf
variable "lightsail_instance_name" {
  type        = string
  description = "Name of the lightsail instance"
}

variable "lightsail_availability_zone" {
  type        = string
  description = "Must be one of [ap-northeast-1{a,c,d}, ap-northeast-2{a,c}, ap-south-1{a,b}, ap-southeast-1{a,b,c}, ap-southeast-2{a,b,c}, ca-central-1{a,b}, eu-central-1{a,b,c}, eu-west-1{a,b,c}, eu-west-2{a,b,c}, eu-west-3{a,b,c}, us-east-1{a,b,c,d,e,f}, us-east-2{a,b,c}, us-west-2{a,b,c}]"
}

variable "lightsail_ip_address_type" {
  type        = string
  description = "The IP address type of the Lightsail Instance. Valid Values: dualstack | ipv4"

  default = "ipv4"
}

variable "lightsail_blueprint" {
  type        = string
  description = "One of the blueprints listed by the AWS cli - aws lightsail get-blueprints"

  default = "wordpress"
}

variable "lightsail_bundle_id" {
  type        = string
  description = "The bundle id of the instance"

  default = "micro_2_0"
}

variable "lightsail_static_ip_name" {
  type        = string
  description = "Unique name for the lightsail static ip resource"
}

These are all options that the Terraform Lightsail provider will use to instantiate the Lightsail instance. Let’s go ahead and write the Terraform we need to build the instance and reference these variables.

# modules/lightsail/main.tf
resource "aws_lightsail_instance" "lightsail" {
  name              = var.lightsail_instance_name
  availability_zone = var.lightsail_availability_zone
  ip_address_type   = var.lightsail_ip_address_type
  blueprint_id      = var.lightsail_blueprint
  bundle_id         = var.lightsail_bundle_id

  add_on {
    type          = "AutoSnapshot"
    snapshot_time = "06:00"
    status        = "Enabled"
  }
}

resource "aws_lightsail_static_ip" "lightsail" {
  name = var.lightsail_static_ip_name
}

resource "aws_lightsail_static_ip_attachment" "lightsail" {
  static_ip_name = aws_lightsail_static_ip.lightsail.id
  instance_name  = aws_lightsail_instance.lightsail.id
}

We have three resources here:

  • aws_lightsail_instance – this is the actual lightsail instance. You have to provide a name, an AZ, specify IPv4, IPv6, or both, a blueprint (machine size), and a bundle (pre-defined container like WordPress). Additionally this resource is going to enable auto snapshots at 06:00 UTC.
  • aws_lightsail_static_ip – creates a static_ip to be used with your Lightsail instance. This will become important as we tie together DNS and routing.
  • aws_lightsail_static_ip_attachment – attaches the static_ip to the lightsail instance.

Notice how there isn’t anything specific to your site in this module. It’s all generic and that’s good because we are going to start specifying details in the top level main.tf.

Main Terraform

├── README.md
├── main.tf
├── modules
│   └── lightsail
│       ├── main.tf
│       ├── outputs.tf
│       └── variables.tf
├── terraform.tfvars
└── variables.tf

Let’s start with our variables.tf definitions. These are values we’ll set in terraform.tfvars and will be referenced by our main.tf.

# ./variables.tf
variable "environment" {
  type        = string
  description = "Unique name for your AWS environment (ie. dev)"
}

variable "user_role_arn" {
  type        = string
  description = "The user_role_arn of the account being used by terraform"
}

variable "bucket_name" {
  type        = string
  description = "The name of the bucket. Must be unique."
}

variable "lightsail_instance_name" {
  type        = string
  description = "Name of the lightsail instance"
}

variable "lightsail_availability_zone" {
  type        = string
  description = "Must be one of [ap-northeast-1{a,c,d}, ap-northeast-2{a,c}, ap-south-1{a,b}, ap-southeast-1{a,b,c}, ap-southeast-2{a,b,c}, ca-central-1{a,b}, eu-central-1{a,b,c}, eu-west-1{a,b,c}, eu-west-2{a,b,c}, eu-west-3{a,b,c}, us-east-1{a,b,c,d,e,f}, us-east-2{a,b,c}, us-west-2{a,b,c}]"
}

variable "lightsail_ip_address_type" {
  type        = string
  description = "The IP address type of the Lightsail Instance. Valid Values: dualstack | ipv4"

  default = "ipv4"
}

variable "lightsail_blueprint" {
  type        = string
  description = "One of the blueprints listed by the AWS cli - aws lightsail get-blueprints"

  default = "wordpress"
}

variable "lightsail_bundle_id" {
  type        = string
  description = "The bundle id of the instance"

  default = "micro_2_0"
}

variable "lightsail_static_ip_name" {
  type        = string
  description = "Unique name for the lightsail static ip resource"
}

These map pretty close to the things I want to be able to customize from the Lightsail Terraform provider documentation. Now, let’s set them to our customized values in terraform.tfvars. When we we run terraform commands, it will automatically read the terraform.tfvars file and used map the custom values to the variables we defined above. You could also use ENV vars or pass them in via the CLI using arguments, but automatically loading them with a *.tfvars file is pretty simple. Go ahead and create a new file called terraform.tvars adjacent to the root main.tf module.

# ./terraform.tfvars
lightsail_instance_name     = "fishbits_wordpress"
lightsail_availability_zone = "us-west-2b"
lightsail_blueprint         = "wordpress"
lightsail_ip_address_type   = "ipv4"
lightsail_bundle_id         = "micro_2_0"
lightsail_static_ip_name    = "fishbits_static_ip"

It’s time to create the Terraform that will use these values and reference our Lightsail module!

# ./main.tf
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "4.64.0"
    }
  }
}

# Configure the AWS Provider
provider "aws" {
  region = "us-west-2"
}

module "lightsail" {
  source = "./modules/lightsail"

  lightsail_instance_name = var.lightsail_instance_name
  lightsail_availability_zone = var.lightsail_availability_zone
  lightsail_ip_address_type = var.lightsail_ip_address_type
  lightsail_blueprint = var.lightsail_blueprint
  lightsail_bundle_id = var.lightsail_bundle_id
  lightsail_static_ip_name = var.lightsail_static_ip_name
}

We have three stanzas defined above:

  1. Specify the required providers in the terraform block.
  2. Configure the aws provider.
  3. Import the Lightsail module and configure it.

That’s it! Now you can run terraform plan and it will show you what Terraform want’s to create in your AWS account. This is just the beginning, it will setup your Lightsail instance with a WordPress container image and assign it a static IP. Navigate to the Lightsail Dashboard and you will see something similar to this:

Well done!

Cool! You can now hit your WordPress via the static IP assigned to the instance if you’d like. The documentation at AWS can walk you through how to retrieve your password and log in the first time much better than I can! Follow the directions here: Step 3 – log in and start using WordPress.

Next time, we’ll integrate Route53 and manage our domain.

Leave a Reply

Your email address will not be published. Required fields are marked *