The idea behind this project came from the need to build a simple Wordpress application in just few simple steps without the need to manage how much capacity in terms of computation I needed and ideally, by using microservices.
At that time when I started this mini project I was already familiar with AWS, and I was also studying to get my first AWS certificate but I never had the chance to work with microservices. So I said to myself, why don't you build a simple Wordpress application by using ECS?
Amazon ECS is a fully managed container orchestration service that makes it easy for you to deploy, manage, and scale containerized applications. For more info:
I started doing my researches and came up with a very interesting article from AWS that explained how to deploy a Wordpress application directly in ECS by using Cloudformation:
https://aws.amazon.com/blogs/containers/running-wordpress-amazon-ecs-fargate-ecs/
So I though, here we are! job done, I followed the guide, made some changes, and I had a fully working Wordpress website deployed in AWS. AWSome!!
Recently I decided redepedloy the application again, but rather than using Cloudformation I decided to refactor everything to Terraform. I know, I could have used some tools or even the "famous" ChatGPT to assist me in this journey, but since my main objective was to use improve my Terraform skills, I decided to do it manually step by step.
The architecture is based on the one provided by AWS in the article mentioned above. Please find below a picture that I took from the blog post.
The main different between my project and the one provided by AWS is that it's possible to choose how many subnets can be created. Everything has been fully parametrised by using Terraform variables.
In terms of architecture, the application is a classic 3 tiers application where:
- The Frontend layer contains the public subnets, and it is where the internet facing ALB and the NAT gateway are deployed.
- The Appliction layer is where the ECS cluster and an EFS driver are located.
- The Database layer is where the RDS instance is deployed.
For this project, I kept things simple since both the ECS cluster and the DB share the same private subnets in multi AZs way. In a production environment, ECS and DB should be deployed in a dedicated and separate subnets with the NACL in place that will allow only the required traffic between the two subnets.
Segregating the subnets and the workload is required in order to adhere to the principals of zero trust and the AWS well architected framework. In terms of the HA, we have a single RDS instance. In a production environment is strongly advised to deploy the DB in multiple AZs and ideally, one or more read only replica so that the load can be evenly distributed.
Before executing the Terraform file, please perform below two actions
- Create an IAM role to be used by Terraform. The IAM role must contain the required permission in order to create the artefacts. Please update the IAM role in the tfvar file (aws_role)
- Create an S3 bucket that will contain the Terraform state. The S3 bucket configuration can be found in the "terraform-config.tf" file
- Create a file with the required variables. Please note; it is higly reccomanded to create a tfvars file for each environment. In the below example I am adding a tfvar file only for the DEV environment.
$ cat ./environments/dev/terraform.dev.tfvars
################################################################################
# Root
################################################################################
aws_target_region = "eu-west-2"
project_name = "wordpress"
aws_account_id = "<00000000000000>"
aws_role = "deploy-terraform-role"
account_name = "<myaccount_name>"
################################################################################
# network module
################################################################################
vpc_cidr_range = "10.0.0.0/16"
public_subnet_cidr_range = ["10.0.0.0/24", "10.0.1.0/24"]
private_subnet_cidr_range = ["10.0.2.0/24", "10.0.3.0/24"]
alb_port = 80
alb_target_type = "ip"
alb_protocol = "HTTP"
alb_health_check_port = 8080
################################################################################
# data module
################################################################################
db_port = 3306
db_allocated_storage = 20
db_name = "wordpress"
db_engine = "mysql"
db_engine_version = "5.7"
db_instance_class = "db.t3.micro"
db_username = "admin"
db_password = "password"
efs_creation_token = "efs-wordpress"
efs_encrypted = true
efs_throughput_mode = "bursting"
efs_performance_mode = "generalPurpose"
efs_path = "/bitnami"
################################################################################
# ecs-cluster module
################################################################################
container_name = "wordpress"
volume_name = "wordpress_volume"
container_port = 8080
image_name = "bitnami/wordpress"
container_path = "/bitnami/wordpress"
task_number = 2
$ terraform workspace new dev
$ terraform init
$ terraform plan -var-file=./environments/dev/terraform.dev.tfvars
$ terraform apply -var-file=./environments/dev/terraform.dev.tfvars
After Terraform has completed, the Wordpress application can be access at the following url:
The ALB value can be retrieve from the AWS console.
Please note that these are the default credentials and should be changed.
Username: user Password: bitnami
$ terraform destroy -var-file=./environments/dev/terraform.dev.tfvars
Name | Version |
---|---|
terraform | >= 1.3.0 |
aws | ~> 4.30 |
No providers.
Name | Source | Version |
---|---|---|
data | ./modules/data | n/a |
ecs-cluster | ./modules/ecs-cluster | n/a |
network | ./modules/network | n/a |
No resources.
Name | Description | Type | Default | Required |
---|---|---|---|---|
account_name | this is the account name where we want to deploy our application | string |
"" |
no |
alb_health_check_port | n/a | any |
n/a | yes |
alb_port | n/a | any |
n/a | yes |
alb_protocol | n/a | any |
n/a | yes |
alb_target_type | n/a | any |
n/a | yes |
aws_account_id | this is the account id where we want to deploy our application | string |
"" |
no |
aws_role | this is the role to be used in order to deploy our application | string |
"" |
no |
aws_target_region | this is the region where we want to deploy our application | string |
"" |
no |
container_name | n/a | any |
n/a | yes |
container_path | n/a | any |
n/a | yes |
container_port | n/a | any |
n/a | yes |
current_env | this is the environment(workspace) where we want to deploy the application | string |
"" |
no |
db_allocated_storage | n/a | any |
n/a | yes |
db_engine | n/a | any |
n/a | yes |
db_engine_version | n/a | any |
n/a | yes |
db_instance_class | n/a | any |
n/a | yes |
db_name | n/a | any |
n/a | yes |
db_password | n/a | any |
n/a | yes |
db_port | n/a | any |
n/a | yes |
db_username | n/a | any |
n/a | yes |
efs_creation_token | n/a | any |
n/a | yes |
efs_encrypted | n/a | any |
n/a | yes |
efs_path | n/a | any |
n/a | yes |
efs_performance_mode | n/a | any |
n/a | yes |
efs_throughput_mode | n/a | any |
n/a | yes |
image_name | n/a | any |
n/a | yes |
private_subnet_cidr_range | n/a | any |
n/a | yes |
project_name | n/a | any |
n/a | yes |
public_subnet_cidr_range | n/a | any |
n/a | yes |
task_number | n/a | any |
n/a | yes |
volume_name | n/a | any |
n/a | yes |
vpc_cidr_range | n/a | any |
n/a | yes |
No outputs.