Skip to content

Commit 8bc4577

Browse files
committed
add terraform ecs
1 parent 3a1742e commit 8bc4577

File tree

9 files changed

+1432
-0
lines changed

9 files changed

+1432
-0
lines changed

GitLab/gitlab-ci-share-artifact.yml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
image: ubuntu:18.04
2+
3+
stages:
4+
- build_stage
5+
- test_stage
6+
- deploy_stage
7+
8+
build:
9+
stage: build_stage
10+
script:
11+
- echo "building..." >> ./build_result.txt
12+
artifacts:
13+
paths:
14+
- build_result.txt
15+
expire_in: 1 week
16+
17+
unit_test:
18+
stage: test_stage
19+
script:
20+
- ls
21+
- cat build_result.txt
22+
- cp build_result.txt unittest_result.txt
23+
- echo "unit testing..." >> ./unittest_result.txt
24+
artifacts:
25+
paths:
26+
- unittest_result.txt
27+
expire_in: 1 week
28+
29+
integration_test:
30+
stage: test_stage
31+
script:
32+
- ls
33+
- cat build_result.txt
34+
- cp build_result.txt integration_test_result.txt
35+
- echo "integration testing..." >> ./integration_test_result.txt
36+
artifacts:
37+
paths:
38+
- integration_test_result.txt
39+
expire_in: 1 week
40+
41+
deploy:
42+
stage: deploy_stage
43+
script:
44+
- ls
45+
- cat build_result.txt
46+
- cat unittest_result.txt
47+
- cat integration_test_result.txt

IaC/terraform-fargate/main.tf.sample

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# * Part 1 - Setup.
2+
locals {
3+
container_name = "hello-world-container"
4+
container_port = 8080 # ! Must be same port from our Dockerfile that we EXPOSE
5+
example = "3-tier-ecs-terraform-aws-modules"
6+
}
7+
8+
provider "aws" {
9+
region = "us-east-1"
10+
11+
default_tags {
12+
tags = { example = local.example }
13+
}
14+
}
15+
16+
# Retrieve the default VPC ID
17+
data "aws_vpc" "default" {
18+
default = true
19+
}
20+
21+
# Retrieve the default subnets
22+
data "aws_subnets" "default" {
23+
filter {
24+
name = "vpc-id"
25+
values = [data.aws_vpc.default.id]
26+
}
27+
}
28+
29+
# Retrieve the default security group of the default VPC
30+
data "aws_security_group" "default" {
31+
name = "default"
32+
vpc_id = data.aws_vpc.default.id
33+
}
34+
35+
36+
data "aws_subnet" "default" {
37+
for_each = toset(data.aws_subnets.default.ids)
38+
id = each.value
39+
}
40+
41+
42+
# Extract the subnet IDs as a list
43+
locals {
44+
subnet_ids = values(data.aws_subnet.default)[*].id
45+
}
46+
47+
48+
# * Part 2 - Create application load balancer
49+
module "alb" {
50+
source = "terraform-aws-modules/alb/aws"
51+
version = "~> 8.4.0"
52+
53+
load_balancer_type = "application"
54+
security_groups = [data.aws_security_group.default.id]
55+
# subnets = [data.aws_subnet.default.id]
56+
subnets = local.subnet_ids # Use the extracted subnet IDs list
57+
vpc_id = data.aws_vpc.default.id
58+
59+
security_group_rules = {
60+
ingress_all_http = {
61+
type = "ingress"
62+
from_port = 80
63+
to_port = 80
64+
protocol = "TCP"
65+
description = "HTTP web traffic"
66+
cidr_blocks = ["0.0.0.0/0"]
67+
}
68+
egress_all = {
69+
type = "egress"
70+
from_port = 0
71+
to_port = 0
72+
protocol = "-1"
73+
cidr_blocks = ["0.0.0.0/0"]
74+
}
75+
}
76+
77+
http_tcp_listeners = [
78+
{
79+
# ! Defaults to "forward" action for "target group"
80+
# ! at index = 0 in "the target_groups" input below.
81+
port = 80
82+
protocol = "HTTP"
83+
target_group_index = 0
84+
}
85+
]
86+
87+
target_groups = [
88+
{
89+
backend_port = local.container_port
90+
backend_protocol = "HTTP"
91+
target_type = "ip"
92+
}
93+
]
94+
}
95+
96+
# * Step 5 - Create our ECS Cluster.
97+
module "ecs" {
98+
source = "terraform-aws-modules/ecs/aws"
99+
version = "~> 4.1.3"
100+
101+
cluster_name = local.example
102+
103+
# * Allocate 20% capacity to FARGATE and then split
104+
# * the remaining 80% capacity 50/50 between FARGATE
105+
# * and FARGATE_SPOT.
106+
fargate_capacity_providers = {
107+
FARGATE = {
108+
default_capacity_provider_strategy = {
109+
base = 20
110+
weight = 50
111+
}
112+
}
113+
FARGATE_SPOT = {
114+
default_capacity_provider_strategy = {
115+
weight = 50
116+
}
117+
}
118+
}
119+
}
120+
121+
# * Step 6 - Create our ECS Task Definition
122+
data "aws_iam_policy_document" "this" {
123+
version = "2012-10-17"
124+
125+
statement {
126+
actions = ["sts:AssumeRole"]
127+
effect = "Allow"
128+
129+
principals {
130+
identifiers = ["ecs-tasks.amazonaws.com"]
131+
type = "Service"
132+
}
133+
}
134+
}
135+
resource "aws_iam_role" "this" { assume_role_policy = data.aws_iam_policy_document.this.json }
136+
resource "aws_iam_role_policy_attachment" "this" {
137+
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
138+
role = resource.aws_iam_role.this.name
139+
}
140+
141+
resource "aws_ecs_task_definition" "this" {
142+
container_definitions = jsonencode([{
143+
environment: [
144+
{ name = "MY_INPUT_ENV_VAR", value = "terraform-modified-env-var" }
145+
],
146+
essential = true,
147+
image = "dockerbogo/docker-nginx-hello-world",
148+
name = local.container_name,
149+
portMappings = [{ containerPort = local.container_port }],
150+
}])
151+
cpu = 256
152+
execution_role_arn = resource.aws_iam_role.this.arn
153+
family = "family-of-${local.example}-tasks"
154+
memory = 512
155+
network_mode = "awsvpc"
156+
requires_compatibilities = ["FARGATE"]
157+
}
158+
159+
# Step 6 - Create ECS Autoscaling Policy
160+
resource "aws_appautoscaling_policy" "ecs_autoscale_policy" {
161+
name = "${local.example}-ecs-autoscale-policy"
162+
service_namespace = "ecs"
163+
scalable_dimension = "ecs:service:DesiredCount"
164+
resource_id = "service/${module.ecs.cluster_name}/${aws_ecs_service.this.name}"
165+
policy_type = "TargetTrackingScaling"
166+
167+
target_tracking_scaling_policy_configuration {
168+
target_value = 70 # Target CPU utilization
169+
predefined_metric_specification {
170+
predefined_metric_type = "ECSServiceAverageCPUUtilization"
171+
172+
}
173+
}
174+
}
175+
176+
# Create ECS Scalable Target for Autoscaling
177+
resource "aws_appautoscaling_target" "ecs_scalable_target" {
178+
max_capacity = 3 # Maximum desired count for autoscaling
179+
min_capacity = 1 # Minimum desired count for autoscaling
180+
resource_id = "service/${module.ecs.cluster_name}/${aws_ecs_service.this.name}"
181+
scalable_dimension = "ecs:service:DesiredCount"
182+
service_namespace = "ecs"
183+
}
184+
185+
186+
# * Step 7 - Run our application.
187+
resource "aws_ecs_service" "this" {
188+
cluster = module.ecs.cluster_id
189+
desired_count = 2
190+
launch_type = "FARGATE"
191+
name = "${local.example}-service"
192+
task_definition = resource.aws_ecs_task_definition.this.arn
193+
194+
# depends_on = [aws_appautoscaling_target.ecs_scalable_target] # Ensure scalable target is created first
195+
196+
lifecycle {
197+
ignore_changes = [desired_count] # Allow external changes to happen without Terraform conflicts, particularly around auto-scaling.
198+
}
199+
200+
load_balancer {
201+
container_name = local.container_name
202+
container_port = local.container_port
203+
target_group_arn = module.alb.target_group_arns[0]
204+
}
205+
206+
network_configuration {
207+
security_groups = [data.aws_security_group.default.id]
208+
subnets = local.subnet_ids
209+
assign_public_ip = true
210+
}
211+
}
212+
213+
# * Step 8 - See our application working.
214+
# * Output the URL of our Application Load Balancer so that we can connect to
215+
# * our application running inside ECS once it is up and running.
216+
output "lb_url" { value = "http://${module.alb.lb_dns_name}" }
217+
# Output
218+
# output "subnets_out" {
219+
# value = data.aws_subnet.default
220+
# }
221+
222+
# output "subnet_cidr_blocks" {
223+
# value = [for s in data.aws_subnet.default : s.cidr_block]
224+
# }
225+
226+
### References
227+
### https://github.com/1Mill/example-terraform-ecs

0 commit comments

Comments
 (0)