Skip to content

Instantly share code, notes, and snippets.

@20k-ultra
Created December 12, 2018 16:04
Show Gist options
  • Save 20k-ultra/579fb434d55a8a447b6beebca9acc335 to your computer and use it in GitHub Desktop.
Save 20k-ultra/579fb434d55a8a447b6beebca9acc335 to your computer and use it in GitHub Desktop.
/*====
Cloudwatch Log Group
======*/
resource "aws_cloudwatch_log_group" "qriket" {
name = "qriket"
tags {
Environment = "${var.environment}"
Application = "Qriket API"
}
}
/*====
ECR repository to store our Docker images
======*/
resource "aws_ecr_repository" "qriket_app" {
name = "${var.repository_name}"
}
/*====
ECS cluster
======*/
resource "aws_ecs_cluster" "cluster" {
name = "${var.environment}-ecs-cluster"
}
/*====
ECS task definitions
======*/
/* the task definition for the web service */
data "template_file" "web_task" {
template = "${file("${path.module}/tasks/web_task_definition.json")}"
vars {
image = "${aws_ecr_repository.qriket_app.repository_url}"
secret_key_base = "${var.secret_key_base}"
database_host = "${var.database_endpoint}"
database_user = "${var.database_username}"
database_pass = "${var.database_password}"
database_name = "${var.database_name}"
database_port = "5432"
redis_endpoint = "${var.redis_endpoint}"
redis_port = "${var.redis_port}"
log_group = "${aws_cloudwatch_log_group.qriket.name}"
}
}
resource "aws_ecs_task_definition" "web" {
family = "${var.environment}_web"
container_definitions = "${data.template_file.web_task.rendered}"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = "256"
memory = "512"
execution_role_arn = "${aws_iam_role.ecs_execution_role.arn}"
task_role_arn = "${aws_iam_role.ecs_execution_role.arn}"
}
/*====
App Load Balancer
======*/
resource "random_id" "target_group_sufix" {
byte_length = 2
}
/* security group for ALB */
resource "aws_security_group" "web_inbound_sg" {
name_prefix = "${var.environment}-web-inbound-sg"
description = "Allow HTTP from Anywhere into ALB"
vpc_id = "${var.vpc_id}"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 8
to_port = 0
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags {
Name = "${var.environment}-web-inbound-sg"
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_alb" "alb_qriket" {
name = "${var.environment}-alb-qriket"
subnets = ["${var.public_subnet_ids}"]
security_groups = ["${var.security_groups_ids}", "${aws_security_group.web_inbound_sg.id}"]
tags {
Name = "${var.environment}-alb-qriket"
Environment = "${var.environment}"
}
}
resource "aws_alb_target_group" "alb_target_group" {
name = "${var.environment}-alb-target-group-${random_id.target_group_sufix.hex}"
port = 80
protocol = "HTTP"
vpc_id = "${var.vpc_id}"
target_type = "ip"
health_check {
path = "/"
port = "80"
protocol = "HTTP"
healthy_threshold = 2
unhealthy_threshold = 2
interval = 5
timeout = 4
matcher = "200-308"
}
}
resource "aws_alb_listener" "qriket" {
load_balancer_arn = "${aws_alb.alb_qriket.arn}"
port = "443"
protocol = "HTTPS"
ssl_policy = "${var.ssl_policy}"
certificate_arn = "${var.certificate_arn}"
depends_on = ["aws_alb_target_group.alb_target_group"]
default_action {
target_group_arn = "${aws_alb_target_group.alb_target_group.arn}"
type = "forward"
}
lifecycle {
create_before_destroy = true
}
}
/*
* IAM service role
*/
data "aws_iam_policy_document" "ecs_service_role" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs.amazonaws.com"]
}
}
}
resource "aws_iam_role" "ecs_role" {
name = "ecs_role"
assume_role_policy = "${data.aws_iam_policy_document.ecs_service_role.json}"
}
data "aws_iam_policy_document" "ecs_service_policy" {
statement {
effect = "Allow"
resources = ["*"]
actions = [
"elasticloadbalancing:Describe*",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"ec2:Describe*",
"ec2:AuthorizeSecurityGroupIngress"
]
}
}
/* ecs service scheduler role */
resource "aws_iam_role_policy" "ecs_service_role_policy" {
name = "ecs_service_role_policy"
policy = "${data.aws_iam_policy_document.ecs_service_policy.json}"
role = "${aws_iam_role.ecs_role.id}"
}
/* role that the Amazon ECS container agent and the Docker daemon can assume */
resource "aws_iam_role" "ecs_execution_role" {
name = "ecs_task_execution_role"
assume_role_policy = "${file("${path.module}/policies/ecs-task-execution-role.json")}"
}
resource "aws_iam_role_policy" "ecs_execution_role_policy" {
name = "ecs_execution_role_policy"
policy = "${file("${path.module}/policies/ecs-execution-role-policy.json")}"
role = "${aws_iam_role.ecs_execution_role.id}"
}
/*====
ECS service
======*/
/* Security Group for ECS */
resource "aws_security_group" "ecs_service" {
vpc_id = "${var.vpc_id}"
name_prefix = "${var.environment}-ecs-service-sg"
description = "Allow egress from container"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 8
to_port = 0
protocol = "icmp"
cidr_blocks = ["0.0.0.0/0"]
}
tags {
Name = "${var.environment}-ecs-service-sg"
Environment = "${var.environment}"
}
lifecycle {
create_before_destroy = true
}
}
/* Simply specify the family to find the latest ACTIVE revision in that family */
data "aws_ecs_task_definition" "web" {
depends_on = ["aws_ecs_task_definition.web"]
task_definition = "${aws_ecs_task_definition.web.family}"
}
resource "aws_ecs_service" "web" {
name = "${var.environment}-web"
task_definition = "${aws_ecs_task_definition.web.family}:${max("${aws_ecs_task_definition.web.revision}", "${data.aws_ecs_task_definition.web.revision}")}"
desired_count = 2
launch_type = "FARGATE"
cluster = "${aws_ecs_cluster.cluster.id}"
depends_on = ["aws_iam_role_policy.ecs_service_role_policy"]
network_configuration {
security_groups = ["${var.security_groups_ids}", "${aws_security_group.ecs_service.id}"]
subnets = ["${var.subnets_ids}"]
}
load_balancer {
target_group_arn = "${aws_alb_target_group.alb_target_group.arn}"
container_name = "web"
container_port = "80"
}
depends_on = ["aws_alb_target_group.alb_target_group"]
}
/*====
Auto Scaling for ECS
======*/
resource "aws_iam_role" "ecs_autoscale_role" {
name = "${var.environment}_ecs_autoscale_role"
assume_role_policy = "${file("${path.module}/policies/ecs-autoscale-role.json")}"
}
resource "aws_iam_role_policy" "ecs_autoscale_role_policy" {
name = "ecs_autoscale_role_policy"
policy = "${file("${path.module}/policies/ecs-autoscale-role-policy.json")}"
role = "${aws_iam_role.ecs_autoscale_role.id}"
}
resource "aws_appautoscaling_target" "target" {
service_namespace = "ecs"
resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.web.name}"
scalable_dimension = "ecs:service:DesiredCount"
role_arn = "${aws_iam_role.ecs_autoscale_role.arn}"
min_capacity = "${var.min_capacity}"
max_capacity = "${var.max_capacity}"
}
resource "aws_appautoscaling_policy" "up" {
name = "${var.environment}_scale_up"
service_namespace = "ecs"
resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.web.name}"
scalable_dimension = "ecs:service:DesiredCount"
step_scaling_policy_configuration {
adjustment_type = "ChangeInCapacity"
cooldown = 60
metric_aggregation_type = "Maximum"
step_adjustment {
metric_interval_lower_bound = 0
scaling_adjustment = 1
}
}
depends_on = ["aws_appautoscaling_target.target"]
}
resource "aws_appautoscaling_policy" "down" {
name = "${var.environment}_scale_down"
service_namespace = "ecs"
resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.web.name}"
scalable_dimension = "ecs:service:DesiredCount"
step_scaling_policy_configuration {
adjustment_type = "ChangeInCapacity"
cooldown = 60
metric_aggregation_type = "Maximum"
step_adjustment {
metric_interval_lower_bound = 0
scaling_adjustment = -1
}
}
depends_on = ["aws_appautoscaling_target.target"]
}
/* metric used for auto scale */
resource "aws_cloudwatch_metric_alarm" "service_cpu_high" {
alarm_name = "${var.environment}_qriket_web_cpu_utilization_high"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/ECS"
period = "60"
statistic = "Maximum"
threshold = "85"
dimensions {
ClusterName = "${aws_ecs_cluster.cluster.name}"
ServiceName = "${aws_ecs_service.web.name}"
}
alarm_actions = ["${aws_appautoscaling_policy.up.arn}"]
ok_actions = ["${aws_appautoscaling_policy.down.arn}"]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment