Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve Terraform and ECS errors #5

Closed
wants to merge 77 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
1bd365c
Remove template_file
jwavoet Jul 22, 2024
3c42c6f
Disable output with missing vars.
jwavoet Jul 22, 2024
782a9fe
terraform fmt
jwavoet Jul 22, 2024
c57b42b
terraform fmt
jwavoet Jul 22, 2024
8fe79e0
Remove file()
jwavoet Jul 22, 2024
251f3ba
Store versions
jwavoet Jul 22, 2024
5c163da
Add missing var
jwavoet Jul 22, 2024
35f7e74
Add missing var
jwavoet Jul 22, 2024
1b29989
Disable logging for ALB
jwavoet Jul 22, 2024
87b67a5
Add lb outputs for Route53
jwavoet Jul 22, 2024
92a808b
Disable logging for ALB
jwavoet Jul 22, 2024
4af7ea2
Add lb outputs for Route53
jwavoet Jul 22, 2024
ab14559
Add aws_efs_access_point for grafana user
jwavoet Jul 23, 2024
0ebf3a3
Only allow fargate
jwavoet Jul 23, 2024
1db580e
Add aws_efs_access_point for grafana user
jwavoet Jul 23, 2024
bc603ed
terraform fmt
jwavoet Jul 23, 2024
db81b2e
Remove secrets
jwavoet Jul 23, 2024
eb37abd
Add name tag to aws_efs_access_point
jwavoet Jul 23, 2024
8ece8cf
Fix health path
jwavoet Jul 23, 2024
f24abab
Remove unused code
jwavoet Jul 23, 2024
79e11ca
Formatting
jwavoet Jul 23, 2024
dc90a52
Remove unused output
jwavoet Jul 23, 2024
5a58485
Add good-for-now default values for vars.
jwavoet Jul 23, 2024
605edda
Merge pull request #1 from dovetailworld/fix/terraform-errors
jwavoet Jul 23, 2024
f5f2ec3
General cleanup/refactor and moving resources to their own .tf file.
jwavoet Jul 23, 2024
12b5a7e
Update README
jwavoet Jul 23, 2024
22271fb
Remove ecs_cluster var
jwavoet Jul 23, 2024
e009f9e
Rename resource ref
jwavoet Jul 23, 2024
1ef3a54
Rename resource ref
jwavoet Jul 23, 2024
14246f5
Rename resource ref
jwavoet Jul 23, 2024
e95ea1f
replace name with arn
jwavoet Jul 23, 2024
1df4647
Update variables
jwavoet Jul 23, 2024
3e728c1
Add credits
jwavoet Jul 23, 2024
406d44c
Merge pull request #2 from dovetailworld/refactor
jwavoet Jul 23, 2024
1052b5d
Refactor security groups
jwavoet Jul 24, 2024
036ae41
Small changes to vars
jwavoet Jul 24, 2024
3078683
Refactor security groups
jwavoet Jul 24, 2024
e4199e8
Refactor security groups
jwavoet Jul 24, 2024
35fae72
Refactor security groups
jwavoet Jul 24, 2024
0045b1b
Refactor security groups
jwavoet Jul 24, 2024
bf61f3c
Replace resources when sg needs to be replaced.
jwavoet Jul 24, 2024
ac6be53
Replace resources when sg needs to be replaced.
jwavoet Jul 24, 2024
3b475ff
Merge pull request #3 from dovetailworld/feat/improve-sg-rules
jwavoet Jul 24, 2024
85e73c8
Update README
jwavoet Jul 24, 2024
1e02f69
Merge pull request #4 from dovetailworld/update/readme
jwavoet Jul 24, 2024
197d592
Allow changing the root URL for Grafana
jwavoet Jul 25, 2024
1b0cc98
Missing quotation marks
jwavoet Jul 25, 2024
02a4f37
Merge pull request #5 from dovetailworld/feat/set-root-url
jwavoet Jul 25, 2024
f8132e1
Add container healthcheck
jwavoet Jul 26, 2024
8a07558
Merge pull request #6 from dovetailworld/feat/container-healthcheck
jwavoet Jul 26, 2024
4f711c0
Add outputs for efs attributes
jwavoet Jul 26, 2024
91c45b8
Merge pull request #7 from dovetailworld/feat/efs-output
jwavoet Jul 26, 2024
1e0ebdd
Add spot with fallback functionality
jwavoet Jul 29, 2024
35ceae2
Move resources to ecs.tf
jwavoet Jul 29, 2024
b866796
Re-use allow_inbound_from_cidr_blocks var for lb
jwavoet Jul 29, 2024
e014ddf
Add spot with fallback functionality
jwavoet Jul 29, 2024
6663e67
Add spot with fallback functionality
jwavoet Jul 29, 2024
b14fc17
Add spot with fallback functionality
jwavoet Jul 29, 2024
9a92e3f
Add spot with fallback functionality
jwavoet Jul 29, 2024
2c4db36
Add spot with fallback functionality
jwavoet Jul 29, 2024
7f20b1c
Add spot with fallback functionality
jwavoet Jul 29, 2024
b48770c
Add spot with fallback functionality
jwavoet Jul 29, 2024
b0d7e10
Add spot with fallback functionality
jwavoet Jul 29, 2024
83430ca
Add spot with fallback functionality
jwavoet Jul 29, 2024
0efca00
Add spot with fallback functionality
jwavoet Jul 29, 2024
c13985a
Add spot with fallback functionality
jwavoet Jul 29, 2024
b875a15
Improve comments & documentation
jwavoet Jul 30, 2024
148b3b2
Add count to lambda related resources
jwavoet Jul 30, 2024
9a391a4
Add count to lambda related resources
jwavoet Jul 30, 2024
7353548
Merge pull request #8 from dovetailworld/feat/spot-with-fallback
jwavoet Jul 30, 2024
1fb26a3
Upgrade Lambda runtime to Python 3.12
jwavoet Jul 30, 2024
c0c705e
Add JSON Event examples to test the Lamba fuction.
jwavoet Jul 30, 2024
0a0636f
Merge pull request #9 from dovetailworld/update/python3.12
jwavoet Jul 30, 2024
aca807b
Update/readme (#10)
jwavoet Jul 31, 2024
978a69f
Feat/image renderer (#11)
jwavoet Jul 31, 2024
0d99ef1
Add output for Grafana version (#12)
jwavoet Aug 9, 2024
b132c76
Add grafana env var to enable embedding (#13)
jwavoet Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 180 additions & 16 deletions README.md

Large diffs are not rendered by default.

106 changes: 60 additions & 46 deletions container-definition/container-definition.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"name": "${container_name}",
"image": "${image}:${version}",
"name": "grafana",
"image": "${grafana_image}:${grafana_version}",
"logConfiguration": {
"logDriver": "awslogs",
"options": {
Expand All @@ -12,70 +12,84 @@
},
"portMappings": [
{
"hostPort": ${container_port},
"name": "grafana-${grafana_container_port}-tcp",
"containerPort": ${grafana_container_port},
"hostPort": 3000,
"protocol": "tcp",
"containerPort": ${container_port}
"appProtocol": "http"
}
],
"cpu": ${cpu},
"memoryReservation": ${memory},
"cpu": ${grafana_cpu},
"memoryReservation": ${grafana_memory},
"mountPoints": [
{
"containerPath": "/var/lib/grafana",
"sourceVolume": "grafana-db"
}
],
"secrets": [
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_ALLOW_SIGN_UP",
"name": "GF_AUTH_GITHUB_ALLOW_SIGN_UP"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_ALLOWED_ORGANIZATIONS",
"name": "GF_AUTH_GITHUB_ALLOWED_ORGANIZATIONS"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_API_URL",
"name": "GF_AUTH_GITHUB_API_URL"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_AUTH_URL",
"name": "GF_AUTH_GITHUB_AUTH_URL"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_CLIENT_ID",
"name": "GF_AUTH_GITHUB_CLIENT_ID"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_CLIENT_SECRET",
"name": "GF_AUTH_GITHUB_CLIENT_SECRET"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_ENABLED",
"name": "GF_AUTH_GITHUB_ENABLED"
},
"secrets": [],
"volumesFrom": [],
"essential": true,
"environment": [
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_SCOPES",
"name": "GF_AUTH_GITHUB_SCOPES"
"name": "GF_LOG_FILTERS",
"value": "rendering:debug"
},
{
"valueFrom": "/grafana/GF_AUTH_GITHUB_TOKEN_URL",
"name": "GF_AUTH_GITHUB_TOKEN_URL"
"name": "GF_RENDERING_CALLBACK_URL",
"value": "http://localhost:3000/"
},
{
"valueFrom": "/grafana/GF_SERVER_ROOT_URL",
"name": "GF_SERVER_ROOT_URL"
"name": "GF_RENDERING_SERVER_URL",
"value": "http://localhost:8081/render"
},
{
"valueFrom": "/grafana/GF_SERVER_ENABLE_GZIP",
"name": "GF_SERVER_ENABLE_GZIP"
"name": "GF_SERVER_ROOT_URL",
"value": "${grafana_root_url}"
},
{
"valueFrom": "/grafana/GF_DEFAULT_INSTANCE_NAME",
"name": "GF_DEFAULT_INSTANCE_NAME"
"name": "GF_SECURITY_ALLOW_EMBEDDING",
"value": "${grafana_allow_embedding}"
}
],
"healthCheck": {
"command": [
"CMD-SHELL",
"curl -f http://localhost:3000/login || exit 1"
],
"interval": 30,
"timeout": 5,
"retries": 3
}
},
{
"name": "renderer",
"image": "${renderer_image}:${renderer_version}",
"cpu": 256,
"memoryReservation": 512,
"portMappings": [
{
"name": "renderer-8081-tcp",
"containerPort": 8081,
"hostPort": 8081,
"protocol": "tcp",
"appProtocol": "http"
}
],
"essential": false,
"environment": [],
"environmentFiles": [],
"mountPoints": [],
"volumesFrom": [],
"essential": true
"healthCheck": {
"command": [
"CMD-SHELL",
"wget --spider http://localhost:8081/ || exit 1"
],
"interval": 30,
"timeout": 5,
"retries": 3
},
"systemControls": []
}
]
218 changes: 218 additions & 0 deletions ecs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Define the assume role IAM policy document for the ECS service scheduler IAM role
data "aws_iam_policy_document" "this" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}

# Create the IAM roles for the ECS task
resource "aws_iam_role" "ecs_task_execution_role" {
name = "${var.service_name}-task-execution-role"
assume_role_policy = data.aws_iam_policy_document.this.json
}

resource "aws_iam_role" "ecs_task_role" {
name = "${var.service_name}-task-role"
assume_role_policy = data.aws_iam_policy_document.this.json
}

# Configure additional IAM policies for the ECS service and task
resource "aws_iam_policy" "ecs_task_custom_policy" {
name = "${var.service_name}-ecs-task-custom-policy"
path = "/"

policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowReadingTagsInstancesRegionsFromEC2",
"Effect": "Allow",
"Action": ["ec2:DescribeTags", "ec2:DescribeInstances", "ec2:DescribeRegions"],
"Resource": "*"
},
{
"Sid": "AllowReadingResourcesForTags",
"Effect": "Allow",
"Action": "tag:GetResources",
"Resource": "*"
}
]
}
EOF
}

resource "aws_iam_role_policy_attachment" "task_custom" {
role = aws_iam_role.ecs_task_role.name
policy_arn = aws_iam_policy.ecs_task_custom_policy.arn
}

resource "aws_iam_role_policy_attachment" "task_ecr" {
role = aws_iam_role.ecs_task_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser"
}

resource "aws_iam_role_policy_attachment" "task_cloudwatch" {
role = aws_iam_role.ecs_task_role.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchFullAccess"
}

resource "aws_iam_role_policy_attachment" "task_ssm_ro" {
role = aws_iam_role.ecs_task_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"
}

resource "aws_iam_role_policy_attachment" "task_execution_custom" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = aws_iam_policy.ecs_task_custom_policy.arn
}

resource "aws_iam_role_policy_attachment" "task_execution_ecr" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPowerUser"
}

resource "aws_iam_role_policy_attachment" "task_execution_cloudwatch" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchFullAccess"
}

resource "aws_iam_role_policy_attachment" "task_execution_ssm_ro" {
role = aws_iam_role.ecs_task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess"
}

# Create the ECS cluster
resource "aws_ecs_cluster" "this" {
name = var.service_name

setting {
name = "containerInsights"
value = "enabled"
}
}

# Create CloudWatch log group
resource "aws_cloudwatch_log_group" "this" {
name = var.cloudwatch_log_group_name
retention_in_days = 30
}

# Create the task definition by passing it the container definition
locals {
container_definitions = templatefile("${path.module}/container-definition/container-definition.json", {
aws_region = var.aws_region
cloudwatch_log_group_name = aws_cloudwatch_log_group.this.name
grafana_image = var.grafana_image
grafana_version = var.grafana_version
renderer_image = var.renderer_image
renderer_version = var.renderer_version
grafana_cpu = (var.cpu - 256)
grafana_memory = (var.memory - 512)
grafana_container_port = var.grafana_container_port
grafana_root_url = var.grafana_root_url
grafana_allow_embedding = var.grafana_allow_embedding
})
}

resource "aws_ecs_task_definition" "this" {
family = var.service_name
container_definitions = local.container_definitions
network_mode = "awsvpc"
cpu = var.cpu
memory = var.memory
requires_compatibilities = ["FARGATE"]
task_role_arn = aws_iam_role.ecs_task_role.arn
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn

volume {
name = "grafana-db"

efs_volume_configuration {
file_system_id = aws_efs_file_system.this.id
root_directory = "/"
transit_encryption = "ENABLED"
authorization_config {
access_point_id = aws_efs_access_point.this.id
iam = "DISABLED"
}
}
}
}

# Create the ECS service(s)
resource "aws_ecs_service" "fargate_ondemand" {
# Create this resource when 'var.enable_spot' & 'var.enable_fallback' are both true.
count = (var.enable_spot && !var.enable_fallback) ? 0 : 1

name = "${var.service_name}-ondemand"
cluster = aws_ecs_cluster.this.arn
task_definition = aws_ecs_task_definition.this.arn
desired_count = 0
deployment_maximum_percent = var.deployment_maximum_percent
deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
health_check_grace_period_seconds = var.health_check_grace_period_seconds
launch_type = "FARGATE"
platform_version = var.platform_version
depends_on = [aws_lb_target_group.this]

load_balancer {
target_group_arn = aws_lb_target_group.this.arn
container_name = var.service_name
container_port = var.grafana_container_port
}

network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_service_sg.id]
assign_public_ip = var.assign_public_ip
}

lifecycle {
replace_triggered_by = [aws_security_group.ecs_service_sg.id]
}
}

resource "aws_ecs_service" "fargate_spot" {
# Create this resource when either 'var.enable_spot' or 'var.enable_fallback' is true.
count = (var.enable_spot || var.enable_fallback) ? 1 : 0

name = "${var.service_name}-spot"
cluster = aws_ecs_cluster.this.arn
task_definition = aws_ecs_task_definition.this.arn
desired_count = var.desired_number_of_tasks
deployment_maximum_percent = var.deployment_maximum_percent
deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
health_check_grace_period_seconds = var.health_check_grace_period_seconds

capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
weight = 1
base = 1
}

platform_version = var.platform_version
depends_on = [aws_lb_target_group.this]

load_balancer {
target_group_arn = aws_lb_target_group.this.arn
container_name = var.service_name
container_port = var.grafana_container_port
}

network_configuration {
subnets = var.private_subnet_ids
security_groups = [aws_security_group.ecs_service_sg.id]
assign_public_ip = var.assign_public_ip
}

lifecycle {
replace_triggered_by = [aws_security_group.ecs_service_sg.id]
}
}
Loading