Skip to content

Commit 7bcf801

Browse files
Create modularized ecs services (#3322)
Create service to handle background tasks as well as create a user-facing service (thrust). This is also used as an opportunity to rename the existing service and move it into the module setup. This is part of a PR chain with #3321 as parent
2 parents 2b31849 + b5e4db1 commit 7bcf801

File tree

14 files changed

+141
-48
lines changed

14 files changed

+141
-48
lines changed

Dockerfile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ USER 1000:1000
8080
# Entrypoint prepares the database.
8181
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
8282

83-
# Start server via Thruster by default, this can be overwritten at runtime
83+
# Start web server by default, this can be overwritten by environment variable
8484
EXPOSE 4000
8585
ENV HTTP_PORT=4000
86-
CMD ["./bin/thrust", "./bin/rails", "server"]
86+
ENV GOOD_JOB_PROBE_PORT=4000
87+
ENV SERVER_TYPE=web
88+
CMD ["./bin/docker-start"]

bin/docker-entrypoint

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ if [ -z "${LD_PRELOAD+x}" ]; then
66
export LD_PRELOAD
77
fi
88

9-
# If running the rails server then create or migrate existing database
10-
if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then
9+
# When starting the container then create or migrate existing database
10+
if [ "$1" == "./bin/docker-start" ]; then
1111
./bin/rails db:prepare:ignore_concurrent_migration_exceptions
1212
fi
1313

bin/docker-start

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
4+
5+
if [ "$SERVER_TYPE" == "web" ]; then
6+
echo "Starting web server..."
7+
exec "$SCRIPT_DIR"/thrust "$SCRIPT_DIR"/rails server
8+
elif [ "$SERVER_TYPE" == "good-job" ]; then
9+
echo "Starting good-job server..."
10+
exec "$SCRIPT_DIR"/bundle exec good_job start
11+
else
12+
echo "SERVER_TYPE variable: '$SERVER_TYPE' unknown. Allowed values ['web','good-job']"
13+
exit 1
14+
fi

config/application.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Application < Rails::Application
7575
config.active_model.i18n_customize_full_message = true
7676

7777
config.active_job.queue_adapter = :good_job
78-
config.good_job.execution_mode = :async
78+
config.good_job.execution_mode = :external
7979

8080
config.view_component.default_preview_layout = "component_preview"
8181
config.view_component.preview_controller = "ComponentPreviewsController"

config/environments/development.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@
8181
# Prevent health checks from clogging up the logs.
8282
config.silence_healthcheck_path = "/up"
8383

84+
# Set up GoodJob for async execution in development mode
85+
config.good_job.execution_mode = :async
86+
8487
# Enable strict loading to catch N+1 problems.
8588
config.active_record.strict_loading_by_default = true
8689
config.active_record.strict_loading_mode = :n_plus_one_only

config/puma.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
# processes).
5858
workers Settings.web_concurrency
5959

60-
if Settings.web_concurrency > 1
60+
if Settings.web_concurrency > 1 &&
61+
Rails.configuration.good_job.execution_mode != :external
6162
# Cleanly shut down GoodJob when Puma is shut down.
6263
# See https://github.com/bensheldon/good_job#execute-jobs-async--in-process
6364
MAIN_PID = Process.pid

terraform/app/autoscaling.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
resource "aws_appautoscaling_target" "ecs_target" {
22
count = var.enable_autoscaling ? 1 : 0
3-
resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.service.name}"
3+
resource_id = "service/${aws_ecs_cluster.cluster.name}/${module.web_service.service.name}"
44
max_capacity = var.maximum_replicas
55
min_capacity = var.minimum_replicas
66
service_namespace = "ecs"

terraform/app/codedeploy.tf

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ resource "aws_codedeploy_deployment_group" "blue_green_deployment_group" {
3232

3333
ecs_service {
3434
cluster_name = aws_ecs_cluster.cluster.name
35-
service_name = aws_ecs_service.service.name
35+
service_name = module.web_service.service.name
3636
}
3737

3838
load_balancer_info {
@@ -116,8 +116,8 @@ resource "aws_s3_object" "appspec_object" {
116116
key = "appspec.yaml"
117117
acl = "private"
118118
content = templatefile("templates/appspec.yaml.tpl", {
119-
task_definition_arn = aws_ecs_task_definition.task_definition.arn
120-
container_name = jsondecode(aws_ecs_task_definition.task_definition.container_definitions)[0].name
119+
task_definition_arn = module.web_service.task_definition.arn
120+
container_name = module.web_service.task_definition.arn
121121
container_port = aws_lb_target_group.blue.port
122122
})
123123

terraform/app/ecs.tf

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#TODO: Remove after release
12
resource "aws_security_group" "ecs_service_sg" {
23
name = "ecs-service-sg"
34
description = "Security Group for communication with ECS"
@@ -7,6 +8,7 @@ resource "aws_security_group" "ecs_service_sg" {
78
}
89
}
910

11+
#TODO: Remove after release
1012
resource "aws_security_group_rule" "ecs_ingress_http" {
1113
type = "ingress"
1214
from_port = 4000
@@ -19,6 +21,7 @@ resource "aws_security_group_rule" "ecs_ingress_http" {
1921
}
2022
}
2123

24+
#TODO: Remove after release
2225
resource "aws_security_group_rule" "ecs_talk_to_internet" {
2326
type = "egress"
2427
from_port = 0
@@ -28,15 +31,7 @@ resource "aws_security_group_rule" "ecs_talk_to_internet" {
2831
security_group_id = aws_security_group.ecs_service_sg.id
2932
}
3033

31-
resource "aws_ecs_cluster" "cluster" {
32-
name = "mavis-${var.environment}"
33-
34-
setting {
35-
name = "containerInsights"
36-
value = "enabled"
37-
}
38-
}
39-
34+
#TODO: Remove after release
4035
resource "aws_ecs_service" "service" {
4136
name = "mavis-${var.environment}"
4237
cluster = aws_ecs_cluster.cluster.id
@@ -53,7 +48,7 @@ resource "aws_ecs_service" "service" {
5348

5449
load_balancer {
5550
target_group_arn = aws_lb_target_group.blue.arn
56-
container_name = local.container_name
51+
container_name = "mavis-${var.environment}"
5752
container_port = 4000
5853
}
5954
deployment_controller {
@@ -69,6 +64,7 @@ resource "aws_ecs_service" "service" {
6964
}
7065
}
7166

67+
#TODO: Remove after release
7268
resource "aws_ecs_task_definition" "task_definition" {
7369
family = "task-definition-${var.environment}"
7470
requires_compatibilities = ["FARGATE"]
@@ -79,7 +75,7 @@ resource "aws_ecs_task_definition" "task_definition" {
7975
task_role_arn = aws_iam_role.ecs_task_role.arn
8076
container_definitions = jsonencode([
8177
{
82-
name = local.container_name
78+
name = "mavis-${var.environment}"
8379
image = "${var.account_id}.dkr.ecr.eu-west-2.amazonaws.com/${var.docker_image}@${var.image_digest}"
8480
essential = true
8581
portMappings = [
@@ -88,7 +84,7 @@ resource "aws_ecs_task_definition" "task_definition" {
8884
hostPort = 4000
8985
}
9086
]
91-
environment = local.task_envs
87+
environment = concat(local.task_envs, [{ name = "SERVER_TYPE", value = "web" }])
9288
secrets = local.task_secrets
9389
logConfiguration = {
9490
logDriver = "awslogs"
@@ -109,3 +105,77 @@ resource "aws_ecs_task_definition" "task_definition" {
109105
])
110106
depends_on = [aws_cloudwatch_log_group.ecs_log_group]
111107
}
108+
109+
resource "aws_security_group_rule" "web_service_alb_ingress" {
110+
type = "ingress"
111+
from_port = 4000
112+
to_port = 4000
113+
protocol = "tcp"
114+
security_group_id = module.web_service.security_group_id
115+
source_security_group_id = aws_security_group.lb_service_sg.id
116+
lifecycle {
117+
create_before_destroy = true
118+
}
119+
}
120+
121+
resource "aws_ecs_cluster" "cluster" {
122+
name = "mavis-${var.environment}"
123+
124+
setting {
125+
name = "containerInsights"
126+
value = "enabled"
127+
}
128+
}
129+
130+
module "web_service" {
131+
source = "./modules/ecs_service"
132+
task_config = {
133+
environment = local.task_envs
134+
secrets = local.task_secrets
135+
cpu = 1024
136+
memory = 2048
137+
docker_image = "${var.account_id}.dkr.ecr.eu-west-2.amazonaws.com/${var.docker_image}@${var.image_digest}"
138+
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
139+
task_role_arn = aws_iam_role.ecs_task_role.arn
140+
log_group_name = aws_cloudwatch_log_group.ecs_log_group.name
141+
region = var.region
142+
health_check_command = ["CMD-SHELL", "curl -f http://localhost:4000/up || exit 1"]
143+
}
144+
network_params = {
145+
subnets = [aws_subnet.private_subnet_a.id, aws_subnet.private_subnet_b.id]
146+
vpc_id = aws_vpc.application_vpc.id
147+
}
148+
loadbalancer = {
149+
target_group_arn = aws_lb_target_group.green.arn
150+
container_port = 4000
151+
}
152+
cluster_id = aws_ecs_cluster.cluster.id
153+
environment = var.environment
154+
server_type = "web"
155+
desired_count = var.minimum_replicas
156+
deployment_controller = "CODE_DEPLOY"
157+
}
158+
159+
module "good_job_service" {
160+
source = "./modules/ecs_service"
161+
task_config = {
162+
environment = local.task_envs
163+
secrets = local.task_secrets
164+
cpu = 1024
165+
memory = 2048
166+
docker_image = "${var.account_id}.dkr.ecr.eu-west-2.amazonaws.com/${var.docker_image}@${var.image_digest}"
167+
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn
168+
task_role_arn = aws_iam_role.ecs_task_role.arn
169+
log_group_name = aws_cloudwatch_log_group.ecs_log_group.name
170+
region = var.region
171+
health_check_command = ["CMD-SHELL", "curl -f http://localhost:4000 || exit 1"]
172+
}
173+
network_params = {
174+
subnets = [aws_subnet.private_subnet_a.id, aws_subnet.private_subnet_b.id]
175+
vpc_id = aws_vpc.application_vpc.id
176+
}
177+
cluster_id = aws_ecs_cluster.cluster.id
178+
environment = var.environment
179+
server_type = "good-job"
180+
desired_count = 1
181+
}

terraform/app/iam_policy_documents.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
data "aws_iam_policy_document" "codedeploy" {
44
statement {
55
actions = ["ecs:DescribeServices", "ecs:UpdateServicePrimaryTaskSet"]
6-
resources = [aws_ecs_service.service.id]
6+
resources = [module.web_service.service.id]
77
effect = "Allow"
88
}
99
statement {
1010
actions = ["ecs:CreateTaskSet", "ecs:DeleteTaskSet"]
11-
resources = ["arn:aws:ecs:*:*:task-set/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.service.name}/*"]
11+
resources = ["arn:aws:ecs:*:*:task-set/${aws_ecs_cluster.cluster.name}/${module.web_service.service.name}/*"]
1212
effect = "Allow"
1313
}
1414
statement {

0 commit comments

Comments
 (0)