Moved to the blog.
Last active
February 11, 2022 17:18
-
-
Save okelet/2b3364fa18ce74f39b43b6ce8f31cccc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
terraform { | |
required_providers { | |
aws = { | |
source = "hashicorp/aws" | |
} | |
} | |
} | |
data "aws_region" "current" { | |
} | |
data "aws_availability_zones" "available" { | |
state = "available" | |
} | |
variable "key_pair" { | |
type = string | |
default = null | |
} | |
variable "prefix" { | |
type = string | |
default = "ecs_fargate_exec_test" | |
} | |
locals { | |
ecs_service_name = "echo" | |
vpc_cidr = "192.168.22.0/24" | |
} | |
# https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest | |
module "vpc" { | |
source = "terraform-aws-modules/vpc/aws" | |
name = "${var.prefix}-vpc" | |
cidr = local.vpc_cidr | |
azs = slice(data.aws_availability_zones.available.names, 0, 2) | |
private_subnets = [cidrsubnet(local.vpc_cidr, 4, 0), cidrsubnet(local.vpc_cidr, 4, 1)] | |
public_subnets = [cidrsubnet(local.vpc_cidr, 4, 2), cidrsubnet(local.vpc_cidr, 4, 3)] | |
enable_nat_gateway = true | |
single_nat_gateway = true | |
enable_dns_hostnames = true | |
enable_dns_support = true | |
} | |
data "aws_ami" "amazon_linux_2" { | |
most_recent = true | |
owners = ["amazon"] | |
filter { | |
name = "name" | |
values = ["amzn2-ami-hvm-*-x86_64-ebs"] | |
} | |
} | |
resource "aws_security_group" "allow_all" { | |
name = "${var.prefix}_allow_all" | |
vpc_id = module.vpc.vpc_id | |
ingress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "ALL" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "ALL" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
} | |
resource "aws_security_group" "allow_ssh" { | |
name = "${var.prefix}_allow_ssh" | |
vpc_id = module.vpc.vpc_id | |
ingress { | |
from_port = 22 | |
to_port = 22 | |
protocol = "tcp" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "ALL" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
} | |
resource "aws_security_group" "allow_http_80" { | |
name = "${var.prefix}_allow_http_80" | |
vpc_id = module.vpc.vpc_id | |
ingress { | |
from_port = 80 | |
to_port = 80 | |
protocol = "tcp" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "ALL" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
} | |
resource "aws_security_group" "allow_http_8080" { | |
name = "${var.prefix}_allow_http_8080" | |
vpc_id = module.vpc.vpc_id | |
ingress { | |
from_port = 8080 | |
to_port = 8080 | |
protocol = "tcp" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
egress { | |
from_port = 0 | |
to_port = 0 | |
protocol = "ALL" | |
cidr_blocks = ["0.0.0.0/0"] | |
} | |
} | |
resource "aws_instance" "bastion" { | |
ami = data.aws_ami.amazon_linux_2.id | |
instance_type = "t3.micro" | |
key_name = var.key_pair | |
user_data = <<-EOF | |
#!/bin/bash | |
amazon-linux-extras install nginx1 -y | |
systemctl enable nginx | |
cp /usr/share/nginx/html/index.html{,.old} | |
echo "Hello from $(hostname)" > /usr/share/nginx/html/index.html | |
systemctl start nginx | |
EOF | |
associate_public_ip_address = true | |
subnet_id = module.vpc.public_subnets[0] | |
vpc_security_group_ids = [aws_security_group.allow_ssh.id, aws_security_group.allow_http_80.id] | |
tags = { | |
Name = "${var.prefix}_bastion" | |
} | |
} | |
resource "aws_lb" "alb" { | |
name = replace(replace("${var.prefix}_alb", "_", "-"), "/[^a-zA-Z0-9-]/", "") | |
load_balancer_type = "application" | |
security_groups = [aws_security_group.allow_http_80.id] | |
subnets = module.vpc.public_subnets | |
} | |
resource "aws_lb_listener" "http" { | |
load_balancer_arn = aws_lb.alb.arn | |
port = "80" | |
protocol = "HTTP" | |
default_action { | |
type = "fixed-response" | |
fixed_response { | |
content_type = "text/html" | |
message_body = "<html><body><p>Nothing yet here; try <a href=\"/echo/\">here</a>.</p></body></html>\n" | |
status_code = "404" | |
} | |
} | |
} | |
resource "aws_lb_target_group" "tg" { | |
name = replace(replace("${var.prefix}_${local.ecs_service_name}", "_", "-"), "/[^a-zA-Z0-9-]/", "") | |
port = 80 | |
protocol = "HTTP" | |
target_type = "ip" | |
vpc_id = module.vpc.vpc_id | |
deregistration_delay = 5 | |
} | |
resource "aws_lb_listener_rule" "static" { | |
listener_arn = aws_lb_listener.http.arn | |
priority = 100 | |
action { | |
type = "forward" | |
target_group_arn = aws_lb_target_group.tg.arn | |
} | |
condition { | |
path_pattern { | |
values = ["/${local.ecs_service_name}/*"] | |
} | |
} | |
} | |
resource "aws_ecs_cluster" "cluster" { | |
name = "${var.prefix}_ecs_cluster" | |
capacity_providers = ["FARGATE", "FARGATE_SPOT"] | |
default_capacity_provider_strategy { | |
capacity_provider = "FARGATE_SPOT" | |
} | |
setting { | |
name = "containerInsights" | |
value = "enabled" | |
} | |
} | |
data "aws_iam_policy_document" "task_role_assume_role_policy" { | |
statement { | |
actions = ["sts:AssumeRole"] | |
principals { | |
type = "Service" | |
identifiers = ["ecs-tasks.amazonaws.com"] | |
} | |
} | |
} | |
resource "aws_iam_role" "task_role" { | |
name = "${var.prefix}_task_role" | |
assume_role_policy = data.aws_iam_policy_document.task_role_assume_role_policy.json | |
} | |
resource "aws_iam_role_policy" "task_policy" { | |
name = "${var.prefix}_task_policy" | |
role = aws_iam_role.task_role.id | |
policy = jsonencode({ | |
"Version" = "2012-10-17" | |
"Statement" = [ | |
{ | |
"Effect" = "Allow" | |
"Action" = [ | |
"ssmmessages:CreateControlChannel", | |
"ssmmessages:CreateDataChannel", | |
"ssmmessages:OpenControlChannel", | |
"ssmmessages:OpenDataChannel" | |
] | |
"Resource" = "*" | |
} | |
] | |
}) | |
} | |
resource "aws_iam_role" "task_execution_role" { | |
name = "${var.prefix}_task_execution_role" | |
assume_role_policy = jsonencode({ | |
"Version" = "2012-10-17" | |
"Statement" = [ | |
{ | |
"Action" = "sts:AssumeRole" | |
"Principal" = { | |
"Service" = "ecs-tasks.amazonaws.com" | |
} | |
"Effect" = "Allow" | |
} | |
] | |
}) | |
} | |
resource "aws_iam_role_policy_attachment" "task_execution_role" { | |
role = aws_iam_role.task_execution_role.name | |
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" | |
} | |
resource "aws_iam_role_policy_attachment" "task_execution_role_attachment_CloudWatchFullAccess" { | |
role = aws_iam_role.task_execution_role.name | |
policy_arn = "arn:aws:iam::aws:policy/CloudWatchFullAccess" | |
} | |
resource "aws_cloudwatch_log_group" "log_group" { | |
name = "/ecs/clusters/${aws_ecs_cluster.cluster.name}/services/${local.ecs_service_name}" | |
} | |
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition | |
resource "aws_ecs_task_definition" "task_def" { | |
family = "${var.prefix}_${local.ecs_service_name}" | |
network_mode = "awsvpc" | |
requires_compatibilities = ["EC2", "FARGATE"] | |
cpu = 256 | |
memory = 512 | |
execution_role_arn = aws_iam_role.task_execution_role.arn | |
task_role_arn = aws_iam_role.task_role.arn | |
container_definitions = jsonencode([ | |
{ | |
name = "echo" | |
image = "mendhak/http-https-echo:19" | |
essential = true | |
portMappings = [ | |
{ | |
containerPort = 8080 | |
hostPort = 8080 | |
} | |
], | |
"linuxParameters" : { | |
"initProcessEnabled" : true | |
}, | |
"logConfiguration" = { | |
"logDriver" = "awslogs" | |
"options" = { | |
"awslogs-group" = aws_cloudwatch_log_group.log_group.name | |
"awslogs-region" = data.aws_region.current.name | |
"awslogs-stream-prefix" = "ecs" | |
} | |
} | |
} | |
]) | |
} | |
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service | |
resource "aws_ecs_service" "service" { | |
name = "${var.prefix}_${local.ecs_service_name}" | |
cluster = aws_ecs_cluster.cluster.id | |
task_definition = aws_ecs_task_definition.task_def.arn | |
desired_count = 2 | |
enable_execute_command = true | |
network_configuration { | |
subnets = module.vpc.private_subnets | |
security_groups = [aws_security_group.allow_http_8080.id] | |
} | |
load_balancer { | |
target_group_arn = aws_lb_target_group.tg.arn | |
container_name = "echo" | |
container_port = 8080 | |
} | |
lifecycle { | |
ignore_changes = [desired_count] | |
} | |
capacity_provider_strategy { | |
capacity_provider = "FARGATE_SPOT" | |
weight = 1 | |
} | |
} | |
resource "aws_appautoscaling_target" "target" { | |
max_capacity = 5 | |
min_capacity = 1 | |
resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.service.name}" | |
scalable_dimension = "ecs:service:DesiredCount" | |
service_namespace = "ecs" | |
} | |
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy | |
resource "aws_appautoscaling_policy" "memory" { | |
name = "${var.prefix}_memory" | |
policy_type = "TargetTrackingScaling" | |
resource_id = aws_appautoscaling_target.target.resource_id | |
scalable_dimension = aws_appautoscaling_target.target.scalable_dimension | |
service_namespace = aws_appautoscaling_target.target.service_namespace | |
target_tracking_scaling_policy_configuration { | |
predefined_metric_specification { | |
predefined_metric_type = "ECSServiceAverageMemoryUtilization" | |
} | |
target_value = 80 | |
} | |
} | |
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy | |
resource "aws_appautoscaling_policy" "cpu" { | |
name = "${var.prefix}_cpu" | |
policy_type = "TargetTrackingScaling" | |
resource_id = aws_appautoscaling_target.target.resource_id | |
scalable_dimension = aws_appautoscaling_target.target.scalable_dimension | |
service_namespace = aws_appautoscaling_target.target.service_namespace | |
target_tracking_scaling_policy_configuration { | |
predefined_metric_specification { | |
predefined_metric_type = "ECSServiceAverageCPUUtilization" | |
} | |
target_value = 60 | |
} | |
} | |
output "cluster_name" { | |
value = aws_ecs_cluster.cluster.name | |
} | |
output "service_name" { | |
value = aws_ecs_service.service.name | |
} | |
output "lb_addr" { | |
value = aws_lb.alb.dns_name | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment