Hello everyone!
How are you today? I hope you're doing great. I'm excited to learn Terraform, so I'm writing this to document my experience and notes.
My name is Bervianto Leo Pratama. I'm a Software Engineer who wants to know more DevOps world. I hope you will enjoy my article, also give advice and comment on my content. I'm not an expert on the DevOps world, especially IAC (Infrastructure as Code). I believe I still need to learn more about DevOps.
Preparation
You will need the tool (Terraform) if you want to try the code. You may download Terraform CLI here. Anyway, my Terraform CLI version is 1.11.7.
Prepare a User
Since I just explore and want to know more about Terraform and AWS. I'm using the highest privilege for now. I use AdministratorAccess. Please always use the least privilege for production use.
Additional
You may need to use the Terraform Cloud. When you use the Terraform Cloud, please use this guide. However, it's not required for now.
Let's Jump In
TLDR about my goal. I use Nginx
as my service. In addition, I use Amazon ECS Fargate and ALB (Application Load Balancer). In summary, I want to access my services using Load Balancer and use Nginx for sampling.
1. Prepare the main.tf
and add AWS as provider.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
Note: You may setup cloud state in there. When I'm exploring, I'm using local state. But, after that I migrate to use cloud state in my Github Repository.
2. Configure Our AWS Provider
provider "aws" {
alias = "ap-southeast-1"
region = "ap-southeast-1"
}
Note: Please configure with your desire region. I use ap-southeast-1 (Singapore).
3. Setup Networking
resource "aws_default_vpc" "my-personal-web" {
provider = aws.ap-southeast-1
tags = {
env = "dev"
}
}
resource "aws_default_subnet" "my-personal-web" {
provider = aws.ap-southeast-1
availability_zone = "ap-southeast-1a"
tags = {
env = "dev"
}
}
resource "aws_default_subnet" "my-personal-web-1" {
provider = aws.ap-southeast-1
availability_zone = "ap-southeast-1b"
tags = {
env = "dev"
}
}
resource "aws_security_group" "my-personal-web" {
provider = aws.ap-southeast-1
name = "allow_http"
description = "Allow HTTP inbound traffic"
vpc_id = aws_default_vpc.my-personal-web.id
ingress {
description = "Allow HTTP for all"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
Note: I use default vpc & subnet and config new security group to open port 80 only. Since, I will use nginx
as my services. You will need config vpc & subnet correctly for production use.
4. Configure Load Balancer
resource "aws_lb" "my-personal-web" {
provider = aws.ap-southeast-1
name = "my-personal-web-lb-tf"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.my-personal-web.id]
subnets = [aws_default_subnet.my-personal-web.id, aws_default_subnet.my-personal-web-1.id]
tags = {
env = "dev"
}
}
resource "aws_lb_target_group" "my-personal-web" {
provider = aws.ap-southeast-1
name = "tf-my-personal-web-lb-tg"
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = aws_default_vpc.my-personal-web.id
}
resource "aws_lb_listener" "my-personal-web" {
provider = aws.ap-southeast-1
load_balancer_arn = aws_lb.my-personal-web.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.my-personal-web.arn
}
}
Note: I just use port 80. Maybe, you will need 443 for production use.
5. Configure Amazon ECS
resource "aws_ecs_cluster" "my-personal-web" {
provider = aws.ap-southeast-1
name = "my-personal-web-api-cluster"
}
resource "aws_ecs_cluster_capacity_providers" "my-personal-web" {
provider = aws.ap-southeast-1
cluster_name = aws_ecs_cluster.my-personal-web.name
capacity_providers = ["FARGATE"]
}
resource "aws_ecs_task_definition" "my-personal-web" {
provider = aws.ap-southeast-1
family = "service"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = 1024
memory = 2048
container_definitions = jsonencode([
{
name = "my-personal-web-api"
image = "nginx"
cpu = 1024
memory = 2048
essential = true
portMappings = [
{
containerPort = 80
hostPort = 80
}
]
}
])
}
resource "aws_ecs_service" "my-personal-web" {
provider = aws.ap-southeast-1
name = "my-personal-web"
cluster = aws_ecs_cluster.my-personal-web.id
task_definition = aws_ecs_task_definition.my-personal-web.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = [aws_default_subnet.my-personal-web.id, aws_default_subnet.my-personal-web-1.id]
security_groups = [aws_security_group.my-personal-web.id]
assign_public_ip = true
}
load_balancer {
target_group_arn = aws_lb_target_group.my-personal-web.arn
container_name = "my-personal-web-api"
container_port = 80
}
tags = {
env = "dev"
}
}
Full Code
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
# Configure the AWS Provider
provider "aws" {
alias = "ap-southeast-1"
region = "ap-southeast-1"
}
resource "aws_default_vpc" "my-personal-web" {
provider = aws.ap-southeast-1
tags = {
env = "dev"
}
}
resource "aws_default_subnet" "my-personal-web" {
provider = aws.ap-southeast-1
availability_zone = "ap-southeast-1a"
tags = {
env = "dev"
}
}
resource "aws_default_subnet" "my-personal-web-1" {
provider = aws.ap-southeast-1
availability_zone = "ap-southeast-1b"
tags = {
env = "dev"
}
}
resource "aws_security_group" "my-personal-web" {
provider = aws.ap-southeast-1
name = "allow_http"
description = "Allow HTTP inbound traffic"
vpc_id = aws_default_vpc.my-personal-web.id
ingress {
description = "Allow HTTP for all"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_lb" "my-personal-web" {
provider = aws.ap-southeast-1
name = "my-personal-web-lb-tf"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.my-personal-web.id]
subnets = [aws_default_subnet.my-personal-web.id, aws_default_subnet.my-personal-web-1.id]
tags = {
env = "dev"
}
}
resource "aws_lb_target_group" "my-personal-web" {
provider = aws.ap-southeast-1
name = "tf-my-personal-web-lb-tg"
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = aws_default_vpc.my-personal-web.id
}
resource "aws_lb_listener" "my-personal-web" {
provider = aws.ap-southeast-1
load_balancer_arn = aws_lb.my-personal-web.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.my-personal-web.arn
}
}
resource "aws_ecs_cluster" "my-personal-web" {
provider = aws.ap-southeast-1
name = "my-personal-web-api-cluster"
}
resource "aws_ecs_cluster_capacity_providers" "my-personal-web" {
provider = aws.ap-southeast-1
cluster_name = aws_ecs_cluster.my-personal-web.name
capacity_providers = ["FARGATE"]
}
resource "aws_ecs_task_definition" "my-personal-web" {
provider = aws.ap-southeast-1
family = "service"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = 1024
memory = 2048
container_definitions = jsonencode([
{
name = "my-personal-web-api"
image = "nginx"
cpu = 1024
memory = 2048
essential = true
portMappings = [
{
containerPort = 80
hostPort = 80
}
]
}
])
}
resource "aws_ecs_service" "my-personal-web" {
provider = aws.ap-southeast-1
name = "my-personal-web"
cluster = aws_ecs_cluster.my-personal-web.id
task_definition = aws_ecs_task_definition.my-personal-web.arn
desired_count = 2
launch_type = "FARGATE"
network_configuration {
subnets = [aws_default_subnet.my-personal-web.id, aws_default_subnet.my-personal-web-1.id]
security_groups = [aws_security_group.my-personal-web.id]
assign_public_ip = true
}
load_balancer {
target_group_arn = aws_lb_target_group.my-personal-web.arn
container_name = "my-personal-web-api"
container_port = 80
}
tags = {
env = "dev"
}
}
Let's Provision It!
- Run
terraform init
. - Run
terraform plan
. You may check what's the changes in this step. - Run
terraform apply
. Typeyes
and Enter. - Wait until the deployment of all the resources is done. May take a long time.
- After finished and successful, try to access it with your public load balancer. As example, here is mine.
Thank you
Thank you for reading. I really appreciate when you read this long (because the code) article.
Top comments (0)