From 42b28822f3e8e991bb637bb982ebe297148d6d28 Mon Sep 17 00:00:00 2001 From: Guillaume Bouvignies Date: Wed, 10 Jan 2024 08:17:38 +0100 Subject: [PATCH] docs: AWS ECS terraform deploy (#2980) --- examples/deploy/aws-ecs-terraform/.gitignore | 3 + .../aws-ecs-terraform/.terraform.lock.hcl | 25 +++ examples/deploy/aws-ecs-terraform/README.md | 85 ++++++++++ .../aws-ecs-terraform/assets/windmill.png | Bin 0 -> 62604 bytes .../deploy/aws-ecs-terraform/ecs_cluster.tf | 95 +++++++++++ .../deploy/aws-ecs-terraform/load_balancer.tf | 81 ++++++++++ .../aws-ecs-terraform/lt_init_script.sh | 2 + examples/deploy/aws-ecs-terraform/main.tf | 28 ++++ examples/deploy/aws-ecs-terraform/rds.tf | 44 ++++++ .../aws-ecs-terraform/security_group.tf | 35 +++++ .../deploy/aws-ecs-terraform/terraform.tfvars | 1 + examples/deploy/aws-ecs-terraform/vpc.tf | 143 +++++++++++++++++ .../deploy/aws-ecs-terraform/windmill_lsp.tf | 76 +++++++++ .../aws-ecs-terraform/windmill_multiplayer.tf | 76 +++++++++ .../aws-ecs-terraform/windmill_server.tf | 89 +++++++++++ .../windmill_worker_basic.tf | 71 +++++++++ .../windmill_worker_high_performance.tf | 147 ++++++++++++++++++ .../windmill_worker_native.tf | 72 +++++++++ 18 files changed, 1073 insertions(+) create mode 100644 examples/deploy/aws-ecs-terraform/.gitignore create mode 100644 examples/deploy/aws-ecs-terraform/.terraform.lock.hcl create mode 100644 examples/deploy/aws-ecs-terraform/README.md create mode 100644 examples/deploy/aws-ecs-terraform/assets/windmill.png create mode 100644 examples/deploy/aws-ecs-terraform/ecs_cluster.tf create mode 100644 examples/deploy/aws-ecs-terraform/load_balancer.tf create mode 100644 examples/deploy/aws-ecs-terraform/lt_init_script.sh create mode 100644 examples/deploy/aws-ecs-terraform/main.tf create mode 100644 examples/deploy/aws-ecs-terraform/rds.tf create mode 100644 examples/deploy/aws-ecs-terraform/security_group.tf create mode 100644 examples/deploy/aws-ecs-terraform/terraform.tfvars create mode 100644 examples/deploy/aws-ecs-terraform/vpc.tf create mode 100644 examples/deploy/aws-ecs-terraform/windmill_lsp.tf create mode 100644 examples/deploy/aws-ecs-terraform/windmill_multiplayer.tf create mode 100644 examples/deploy/aws-ecs-terraform/windmill_server.tf create mode 100644 examples/deploy/aws-ecs-terraform/windmill_worker_basic.tf create mode 100644 examples/deploy/aws-ecs-terraform/windmill_worker_high_performance.tf create mode 100644 examples/deploy/aws-ecs-terraform/windmill_worker_native.tf diff --git a/examples/deploy/aws-ecs-terraform/.gitignore b/examples/deploy/aws-ecs-terraform/.gitignore new file mode 100644 index 0000000000..5699847e45 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/.gitignore @@ -0,0 +1,3 @@ +.terraform/ +.env +terraform.tfstate* diff --git a/examples/deploy/aws-ecs-terraform/.terraform.lock.hcl b/examples/deploy/aws-ecs-terraform/.terraform.lock.hcl new file mode 100644 index 0000000000..0fa7c0cefa --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/.terraform.lock.hcl @@ -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", + ] +} diff --git a/examples/deploy/aws-ecs-terraform/README.md b/examples/deploy/aws-ecs-terraform/README.md new file mode 100644 index 0000000000..098943e353 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/README.md @@ -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 = +aws_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 +``` + +![Windmill screenshot](./assets/windmill.png) \ No newline at end of file diff --git a/examples/deploy/aws-ecs-terraform/assets/windmill.png b/examples/deploy/aws-ecs-terraform/assets/windmill.png new file mode 100644 index 0000000000000000000000000000000000000000..bba591b28da33436b4c37615edef777bf592569c GIT binary patch literal 62604 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�?M&OUsV@RvJ{2o}60_qo7 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

=1cfH#=`!FQUkbLe=qx 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 n|I@AU0S{Bv+3q> /etc/ecs/ecs.config; \ No newline at end of file diff --git a/examples/deploy/aws-ecs-terraform/main.tf b/examples/deploy/aws-ecs-terraform/main.tf new file mode 100644 index 0000000000..6c84b250b3 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/main.tf @@ -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" +} diff --git a/examples/deploy/aws-ecs-terraform/rds.tf b/examples/deploy/aws-ecs-terraform/rds.tf new file mode 100644 index 0000000000..4a9d312d0f --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/rds.tf @@ -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 +} \ No newline at end of file diff --git a/examples/deploy/aws-ecs-terraform/security_group.tf b/examples/deploy/aws-ecs-terraform/security_group.tf new file mode 100644 index 0000000000..dd17c23cee --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/security_group.tf @@ -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 + } +} diff --git a/examples/deploy/aws-ecs-terraform/terraform.tfvars b/examples/deploy/aws-ecs-terraform/terraform.tfvars new file mode 100644 index 0000000000..9d2d10a1e1 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/terraform.tfvars @@ -0,0 +1 @@ +database_password = "changeme" \ No newline at end of file diff --git a/examples/deploy/aws-ecs-terraform/vpc.tf b/examples/deploy/aws-ecs-terraform/vpc.tf new file mode 100644 index 0000000000..6e9c66c6bf --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/vpc.tf @@ -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 +} diff --git a/examples/deploy/aws-ecs-terraform/windmill_lsp.tf b/examples/deploy/aws-ecs-terraform/windmill_lsp.tf new file mode 100644 index 0000000000..13a23f3d8a --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/windmill_lsp.tf @@ -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] +} diff --git a/examples/deploy/aws-ecs-terraform/windmill_multiplayer.tf b/examples/deploy/aws-ecs-terraform/windmill_multiplayer.tf new file mode 100644 index 0000000000..2ddec1d6d5 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/windmill_multiplayer.tf @@ -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] +} diff --git a/examples/deploy/aws-ecs-terraform/windmill_server.tf b/examples/deploy/aws-ecs-terraform/windmill_server.tf new file mode 100644 index 0000000000..94b247bed5 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/windmill_server.tf @@ -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] +} diff --git a/examples/deploy/aws-ecs-terraform/windmill_worker_basic.tf b/examples/deploy/aws-ecs-terraform/windmill_worker_basic.tf new file mode 100644 index 0000000000..ad441543f3 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/windmill_worker_basic.tf @@ -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] +} diff --git a/examples/deploy/aws-ecs-terraform/windmill_worker_high_performance.tf b/examples/deploy/aws-ecs-terraform/windmill_worker_high_performance.tf new file mode 100644 index 0000000000..d510f494e6 --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/windmill_worker_high_performance.tf @@ -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] +} + diff --git a/examples/deploy/aws-ecs-terraform/windmill_worker_native.tf b/examples/deploy/aws-ecs-terraform/windmill_worker_native.tf new file mode 100644 index 0000000000..02cb83a9ca --- /dev/null +++ b/examples/deploy/aws-ecs-terraform/windmill_worker_native.tf @@ -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] +} \ No newline at end of file