Skip to content

Commit c877056

Browse files
Merge pull request #16 from tryretool/roberto/workflows-ecs-module-v0
v0 workflows terraform modules
2 parents 0171107 + eae3ea3 commit c877056

File tree

15 files changed

+2028
-0
lines changed

15 files changed

+2028
-0
lines changed

modules/aws_ecs/README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# AWS ECS + EC2 Module
2+
3+
This module deploys an ECS cluster with autoscaling group of EC2 instances.
4+
5+
# Usage
6+
7+
1. Directly use our module in your existing Terraform configuration and provide the required variables
8+
9+
```
10+
module "retool" {
11+
source = "[email protected]:tryretool/retool-terraform.git//modules/aws_ecs"
12+
13+
aws_region = "<your-aws-region>"
14+
vpc_id = "<your-vpc-id>"
15+
subnet_ids = [
16+
"<your-subnet-1>",
17+
"<your-subnet-2>"
18+
]
19+
ssh_key_name = "<your-key-pair>"
20+
ecs_retool_image = "<desired-retool-version>"
21+
workflows_enabled = true
22+
23+
# Additional configuration
24+
...
25+
}
26+
```
27+
28+
2. Run `terraform init` to install all requirements for the module.
29+
30+
3. Replace `ecs_retool_image` with your desired [Retool Version](https://docs.retool.com/docs/updating-retool-on-premise#retool-release-versions). The format should be `tryretool/backend:X.Y.Z`, where `X.Y.Z` is your desired version number. Version 2.111 or greater is needed for Workflows (2.117 or later strongly recommended for performance improvements).
31+
32+
4. Ensure that the default security settings in `security.tf` matches your specifications. If you need to tighten down access, pass in custom ingress and egress rules into `container_egress_rules`, `container_ingress_rules`, `alb_egress_rules`, and `alb_ingress_rules`.
33+
34+
5. Check through `variables.tf` for any other input variables that may be required. Set `launch_type` to `EC2` if not using Fargate.
35+
36+
6. Run `terraform plan` to view all planned changes to your account.
37+
38+
7. Run `terraform apply` to apply the changes and deploy Retool.
39+
40+
8. You should now find a Load Balancer in your AWS EC2 Console associated with the deployment. The instance address should now be running Retool.
41+
42+
## Common Configuration
43+
44+
### Instances
45+
46+
**EC2 Instance Size**
47+
To configure the EC instance size, set the `instance_type` input variable (e.g. `t2.large`).
48+
49+
**RDS Instance Class**
50+
To configure the RDS instance class, set the `instance_class` input variable (e.g. `db.m6g.large`).
51+
52+
## Advanced Configuration
53+
**Bring your own Temporal Cluster**
54+
To configure your own Temporal cluster, set the `use_existing_temporal_cluster` to `true` and configure your Temporal Cluster's Frontend service endpoint (and TLS if needed) using `temporal_cluster_config`. If configuring mTLS, we expect the cert and key values to be base64-encoded strings.
55+
### Security Groups
56+
57+
To customize the ingress and egress rules on the security groups, you can override specific input variable defaults.
58+
59+
- `container_ingress_rules` controls the inbound rules for EC2 instances in autoscaling group or ECS services in Fargate
60+
- `container_egress_rules` controls the outbound rules for EC2 instances in autoscaling group or ECS services in Fargate
61+
- `alb_ingress_rules` controls the inbound rules for the Load Balancer
62+
- `alb_egress_rules` controls the outbound rules for the Load Balancer
63+
64+
```
65+
container_ingress_rules = [
66+
{
67+
description = "Global HTTP inbound"
68+
from_port = "80"
69+
to_port = "80"
70+
protocol = "tcp"
71+
cidr_blocks = ["0.0.0.0/0"]
72+
ipv6_cidr_blocks = ["::/0"]
73+
},
74+
{
75+
description = "Global HTTPS inbound"
76+
from_port = "443"
77+
to_port = "443"
78+
protocol = "tcp"
79+
cidr_blocks = ["0.0.0.0/0"]
80+
ipv6_cidr_blocks = ["::/0"]
81+
},
82+
{
83+
description = "SSH inbound"
84+
from_port = "22"
85+
to_port = "22"
86+
protocol = "tcp"
87+
cidr_blocks = ["0.0.0.0/0"]
88+
ipv6_cidr_blocks = ["::/0"]
89+
}
90+
]
91+
92+
container_egress_rules = [
93+
{
94+
description = "Global outbound"
95+
from_port = "0"
96+
to_port = "0"
97+
protocol = "-1"
98+
cidr_blocks = ["0.0.0.0/0"]
99+
ipv6_cidr_blocks = ["::/0"]
100+
}
101+
]
102+
```
103+
104+
### Environment Variables
105+
106+
To add additional [Retool environment variables](https://docs.retool.com/docs/environment-variables) to your deployment, populate the `additional_env_vars` input variable into the module.
107+
108+
NOTE: The `additional_env_vars` will only work as type `map(string)`. Convert all booleans and numbers into strings, e.g.
109+
110+
```
111+
additional_env_vars = [
112+
{
113+
name = "DISABLE_GIT_SYNCING"
114+
value = "true"
115+
}
116+
]
117+
```

modules/aws_ecs/ecs.tf

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
resource "aws_ecs_cluster" "this" {
2+
name = "${var.deployment_name}-ecs"
3+
4+
setting {
5+
name = "containerInsights"
6+
value = var.ecs_insights_enabled
7+
}
8+
}
9+
10+
# Fargate capacity provider
11+
resource "aws_ecs_cluster_capacity_providers" "this" {
12+
cluster_name = aws_ecs_cluster.this.name
13+
14+
capacity_providers = var.launch_type == "FARGATE" ? ["FARGATE"] : [aws_ecs_capacity_provider.this[0].name]
15+
16+
default_capacity_provider_strategy {
17+
base = 1
18+
weight = 100
19+
capacity_provider = var.launch_type == "FARGATE" ? "FARGATE" : aws_ecs_capacity_provider.this[0].name
20+
}
21+
}
22+
23+
# Required setup for EC2 instances (if not using Fargate)
24+
data "aws_ami" "this" {
25+
most_recent = true # get the latest version
26+
name_regex = "^amzn2-ami-ecs-hvm-\\d\\.\\d\\.\\d{8}-x86_64-ebs$"
27+
28+
filter {
29+
name = "virtualization-type"
30+
values = [
31+
"hvm"
32+
]
33+
}
34+
35+
owners = [
36+
"amazon" # only official images
37+
]
38+
}
39+
40+
resource "aws_launch_configuration" "this" {
41+
count = var.launch_type == "EC2" ? 1 : 0
42+
name_prefix = "${var.deployment_name}-ecs-launch-configuration-"
43+
image_id = data.aws_ami.this.id
44+
instance_type = var.instance_type # e.g. t2.medium
45+
46+
enable_monitoring = true
47+
associate_public_ip_address = true
48+
49+
# This user data represents a collection of “scripts” that will be executed the first time the machine starts.
50+
# This specific example makes sure the EC2 instance is automatically attached to the ECS cluster that we create earlier
51+
# and marks the instance as purchased through the Spot pricing
52+
user_data = <<-EOF
53+
#!/bin/bash
54+
echo ECS_CLUSTER=${var.deployment_name}-ecs >> /etc/ecs/ecs.config
55+
EOF
56+
57+
# We’ll see security groups later
58+
security_groups = [
59+
aws_security_group.containers.id
60+
]
61+
62+
# If you want to SSH into the instance and manage it directly:
63+
# 1. Make sure this key exists in the AWS EC2 dashboard
64+
# 2. Make sure your local SSH agent has it loaded
65+
# 3. Make sure the EC2 instances are launched within a public subnet (are accessible from the internet)
66+
key_name = var.ssh_key_name
67+
68+
# Allow the EC2 instances to access AWS resources on your behalf, using this instance profile and the permissions defined there
69+
iam_instance_profile = aws_iam_instance_profile.ec2[0].arn
70+
71+
lifecycle {
72+
create_before_destroy = true
73+
}
74+
}
75+
76+
resource "aws_autoscaling_group" "this" {
77+
count = var.launch_type == "EC2" ? 1 : 0
78+
name = "${var.deployment_name}-autoscaling-group"
79+
max_size = var.max_instance_count
80+
min_size = var.min_instance_count
81+
desired_capacity = var.min_instance_count
82+
vpc_zone_identifier = var.subnet_ids
83+
launch_configuration = aws_launch_configuration.this[0].name
84+
85+
default_cooldown = 30
86+
health_check_grace_period = 30
87+
88+
termination_policies = [
89+
"OldestInstance"
90+
]
91+
92+
tag {
93+
key = "AmazonECSManaged"
94+
value = ""
95+
propagate_at_launch = true
96+
}
97+
98+
tag {
99+
key = "Cluster"
100+
value = "${var.deployment_name}-ecs"
101+
propagate_at_launch = true
102+
}
103+
104+
tag {
105+
key = "Name"
106+
value = "${var.deployment_name}-ec2-instance"
107+
propagate_at_launch = true
108+
}
109+
110+
lifecycle {
111+
create_before_destroy = true
112+
}
113+
}
114+
115+
# Attach an autoscaling policy to the spot cluster to target 70% MemoryReservation on the ECS cluster.
116+
resource "aws_autoscaling_policy" "this" {
117+
count = var.launch_type == "EC2" ? 1 : 0
118+
name = "${var.deployment_name}-ecs-scale-policy"
119+
policy_type = "TargetTrackingScaling"
120+
adjustment_type = "ChangeInCapacity"
121+
autoscaling_group_name = aws_autoscaling_group.this[0].name
122+
123+
target_tracking_configuration {
124+
customized_metric_specification {
125+
metric_dimension {
126+
name = "ClusterName"
127+
value = "${var.deployment_name}-ecs"
128+
}
129+
metric_name = "MemoryReservation"
130+
namespace = "AWS/ECS"
131+
statistic = "Average"
132+
}
133+
target_value = var.autoscaling_memory_reservation_target
134+
}
135+
}
136+
137+
resource "aws_ecs_capacity_provider" "this" {
138+
count = var.launch_type == "EC2" ? 1 : 0
139+
name = "${var.deployment_name}-ecs-capacity-provider"
140+
141+
auto_scaling_group_provider {
142+
auto_scaling_group_arn = aws_autoscaling_group.this[0].arn
143+
}
144+
}

modules/aws_ecs/loadbalancers.tf

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
resource "aws_lb" "this" {
2+
name = "${var.deployment_name}-alb"
3+
idle_timeout = var.alb_idle_timeout
4+
5+
security_groups = [aws_security_group.alb.id]
6+
subnets = var.subnet_ids
7+
}
8+
9+
resource "aws_lb_listener" "this" {
10+
load_balancer_arn = aws_lb.this.arn
11+
port = 80
12+
protocol = "HTTP"
13+
14+
default_action {
15+
type = "forward"
16+
target_group_arn = aws_lb_target_group.this.arn
17+
}
18+
}
19+
20+
resource "aws_lb_listener_rule" "this" {
21+
listener_arn = aws_lb_listener.this.arn
22+
priority = 1
23+
24+
action {
25+
type = "forward"
26+
target_group_arn = aws_lb_target_group.this.arn
27+
}
28+
29+
condition {
30+
path_pattern {
31+
values = ["/"]
32+
}
33+
}
34+
}
35+
36+
resource "aws_lb_target_group" "this" {
37+
name = "${var.deployment_name}-target"
38+
vpc_id = var.vpc_id
39+
deregistration_delay = 30
40+
port = 3000
41+
protocol = "HTTP"
42+
target_type = var.launch_type == "FARGATE" ? "ip" : "instance"
43+
44+
health_check {
45+
interval = 61
46+
path = "/api/checkHealth"
47+
protocol = "HTTP"
48+
timeout = 60
49+
healthy_threshold = 3
50+
unhealthy_threshold = 2
51+
}
52+
}

0 commit comments

Comments
 (0)