Terraform Cloud Project Bootcamp with Andrew Brown — Static Website Hosting
Quick preface
This article is part of my Terraform journey with Terraform Bootcamp by Andrew Brown and Andrew Bayko with Chris Williams and Shala.
My wild career adventure into Cloud Computing continues with Andrews, and I highly, highly recommend you to come join us if you are interested. Check out Andrews’ free youtube learning contents. You can also buy some paid courses here to support their good cause.
Agenda
- ✅ 1) Add the Configuration for Static Website Hosting
- ✅ 2) Declare module outputs and reference them from root
- ✅ 3) Upload files using Terraform
- ✅ 4) Detect data change in files with Terraform
- ✅ 5) Troubleshoot — Missing required argument
1. Add the Configuration for Static Website Hosting
To enable static website hosting in S3 bucket using Terraform. we introduce the following code. You can refer to this TF documentation for detail.
./modules/terrahouse_aws/main.tf
resource "aws_s3_bucket_website_configuration" "website_configuration" {
bucket = aws_s3_bucket.website_bucket.bucket
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
# routing_rule {
# condition {
# key_prefix_equals = "docs/"
# }
# redirect {
# replace_key_prefix_with = "documents/"
# }
# }
}
Then try running the following:
terraform plan # for validation
terraform apply --auto-approve
Then go check your AWS console if the newly created S3 bucket has the static website hosting option enabled.
2. Declare module outputs and reference them from root
/PROJECT_ROOT
├── /modules
| /terrahouse_aws
| ├── ...
| ├── outputs.tf
| └── ...
├── ...
├── outputs.tf
└── ...
Above is the simplified structure of our project highlighting the depths of the outputs.tf
files. See how the output declaration at module and output referencing from root compare.
- Output declaration: references the resource declared in the
main.tf
file inside the same module (resource entity). - Output referencing: specifies the path to the output of a module (file path).
# outputs.tf at PROJECT_ROOT/modules/terrahouse_aws
output "s3_website_endpoint" {
description = "website endpoint for the statically hosted website"
value = aws_s3_bucket_website_configuration
.website_configuration.website_endpoint # the entity from main.tf
}
# outputs.tf at PROJECT_ROOT
output "s3_website_endpoint" {
value = module.terrahouse_aws.website_endpoint # specify the output path.
}
3. Upload files using Terraform
Add the resources
indexhtml
& error_html
which specify the attributes and path of the actual files. Make sure that the files are actually at the specified paths and the paths are correct.
resource "aws_s3_object" "index_html" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "index.html"
source = var.index_html_filepath
etag = filemd5("${path.root}/public/index.html")
}
resource "aws_s3_object" "error_html" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "error.html"
source = "${path.root}/public/error.html"
etag = filemd5("${path.root}/public/error.html")
}
4. Detect data change in files with Terraform
If you modify the code in files like index.html
and error.html
then try running terrafrom, you may notice that there is no changes to the infrastructure. So you may get a message like this:
This is because by default, terraform doesn’t run data check for change sets. It only compares the changes to the infrastructure. If you want to make sure terraform updates the infrastructures including files changes upon modifying the content of some of your files, you can inform terraform of this by using theetag
attribute of aws_s3_bucket_object
.
etag
: Triggers updates when the value changes. See documentation as it requires strict formatting.
# main.tf
resource "aws_s3_object" "website_index" {
bucket = aws_s3_bucket.website_bucket.bucket
key = "index.html"
source = "${path.root}/public/index.html"
+ etag = filemd5("${path.root}/public/index.html")
}
Then now run terraform apply
and there will be changes.
5. Troubleshoot — Missing required argument
In order to use the module variables at root, we have to declare them in the module definition in main.tf
at root.
module "terrahouse_aws" {
source = "./modules/terrahouse_aws"
user_uuid = var.user_uuid
bucket_name = var.bucket_name
+ index_html_filepath = var.index_html_filepath
+ error_html_filepath = var.error_html_filepath
}
Fixing Tags
Delete the latest tag
How to delete local and remote tags on Git
git tag -d <tag_name>
: locally delete a taggit push --delete origin <tag_name>
: remotely delete tag
Fix previous tags (non-HEAD
tags)
- 1)
checkout
the commit that you want to re-tag. - 2) Grab the SHA from your Github commit history.
- 3) Then run the following commands:
git checkout <SHA>
git tag M.M.P
git push --tags
git checkout main
Bash Command Cheat Sheet
# Download everything from your bucket to destination
aws s3 sync s3://YOUR_BUCKET_NAME .
# Empty bucket
aws s3 rm s3://YOUR_BUCKET_NAME --recursive
# Remove bucket
aws s3 rb s3://YOUR_BUCKET_NAME
Considerations when using Terraform to manage different types of resources
In this bootcamp, we are using Terraform for all three types of management:
- Infrastructure (resources management)
- Configurations
- Files
Please note that Terraform is optimised and made for infrastructure management. Therefore, managing files (uploading and downloading) using terraform is not the best practice, all the more so in production environment although Terraform does offer the capabilities to manage other resources like configuration and files.