mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-10-08 00:02:27 +00:00
docs: AWS ECS terraform deploy (#2980)
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
.terraform/
|
||||
.env
|
||||
terraform.tfstate*
|
||||
@@ -0,0 +1,25 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/aws" {
|
||||
version = "4.67.0"
|
||||
constraints = "~> 4.16"
|
||||
hashes = [
|
||||
"h1:5Zfo3GfRSWBaXs4TGQNOflr1XaYj6pRnVJLX5VAjFX4=",
|
||||
"zh:0843017ecc24385f2b45f2c5fce79dc25b258e50d516877b3affee3bef34f060",
|
||||
"zh:19876066cfa60de91834ec569a6448dab8c2518b8a71b5ca870b2444febddac6",
|
||||
"zh:24995686b2ad88c1ffaa242e36eee791fc6070e6144f418048c4ce24d0ba5183",
|
||||
"zh:4a002990b9f4d6d225d82cb2fb8805789ffef791999ee5d9cb1fef579aeff8f1",
|
||||
"zh:559a2b5ace06b878c6de3ecf19b94fbae3512562f7a51e930674b16c2f606e29",
|
||||
"zh:6a07da13b86b9753b95d4d8218f6dae874cf34699bca1470d6effbb4dee7f4b7",
|
||||
"zh:768b3bfd126c3b77dc975c7c0e5db3207e4f9997cf41aa3385c63206242ba043",
|
||||
"zh:7be5177e698d4b547083cc738b977742d70ed68487ce6f49ecd0c94dbf9d1362",
|
||||
"zh:8b562a818915fb0d85959257095251a05c76f3467caa3ba95c583ba5fe043f9b",
|
||||
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
|
||||
"zh:9c385d03a958b54e2afd5279cd8c7cbdd2d6ca5c7d6a333e61092331f38af7cf",
|
||||
"zh:b3ca45f2821a89af417787df8289cb4314b273d29555ad3b2a5ab98bb4816b3b",
|
||||
"zh:da3c317f1db2469615ab40aa6baba63b5643bae7110ff855277a1fb9d8eb4f2c",
|
||||
"zh:dc6430622a8dc5cdab359a8704aec81d3825ea1d305bbb3bbd032b1c6adfae0c",
|
||||
"zh:fac0d2ddeadf9ec53da87922f666e1e73a603a611c57bcbc4b86ac2821619b1d",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
Deploying Windmill on AWS ECS
|
||||
=============================
|
||||
|
||||
This folder contains terraform files to deploy a modular Windmill stack on AWS ECS with just a few commands.
|
||||
|
||||
### Pre-requisite
|
||||
|
||||
##### AWS terraform user
|
||||
|
||||
An AWS user with the AWS managed `AdministratorAccess` policy (arn: `arn:aws:iam::aws:policy/AdministratorAccess`) is necessary. This will be the user terraform uses to deploy the components to AWS.
|
||||
|
||||
Generate an AWS access key ID and secret, and append the following block to your `~/.aws/credentials`:
|
||||
|
||||
```
|
||||
[terraform]
|
||||
aws_access_key_id = <ACCESS_KEY_ID>
|
||||
aws_secret_access_key = <SECRET_ACCESS_KEY>
|
||||
```
|
||||
|
||||
##### Creating an ecs task execution role
|
||||
|
||||
Terraform will reference the role `ecsTaskExecutionRole` to launch tasks in the ECS cluster. SInce it is a common role, this Terraform does not create it, it need to be present in your AWS account.
|
||||
|
||||
If it's not, just create it in you IAM console and attach it the following AWS managed policy: `AmazonECSTaskExecutionRolePolicy` (arn: `arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy`)
|
||||
|
||||
##### Database password
|
||||
|
||||
Windmill relies on a PostgreSQL database which will be created by Terraform. The only think you need to manually provide is a strong password. It should be set in [terraform.tfvars](./terraform.tfvars).
|
||||
|
||||
### Windmill stack
|
||||
|
||||
The following stack will be deployed by this terraform as it is provided:
|
||||
- 2 Windmill servers (each requiring 1 CPU and 1.5GiB of Memory)
|
||||
- 2 multi-purpose Windmill workers (each requiring 2 CPU and 3GiB of Memory)
|
||||
- Windmill LSP (requiring 1 CPU and 1.5GiB of Memory)
|
||||
- Windmill Multiplayer (requiring 1 CPU and 1.5GiB of Memory)
|
||||
- 1 native Windmill worker (requiring 2 CPU and 3GiB of Memory)
|
||||
- 1 high performance Windmill worker (requiring 4 CPU and 15GiB of Memory)
|
||||
|
||||
The ECS cluster will be composed of 1 autoscaling group composed of up-to 6 `t3.medium` instances (5 necessary for the entire load, and 1 more for rolling upgrades). This will host all the services except the high performance workers. Those will be deployed on a separate auto-scaling group composed of up-to 2 `t3.xlarge` instances.
|
||||
|
||||
Of course the above is provided as an example, it should be tuned for you own needs, both in terms of instance specs, but also in terms of service architecture. For example, you might not need high performance workers, in which case you won't need the second autoscaling group at all. Same for the native worker, multiplayer, or even LSP (though LSP is highly recommended for a better coding experience).
|
||||
|
||||
The only strictly required components are:
|
||||
- At least 1 Windmill server
|
||||
- At least 1 multi-purpose Windmill worker
|
||||
|
||||
This terraform has been assembled to easily remove components. Each component mentioned in the above list is entirely contained in a `.tf` file. If you don't want it, just remove the file. And if you want to tune it, you know where to look.
|
||||
|
||||
- _REQUIRED_ Windmill server -> [windmill_server.tf](./windmill_server.tf)
|
||||
- _REQUIRED_ Multi-purpose windmill worker -> [windmill_worker_basic.tf](./windmill_worker_basic.tf)
|
||||
- _OPTIONAL_ Windmill LSP -> [windmill_lsp.tf](./windmill_lsp.tf)
|
||||
- _OPTIONAL_ Windmill Multiplayer -> [windmill_multiplayer.tf](./windmill_multiplayer.tf)
|
||||
- _OPTIONAL_ Windmill Native worker -> [windmill_worker_native.tf](./windmill_worker_native.tf)
|
||||
- _OPTIONAL_ Windmill High Performace worker -> [windmill_worker_high_performance.tf](./windmill_worker_high_performance.tf) - this one is a lot longer because it deploys a new auto scaling group
|
||||
|
||||
### Network
|
||||
|
||||
The network deployed here is a single VPC, composed on 4 subnets spread across 2 availability zones (1 public and 1 private subnet per zone). All the services are behind a load balancer routing the request to Windmill server, LSP or multiplayer.
|
||||
|
||||
A single security group is used, allowing HTTP traffic on port 80 (it is not deploying custom certificates and therefore does not use HTTPS).
|
||||
|
||||
All this is provided as an example. It can be refined depending on your needs. All the network components are defined in [vpc.tf](./vpc.tf), except the security group which is is [security_group.tf](./security_group.tf) and load balancer which is defined in [load_balancer.tf](./load_balancer.tf)
|
||||
|
||||
### RDS Database
|
||||
|
||||
Windmill heavily relies on PostgreSQL database. This terraform deploys a standalone RDS instance having 100GiB of storage, which can be scaled up to 1000GiB. For production use cases, we recommend deploying a Multi-AZ instance, or even a Multi-AZ DB cluster. The RDS definition is in [rds.tf](./rds.tf)
|
||||
|
||||
### Ready?
|
||||
|
||||
REMINDER: don't forget to edit [terraform.tfvars](./terraform.tfvars) before deploying the stack.
|
||||
|
||||
Once you're ready, simply run:
|
||||
|
||||
```bash
|
||||
# for a dry-run
|
||||
terraform plan
|
||||
```
|
||||
|
||||
and then
|
||||
```bash
|
||||
terraform apply
|
||||
```
|
||||
|
||||

|
||||
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
@@ -0,0 +1,95 @@
|
||||
resource "aws_launch_template" "windmill_cluster_lt" {
|
||||
name = "windmill-cluster-lt"
|
||||
image_id = "ami-09c0b8e7f21923ac0"
|
||||
instance_type = "t3.medium"
|
||||
# vpc_security_group_ids = [aws_security_group.windmill_cluster_sg.id]
|
||||
|
||||
block_device_mappings {
|
||||
device_name = "/dev/xvda"
|
||||
|
||||
ebs {
|
||||
volume_size = 100
|
||||
}
|
||||
}
|
||||
|
||||
iam_instance_profile {
|
||||
name = "ecsInstanceRole"
|
||||
}
|
||||
|
||||
network_interfaces {
|
||||
device_index = 0
|
||||
delete_on_termination = true
|
||||
associate_public_ip_address = true
|
||||
security_groups = [
|
||||
aws_security_group.windmill_cluster_sg.id
|
||||
]
|
||||
}
|
||||
|
||||
user_data = filebase64("${path.module}/lt_init_script.sh")
|
||||
|
||||
tag_specifications {
|
||||
resource_type = "instance"
|
||||
tags = {
|
||||
Name = "ECS Instance - windmill-cluster"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_autoscaling_group" "windmill_cluster_asg" {
|
||||
name = "windmill-cluster-asg"
|
||||
max_size = 6
|
||||
min_size = 1
|
||||
|
||||
vpc_zone_identifier = [
|
||||
aws_subnet.windmill_cluster_subnet_public1.id,
|
||||
aws_subnet.windmill_cluster_subnet_public2.id,
|
||||
aws_subnet.windmill_cluster_subnet_private1.id,
|
||||
aws_subnet.windmill_cluster_subnet_private2.id
|
||||
]
|
||||
|
||||
launch_template {
|
||||
id = aws_launch_template.windmill_cluster_lt.id
|
||||
version = "$Latest"
|
||||
}
|
||||
|
||||
health_check_type = "EC2"
|
||||
|
||||
tag {
|
||||
key = "AmazonECSManaged"
|
||||
value = true
|
||||
propagate_at_launch = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ecs_cluster" "windmill_cluster" {
|
||||
name = "windmill-cluster"
|
||||
}
|
||||
|
||||
resource "aws_ecs_capacity_provider" "windmill_cluster_capacity_provider" {
|
||||
name = "windmill-cluster-capacity-provider"
|
||||
|
||||
auto_scaling_group_provider {
|
||||
auto_scaling_group_arn = aws_autoscaling_group.windmill_cluster_asg.arn
|
||||
|
||||
managed_scaling {
|
||||
maximum_scaling_step_size = 5
|
||||
minimum_scaling_step_size = 1
|
||||
status = "ENABLED"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ecs_cluster_capacity_providers" "windmill_cluster_cluster___capacity_provider" {
|
||||
cluster_name = aws_ecs_cluster.windmill_cluster.name
|
||||
|
||||
capacity_providers = [
|
||||
aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name,
|
||||
aws_ecs_capacity_provider.windmill_cluster_high_performance_capacity_provider.name # remove if not using high performance workers
|
||||
]
|
||||
|
||||
default_capacity_provider_strategy {
|
||||
base = 1
|
||||
weight = 100
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
resource "aws_lb_target_group" "windmill_cluster_windmill_server_tg" {
|
||||
name = "windmill-cluster-server-tg"
|
||||
port = 8000
|
||||
protocol = "HTTP"
|
||||
target_type = "ip"
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
}
|
||||
|
||||
resource "aws_lb_target_group" "windmill_cluster_windmill_lsp_tg" {
|
||||
name = "windmill-cluster-lsp-tg"
|
||||
port = 3001
|
||||
protocol = "HTTP"
|
||||
target_type = "ip"
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
}
|
||||
|
||||
resource "aws_lb_target_group" "windmill_cluster_windmill_multiplayer_tg" {
|
||||
name = "windmill-cluster-multiplayer-tg"
|
||||
port = 3002
|
||||
protocol = "HTTP"
|
||||
target_type = "ip"
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
}
|
||||
|
||||
resource "aws_lb" "windmill_cluster_alb" {
|
||||
name = "windmill-cluster-alb"
|
||||
internal = false
|
||||
load_balancer_type = "application"
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_public1.id,
|
||||
aws_subnet.windmill_cluster_subnet_public2.id,
|
||||
]
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-alb"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_lb_listener" "windmill_cluster_alb_listener" {
|
||||
load_balancer_arn = aws_lb.windmill_cluster_alb.arn
|
||||
port = 80
|
||||
protocol = "HTTP"
|
||||
|
||||
default_action {
|
||||
type = "forward"
|
||||
target_group_arn = aws_lb_target_group.windmill_cluster_windmill_server_tg.arn
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_lb_listener_rule" "windmill_cluster_alb_lsp_rule" {
|
||||
listener_arn = aws_lb_listener.windmill_cluster_alb_listener.arn
|
||||
priority = 100
|
||||
|
||||
action {
|
||||
type = "forward"
|
||||
target_group_arn = aws_lb_target_group.windmill_cluster_windmill_lsp_tg.arn
|
||||
}
|
||||
|
||||
condition {
|
||||
path_pattern {
|
||||
values = ["/ws/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_lb_listener_rule" "windmill_cluster_alb_multiplayer_rule" {
|
||||
listener_arn = aws_lb_listener.windmill_cluster_alb_listener.arn
|
||||
priority = 50
|
||||
|
||||
action {
|
||||
type = "forward"
|
||||
target_group_arn = aws_lb_target_group.windmill_cluster_windmill_multiplayer_tg.arn
|
||||
}
|
||||
|
||||
condition {
|
||||
path_pattern {
|
||||
values = ["/ws_mp/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
echo ECS_CLUSTER=windmill-cluster >> /etc/ecs/ecs.config;
|
||||
@@ -0,0 +1,28 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 4.16"
|
||||
}
|
||||
}
|
||||
|
||||
required_version = ">= 1.2.0"
|
||||
}
|
||||
|
||||
provider "aws" {
|
||||
region = "us-east-2"
|
||||
profile = "terraform"
|
||||
}
|
||||
|
||||
data "aws_region" "current" {}
|
||||
|
||||
data "aws_iam_role" "ecs_task_execution_role" {
|
||||
# this needs to be creates in AWS with the attaching the AWS managed policy: 'AmazonECSTaskExecutionRolePolicy'
|
||||
name = "ecsTaskExecutionRole"
|
||||
}
|
||||
|
||||
variable "database_password" {
|
||||
type = string
|
||||
sensitive = true
|
||||
description = "RDS Database password"
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
resource "aws_db_subnet_group" "windmill_cluster_rds_subnets" {
|
||||
name = "windmill-cluster-rds-subnets"
|
||||
subnet_ids = [
|
||||
aws_subnet.windmill_cluster_subnet_public1.id,
|
||||
aws_subnet.windmill_cluster_subnet_public2.id,
|
||||
aws_subnet.windmill_cluster_subnet_private1.id,
|
||||
aws_subnet.windmill_cluster_subnet_private2.id,
|
||||
]
|
||||
}
|
||||
|
||||
resource "aws_db_instance" "windmill_cluster_rds" {
|
||||
identifier = "windmill-cluster-db"
|
||||
|
||||
availability_zone = "us-east-2a"
|
||||
instance_class = "db.m5d.large"
|
||||
allocated_storage = 100
|
||||
max_allocated_storage = 1000
|
||||
storage_type = "gp3"
|
||||
# storage_throughput = 125
|
||||
storage_encrypted = true
|
||||
# iops = 3000
|
||||
|
||||
engine = "postgres"
|
||||
engine_version = "16.1"
|
||||
parameter_group_name = "default.postgres16"
|
||||
license_model = "postgresql-license"
|
||||
|
||||
db_name = "windmill"
|
||||
username = "postgres"
|
||||
password = var.database_password
|
||||
|
||||
network_type = "IPV4"
|
||||
port = 5432
|
||||
db_subnet_group_name = aws_db_subnet_group.windmill_cluster_rds_subnets.name
|
||||
vpc_security_group_ids = [aws_security_group.windmill_cluster_sg.id]
|
||||
publicly_accessible = false
|
||||
|
||||
performance_insights_enabled = true
|
||||
performance_insights_retention_period = 7
|
||||
|
||||
backup_retention_period = 7
|
||||
skip_final_snapshot = true
|
||||
deletion_protection = false
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
resource "aws_security_group" "windmill_cluster_sg" {
|
||||
name = "windmill-cluster-sg"
|
||||
description = "Windmill cluster security group"
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
|
||||
ingress {
|
||||
from_port = 80
|
||||
to_port = 80
|
||||
protocol = "tcp"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
ingress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
self = true
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
ipv6_cidr_blocks = ["::/0"]
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-sg"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
database_password = "changeme"
|
||||
@@ -0,0 +1,143 @@
|
||||
resource "aws_vpc" "windmill_cluster_vpc" {
|
||||
cidr_block = "132.0.0.0/16"
|
||||
instance_tenancy = "default"
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-vpc"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "windmill_cluster_subnet_public1" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
cidr_block = "132.0.0.0/20"
|
||||
availability_zone = "us-east-2a"
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-subnet-public1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "windmill_cluster_subnet_public2" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
cidr_block = "132.0.16.0/20"
|
||||
availability_zone = "us-east-2b"
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-subnet-public2"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "windmill_cluster_subnet_private1" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
cidr_block = "132.0.128.0/20"
|
||||
availability_zone = "us-east-2a"
|
||||
map_public_ip_on_launch = false
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-subnet-private1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "windmill_cluster_subnet_private2" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
cidr_block = "132.0.144.0/20"
|
||||
availability_zone = "us-east-2b"
|
||||
map_public_ip_on_launch = false
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-subnet-private2"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "windmill_cluster_internet_gateway" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-internet-gateway"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_eip" "windmill_cluster_nat_gateway_public1_eip" {
|
||||
vpc = true
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "windmill_cluster_nat_gateway_public1" {
|
||||
allocation_id = aws_eip.windmill_cluster_nat_gateway_public1_eip.id
|
||||
subnet_id = aws_subnet.windmill_cluster_subnet_public1.id
|
||||
tags = {
|
||||
"Name" = "windmill-cluster-nat-gateway-public1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_eip" "windmill_cluster_nat_gateway_public2_eip" {
|
||||
vpc = true
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "windmill_cluster_nat_gateway_public2" {
|
||||
allocation_id = aws_eip.windmill_cluster_nat_gateway_public2_eip.id
|
||||
subnet_id = aws_subnet.windmill_cluster_subnet_public2.id
|
||||
tags = {
|
||||
"Name" = "windmill-cluster-nat-gateway-public2"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "windmill_cluster_rtb_public" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.windmill_cluster_internet_gateway.id
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-rtb-public"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "windmill_cluster_subnet_public1__rtb_public" {
|
||||
subnet_id = aws_subnet.windmill_cluster_subnet_public1.id
|
||||
route_table_id = aws_route_table.windmill_cluster_rtb_public.id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "windmill_cluster_subnet_public2__rtb_public" {
|
||||
subnet_id = aws_subnet.windmill_cluster_subnet_public2.id
|
||||
route_table_id = aws_route_table.windmill_cluster_rtb_public.id
|
||||
}
|
||||
|
||||
resource "aws_route_table" "windmill_cluster_rtb_private1" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.windmill_cluster_nat_gateway_public1.id
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-rtb-private1"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "windmill_cluster_subnet_private1__rtb_private1" {
|
||||
subnet_id = aws_subnet.windmill_cluster_subnet_private1.id
|
||||
route_table_id = aws_route_table.windmill_cluster_rtb_private1.id
|
||||
}
|
||||
|
||||
resource "aws_route_table" "windmill_cluster_rtb_private2" {
|
||||
vpc_id = aws_vpc.windmill_cluster_vpc.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.windmill_cluster_nat_gateway_public2.id
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "windmill-cluster-rtb-private2"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "windmill_cluster_subnet_private2__rtb_private2" {
|
||||
subnet_id = aws_subnet.windmill_cluster_subnet_private2.id
|
||||
route_table_id = aws_route_table.windmill_cluster_rtb_private2.id
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
resource "aws_cloudwatch_log_group" "windmill_cluster_windmill_lsp_log_group" {
|
||||
name = "/ecs/windmill-lsp"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "windmill_cluster_windmill_lsp_td" {
|
||||
family = "windmill-lsp"
|
||||
network_mode = "awsvpc"
|
||||
execution_role_arn = data.aws_iam_role.ecs_task_execution_role.arn
|
||||
cpu = 1024
|
||||
memory = 1536
|
||||
runtime_platform {
|
||||
operating_system_family = "LINUX"
|
||||
cpu_architecture = "X86_64"
|
||||
}
|
||||
requires_compatibilities = ["EC2"]
|
||||
|
||||
container_definitions = jsonencode([
|
||||
{
|
||||
name = "windmill-lsp"
|
||||
image = "ghcr.io/windmill-labs/windmill-lsp:latest"
|
||||
cpu = 1024
|
||||
memory = 1536
|
||||
essential = true
|
||||
portMappings = [
|
||||
{
|
||||
name = "http"
|
||||
containerPort = 3001
|
||||
hostPort = 3001
|
||||
protocol = "tcp"
|
||||
appProtocol = "http"
|
||||
}
|
||||
]
|
||||
logConfiguration = {
|
||||
logDriver = "awslogs"
|
||||
options = {
|
||||
"awslogs-group" = aws_cloudwatch_log_group.windmill_cluster_windmill_lsp_log_group.name
|
||||
"awslogs-region" = data.aws_region.current.name
|
||||
"awslogs-stream-prefix" = "ecs"
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "windmill_cluster_windmill_lsp_service" {
|
||||
name = "windmill-lsp"
|
||||
cluster = aws_ecs_cluster.windmill_cluster.id
|
||||
task_definition = aws_ecs_task_definition.windmill_cluster_windmill_lsp_td.arn
|
||||
desired_count = 1
|
||||
|
||||
network_configuration {
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_public1.id,
|
||||
aws_subnet.windmill_cluster_subnet_public2.id,
|
||||
]
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
}
|
||||
|
||||
force_new_deployment = true
|
||||
placement_constraints {
|
||||
type = "distinctInstance"
|
||||
}
|
||||
|
||||
capacity_provider_strategy {
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name
|
||||
weight = 100
|
||||
}
|
||||
|
||||
load_balancer {
|
||||
target_group_arn = aws_lb_target_group.windmill_cluster_windmill_lsp_tg.arn
|
||||
container_name = "windmill-lsp"
|
||||
container_port = 3001
|
||||
}
|
||||
|
||||
depends_on = [aws_autoscaling_group.windmill_cluster_asg]
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
resource "aws_cloudwatch_log_group" "windmill_cluster_windmill_multiplayer_log_group" {
|
||||
name = "/ecs/windmill-multiplayer"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "windmill_cluster_windmill_multiplayer_td" {
|
||||
family = "windmill-multiplayer"
|
||||
network_mode = "awsvpc"
|
||||
execution_role_arn = data.aws_iam_role.ecs_task_execution_role.arn
|
||||
cpu = 1024
|
||||
memory = 1536
|
||||
runtime_platform {
|
||||
operating_system_family = "LINUX"
|
||||
cpu_architecture = "X86_64"
|
||||
}
|
||||
requires_compatibilities = ["EC2"]
|
||||
|
||||
container_definitions = jsonencode([
|
||||
{
|
||||
name = "windmill-multiplayer"
|
||||
image = "ghcr.io/windmill-labs/windmill-multiplayer:latest"
|
||||
cpu = 1024
|
||||
memory = 1536
|
||||
essential = true
|
||||
portMappings = [
|
||||
{
|
||||
name = "http"
|
||||
containerPort = 3002
|
||||
hostPort = 3002
|
||||
protocol = "tcp"
|
||||
appProtocol = "http"
|
||||
}
|
||||
]
|
||||
logConfiguration = {
|
||||
logDriver = "awslogs"
|
||||
options = {
|
||||
"awslogs-group" = aws_cloudwatch_log_group.windmill_cluster_windmill_multiplayer_log_group.name
|
||||
"awslogs-region" = data.aws_region.current.name
|
||||
"awslogs-stream-prefix" = "ecs"
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "windmill_cluster_windmill_multiplayer_service" {
|
||||
name = "windmill-multiplayer"
|
||||
cluster = aws_ecs_cluster.windmill_cluster.id
|
||||
task_definition = aws_ecs_task_definition.windmill_cluster_windmill_multiplayer_td.arn
|
||||
desired_count = 1
|
||||
|
||||
network_configuration {
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_public1.id,
|
||||
aws_subnet.windmill_cluster_subnet_public2.id,
|
||||
]
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
}
|
||||
|
||||
force_new_deployment = true
|
||||
placement_constraints {
|
||||
type = "distinctInstance"
|
||||
}
|
||||
|
||||
capacity_provider_strategy {
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name
|
||||
weight = 100
|
||||
}
|
||||
|
||||
load_balancer {
|
||||
target_group_arn = aws_lb_target_group.windmill_cluster_windmill_multiplayer_tg.arn
|
||||
container_name = "windmill-multiplayer"
|
||||
container_port = 3002
|
||||
}
|
||||
|
||||
depends_on = [aws_autoscaling_group.windmill_cluster_asg]
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
resource "aws_cloudwatch_log_group" "windmill_cluster_windmill_server_log_group" {
|
||||
name = "/ecs/windmill-server"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "windmill_cluster_windmill_server_td" {
|
||||
family = "windmill-server"
|
||||
network_mode = "awsvpc"
|
||||
execution_role_arn = data.aws_iam_role.ecs_task_execution_role.arn
|
||||
cpu = 1024
|
||||
memory = 1536
|
||||
runtime_platform {
|
||||
operating_system_family = "LINUX"
|
||||
cpu_architecture = "X86_64"
|
||||
}
|
||||
requires_compatibilities = ["EC2"]
|
||||
|
||||
container_definitions = jsonencode([
|
||||
{
|
||||
name = "windmill-server"
|
||||
image = "ghcr.io/windmill-labs/windmill-ee:main"
|
||||
cpu = 1024
|
||||
memory = 1536
|
||||
essential = true
|
||||
portMappings = [
|
||||
{
|
||||
name = "http"
|
||||
containerPort = 8000
|
||||
hostPort = 8000
|
||||
protocol = "tcp"
|
||||
appProtocol = "http"
|
||||
}
|
||||
]
|
||||
environment = [{
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "server"
|
||||
}]
|
||||
healthCheck = {
|
||||
command = ["CMD-SHELL", "curl -f http://localhost:8000/api/version || exit 1"]
|
||||
interval = 10
|
||||
timeout = 5
|
||||
retries = 5
|
||||
}
|
||||
logConfiguration = {
|
||||
logDriver = "awslogs"
|
||||
options = {
|
||||
"awslogs-group" = aws_cloudwatch_log_group.windmill_cluster_windmill_server_log_group.name
|
||||
"awslogs-region" = data.aws_region.current.name
|
||||
"awslogs-stream-prefix" = "ecs"
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "windmill_cluster_windmill_server_service" {
|
||||
name = "windmill-server"
|
||||
cluster = aws_ecs_cluster.windmill_cluster.id
|
||||
task_definition = aws_ecs_task_definition.windmill_cluster_windmill_server_td.arn
|
||||
desired_count = 2
|
||||
|
||||
network_configuration {
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_public1.id,
|
||||
aws_subnet.windmill_cluster_subnet_public2.id,
|
||||
]
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
}
|
||||
|
||||
force_new_deployment = true
|
||||
placement_constraints {
|
||||
type = "distinctInstance"
|
||||
}
|
||||
|
||||
capacity_provider_strategy {
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name
|
||||
weight = 100
|
||||
}
|
||||
|
||||
load_balancer {
|
||||
target_group_arn = aws_lb_target_group.windmill_cluster_windmill_server_tg.arn
|
||||
container_name = "windmill-server"
|
||||
container_port = 8000
|
||||
}
|
||||
|
||||
depends_on = [aws_autoscaling_group.windmill_cluster_asg]
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
resource "aws_cloudwatch_log_group" "windmill_cluster_windmill_worker_log_group" {
|
||||
name = "/ecs/windmill-worker"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "windmill_cluster_windmill_worker_td" {
|
||||
family = "windmill-worker"
|
||||
network_mode = "awsvpc"
|
||||
execution_role_arn = data.aws_iam_role.ecs_task_execution_role.arn
|
||||
cpu = 2048
|
||||
memory = 3072
|
||||
runtime_platform {
|
||||
operating_system_family = "LINUX"
|
||||
cpu_architecture = "X86_64"
|
||||
}
|
||||
requires_compatibilities = ["EC2"]
|
||||
|
||||
container_definitions = jsonencode([
|
||||
{
|
||||
name = "windmill-worker"
|
||||
image = "ghcr.io/windmill-labs/windmill-ee:main"
|
||||
cpu = 2048
|
||||
memory = 3072
|
||||
essential = true
|
||||
environment = [{
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "worker"
|
||||
}, {
|
||||
name = "WORKER_GROUP"
|
||||
value = "default"
|
||||
}]
|
||||
logConfiguration = {
|
||||
logDriver = "awslogs"
|
||||
options = {
|
||||
"awslogs-group" = aws_cloudwatch_log_group.windmill_cluster_windmill_worker_log_group.name
|
||||
"awslogs-region" = data.aws_region.current.name
|
||||
"awslogs-stream-prefix" = "ecs"
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "windmill_cluster_windmill_worker_service" {
|
||||
name = "windmill-worker"
|
||||
cluster = aws_ecs_cluster.windmill_cluster.id
|
||||
task_definition = aws_ecs_task_definition.windmill_cluster_windmill_worker_td.arn
|
||||
desired_count = 2
|
||||
|
||||
network_configuration {
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_private1.id,
|
||||
aws_subnet.windmill_cluster_subnet_private2.id,
|
||||
]
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
}
|
||||
|
||||
force_new_deployment = true
|
||||
placement_constraints {
|
||||
type = "distinctInstance"
|
||||
}
|
||||
|
||||
capacity_provider_strategy {
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name
|
||||
weight = 100
|
||||
}
|
||||
|
||||
depends_on = [aws_autoscaling_group.windmill_cluster_asg]
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
resource "aws_launch_template" "windmill_cluster_high_performance_lt" {
|
||||
name = "windmill-cluster-high-perf-lt"
|
||||
image_id = "ami-09c0b8e7f21923ac0"
|
||||
instance_type = "t3.xlarge"
|
||||
# vpc_security_group_ids = [aws_security_group.windmill_cluster_sg.id]
|
||||
|
||||
block_device_mappings {
|
||||
device_name = "/dev/xvda"
|
||||
|
||||
ebs {
|
||||
volume_size = 100
|
||||
}
|
||||
}
|
||||
|
||||
iam_instance_profile {
|
||||
name = "ecsInstanceRole"
|
||||
}
|
||||
|
||||
network_interfaces {
|
||||
device_index = 0
|
||||
delete_on_termination = true
|
||||
associate_public_ip_address = true
|
||||
security_groups = [
|
||||
aws_security_group.windmill_cluster_sg.id
|
||||
]
|
||||
}
|
||||
|
||||
user_data = filebase64("${path.module}/lt_init_script.sh")
|
||||
|
||||
tag_specifications {
|
||||
resource_type = "instance"
|
||||
tags = {
|
||||
Name = "ECS Instance - windmill-cluster"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_autoscaling_group" "windmill_cluster_high_performance_asg" {
|
||||
name = "windmill-cluster-high-perf-asg"
|
||||
max_size = 2
|
||||
min_size = 0
|
||||
|
||||
vpc_zone_identifier = [
|
||||
aws_subnet.windmill_cluster_subnet_private1.id,
|
||||
aws_subnet.windmill_cluster_subnet_private2.id
|
||||
]
|
||||
|
||||
launch_template {
|
||||
id = aws_launch_template.windmill_cluster_high_performance_lt.id
|
||||
version = "$Latest"
|
||||
}
|
||||
|
||||
health_check_type = "EC2"
|
||||
|
||||
tag {
|
||||
key = "AmazonECSManaged"
|
||||
value = true
|
||||
propagate_at_launch = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ecs_capacity_provider" "windmill_cluster_high_performance_capacity_provider" {
|
||||
name = "windmill-cluster-high-perf-cp"
|
||||
|
||||
auto_scaling_group_provider {
|
||||
auto_scaling_group_arn = aws_autoscaling_group.windmill_cluster_high_performance_asg.arn
|
||||
|
||||
managed_scaling {
|
||||
maximum_scaling_step_size = 1
|
||||
minimum_scaling_step_size = 1
|
||||
status = "ENABLED"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "windmill_cluster_windmill_high_performance_worker_log_group" {
|
||||
name = "/ecs/windmill-high-performance-worker"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "windmill_cluster_windmill_high_performance_worker_td" {
|
||||
family = "windmill-high-performance-worker"
|
||||
network_mode = "awsvpc"
|
||||
execution_role_arn = data.aws_iam_role.ecs_task_execution_role.arn
|
||||
cpu = 4096
|
||||
memory = 15360
|
||||
runtime_platform {
|
||||
operating_system_family = "LINUX"
|
||||
cpu_architecture = "X86_64"
|
||||
}
|
||||
requires_compatibilities = ["EC2"]
|
||||
|
||||
container_definitions = jsonencode([
|
||||
{
|
||||
name = "windmill-worker"
|
||||
image = "ghcr.io/windmill-labs/windmill-ee:main"
|
||||
cpu = 4096
|
||||
memory = 15360
|
||||
essential = true
|
||||
environment = [{
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "worker"
|
||||
}, {
|
||||
name = "WORKER_GROUP"
|
||||
value = "high_performance"
|
||||
}]
|
||||
logConfiguration = {
|
||||
logDriver = "awslogs"
|
||||
options = {
|
||||
"awslogs-group" = aws_cloudwatch_log_group.windmill_cluster_windmill_high_performance_worker_log_group.name
|
||||
"awslogs-region" = data.aws_region.current.name
|
||||
"awslogs-stream-prefix" = "ecs"
|
||||
}
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "windmill_cluster_windmill_high_performance_worker_service" {
|
||||
name = "windmill-high-performance-worker"
|
||||
cluster = aws_ecs_cluster.windmill_cluster.id
|
||||
task_definition = aws_ecs_task_definition.windmill_cluster_windmill_high_performance_worker_td.arn
|
||||
desired_count = 1
|
||||
|
||||
network_configuration {
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_private1.id,
|
||||
aws_subnet.windmill_cluster_subnet_private2.id,
|
||||
]
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
}
|
||||
|
||||
force_new_deployment = true
|
||||
placement_constraints {
|
||||
type = "distinctInstance"
|
||||
}
|
||||
|
||||
capacity_provider_strategy {
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_high_performance_capacity_provider.name
|
||||
weight = 100
|
||||
}
|
||||
|
||||
depends_on = [aws_autoscaling_group.windmill_cluster_high_performance_asg]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
resource "aws_cloudwatch_log_group" "windmill_cluster_windmill_native_worker_log_group" {
|
||||
name = "/ecs/windmill-native-worker"
|
||||
}
|
||||
|
||||
resource "aws_ecs_task_definition" "windmill_cluster_windmill_native_worker_td" {
|
||||
family = "windmill-native-worker"
|
||||
network_mode = "awsvpc"
|
||||
execution_role_arn = data.aws_iam_role.ecs_task_execution_role.arn
|
||||
cpu = 2048
|
||||
memory = 3072
|
||||
runtime_platform {
|
||||
operating_system_family = "LINUX"
|
||||
cpu_architecture = "X86_64"
|
||||
}
|
||||
requires_compatibilities = ["EC2"]
|
||||
|
||||
container_definitions = jsonencode([
|
||||
{
|
||||
name = "windmill-native-worker"
|
||||
image = "ghcr.io/windmill-labs/windmill-ee:main"
|
||||
cpu = 2048
|
||||
memory = 3072
|
||||
essential = true
|
||||
environment = [{
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "worker"
|
||||
}, {
|
||||
name = "WORKER_GROUP"
|
||||
value = "native"
|
||||
}]
|
||||
logConfiguration = {
|
||||
logDriver = "awslogs"
|
||||
options = {
|
||||
"awslogs-group" = aws_cloudwatch_log_group.windmill_cluster_windmill_native_worker_log_group.name
|
||||
"awslogs-region" = data.aws_region.current.name
|
||||
"awslogs-stream-prefix" = "ecs"
|
||||
}
|
||||
"secretOptions" : []
|
||||
}
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
resource "aws_ecs_service" "windmill_cluster_windmill_native_worker_service" {
|
||||
name = "windmill-native-worker"
|
||||
cluster = aws_ecs_cluster.windmill_cluster.id
|
||||
task_definition = aws_ecs_task_definition.windmill_cluster_windmill_native_worker_td.arn
|
||||
desired_count = 1
|
||||
|
||||
network_configuration {
|
||||
subnets = [
|
||||
aws_subnet.windmill_cluster_subnet_private1.id,
|
||||
aws_subnet.windmill_cluster_subnet_private2.id,
|
||||
]
|
||||
security_groups = [aws_security_group.windmill_cluster_sg.id]
|
||||
}
|
||||
|
||||
force_new_deployment = true
|
||||
placement_constraints {
|
||||
type = "distinctInstance"
|
||||
}
|
||||
|
||||
capacity_provider_strategy {
|
||||
capacity_provider = aws_ecs_capacity_provider.windmill_cluster_capacity_provider.name
|
||||
weight = 100
|
||||
}
|
||||
|
||||
depends_on = [aws_autoscaling_group.windmill_cluster_asg]
|
||||
}
|
||||
Reference in New Issue
Block a user