Skip to content

Commit 11ae2fe

Browse files
authored
Merge pull request #5 from optiop/feature/ecs-infra
Add infrastructure code for ECS.
2 parents 1d8f61e + 2d881da commit 11ae2fe

File tree

18 files changed

+1004
-0
lines changed

18 files changed

+1004
-0
lines changed

ops/ecs/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Elastic Container Service (ECS) Stack
2+
3+
![Architecture](./docs/architecture.svg)
4+
5+
## Usage
6+
7+
1. Create a secret name `grafana-postgres-on-ecs` in AWS Secret Manager with the following secrets.
8+
9+
| Key | Value |
10+
| --- | --- |
11+
| `DATABASE_USERNAME` | Username for database (e.g. postgres) |
12+
| `DATABASE_PASSWORD` | Password for database (e.g. passw0rd) |
13+
| `DATABASE_HOST` | `database.service.local` |
14+
| `DATABASE_NAME` | Name of the database (e.g. sylla) |
15+
16+
2. We need to have two ECR repositories `grafana` and `postgres`. Set the variables
17+
set the `repository_name` variable in `modules/grafana/variables.tf` and `modules/postgres/variables.tf`
18+
respectively. The subdirectory `repo/ops/repository` contains the
19+
terraform code to create the ECR repositories.
20+
21+
22+
3. Add your public key to `main.tf` to allow ssh access to the EC2 instances.
23+
24+
25+
## References
26+
* [How to Deploy an AWS ECS Cluster with Terraform](https://spacelift.io/blog/terraform-ecs)]

ops/ecs/docs/architecture.svg

Lines changed: 242 additions & 0 deletions
Loading

ops/ecs/main.tf

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
module "vpc" {
2+
source = "./modules/vpc"
3+
name = "ecs-vpc"
4+
}
5+
6+
module "cluster" {
7+
source = "./modules/cluster"
8+
name = "ecs-cluster"
9+
vpc_security_group_id = module.vpc.security_group_id
10+
vpc_public_subnets = module.vpc.public_subnets
11+
12+
depends_on = [module.vpc]
13+
}
14+
15+
module "grafana" {
16+
source = "./modules/grafana"
17+
repository_name = "postgres-grafana-on-ecs-grafana-repo"
18+
cluster_id = module.cluster.cluster_id
19+
vpc_id = module.vpc.vpc_id
20+
vpc_public_subnets = module.vpc.public_subnets
21+
security_group_id = module.vpc.security_group_id
22+
namespace_id = module.vpc.namespace_id
23+
secret_manager_name = var.secret_manager_name
24+
25+
depends_on = [module.cluster]
26+
}
27+
28+
module "postgres" {
29+
source = "./modules/postgres"
30+
repository_name = "postgres-grafana-on-ecs-postgres-repo"
31+
cluster_id = module.cluster.cluster_id
32+
vpc_id = module.vpc.vpc_id
33+
vpc_public_subnets = module.vpc.public_subnets
34+
security_group_id = module.vpc.security_group_id
35+
namespace_id = module.vpc.namespace_id
36+
secret_manager_name = var.secret_manager_name
37+
38+
depends_on = [module.cluster]
39+
}

ops/ecs/modules/cluster/iam.tf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
resource "aws_iam_role" "ecsInstanceRole" {
2+
name = "ecsInstanceRole"
3+
assume_role_policy = jsonencode({
4+
Version = "2012-10-17"
5+
Statement = [
6+
{
7+
Action = "sts:AssumeRole"
8+
Principal = {
9+
Service = "ec2.amazonaws.com"
10+
},
11+
Effect = "Allow",
12+
}
13+
]
14+
})
15+
}
16+
17+
resource "aws_iam_role_policy_attachment" "ecsInstanceRole" {
18+
role = aws_iam_role.ecsInstanceRole.name
19+
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
20+
}
21+
22+
resource "aws_iam_instance_profile" "ecsInstanceRole" {
23+
name = "ecsInstanceRole"
24+
role = aws_iam_role.ecsInstanceRole.name
25+
}

ops/ecs/modules/cluster/main.tf

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Creating an ECS cluster
2+
resource "aws_ecs_cluster" "cluster" {
3+
name = var.name
4+
5+
setting {
6+
name = "containerInsights"
7+
value = "enabled"
8+
}
9+
}
10+
11+
resource "aws_launch_configuration" "ecs_cfg" {
12+
name = "ecs-instance"
13+
image_id = "ami-06581a55723db5feb"
14+
instance_type = "t2.small"
15+
16+
iam_instance_profile = aws_iam_instance_profile.ecsInstanceRole.name
17+
18+
associate_public_ip_address = true
19+
security_groups = [var.vpc_security_group_id]
20+
21+
user_data = <<EOF
22+
#!/bin/bash
23+
echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCt/+JcQz8a8UwAYaWUqGIHMWtHOkLKuzbCIy3aQwDMwxRMpEfUXThoiqOnszx8ntWEVEYpgQXJzoi2ltkL5odO1nzWxxLGUeTb3dNa8eaABvhKrrXvB7yZ/W9K2ZQ/tS5JA62zxQg+a1aFw5eT8GtiRm3Fjivo5K5PKOHQsYyYQwsu0E17K/u000+Gef9l1ZKaf/LWujISx8mpXEABFKr1IJRxTI0PeQidLHJSwoiKZ81tCfcRBi1yEJWssfgmdeZZlZvqeKKtd1Z4CXV8ez7BYFCsD3qzutUHUi2cQPTTQPJ084DN/6yPhIOuBevfXHbWxVexb6AorY/0ndPvomVIz9Oc/1B1UY1VvrtQdHwldQ3Wj4BfeHudrrsYdvDa6IgEgVYZM0ciZOGakk2/MXWUpysNtDy89TlNuIEPuZGblJ/LLIxRlF+v89is3/F16btQMz1FYwQePvpEJiMY68ZCqRf8o93D38iP0zRU8OEbfvR3fAAe3UdDXULjyFWOKMEX/yVlKwaXf+XJ6c+z/UKu8+4NtZJdU4nMmqLNc+YFsykNaPU9Grl/1lAIgP6mWZuZxqve0Ht+CqOtxnka8uwmK0DPxBJX9V+Mtj7ATgJtXnopPKvFa6ldpWmbOVU/KjiCQgNyJ6V7Z2kcQtyIBIbChU3ktts0gyquEZlFu1iJqQ== mehrshadlotfi@Mehrshads-MBP.fritz.box' >> /home/ec2-user/.ssh/authorized_keys
24+
echo ECS_CLUSTER=${var.name} >> /etc/ecs/ecs.config
25+
EOF
26+
}
27+
28+
resource "aws_autoscaling_group" "ecs_instance_asg" {
29+
launch_configuration = aws_launch_configuration.ecs_cfg.name
30+
31+
vpc_zone_identifier = var.vpc_public_subnets
32+
min_size = 1
33+
max_size = 1
34+
desired_capacity = 1
35+
36+
tag {
37+
key = "AmazonECSManaged"
38+
value = "ecs-instance"
39+
propagate_at_launch = true
40+
}
41+
}
42+
43+
resource "aws_ecs_capacity_provider" "ecs_capacity_provider" {
44+
name = "default"
45+
auto_scaling_group_provider {
46+
auto_scaling_group_arn = aws_autoscaling_group.ecs_instance_asg.arn
47+
managed_scaling {
48+
status = "ENABLED"
49+
target_capacity = 1
50+
}
51+
}
52+
}
53+
54+
resource "aws_ecs_cluster_capacity_providers" "cluster_capacity_providers" {
55+
cluster_name = aws_ecs_cluster.cluster.name
56+
capacity_providers = [aws_ecs_capacity_provider.ecs_capacity_provider.name]
57+
58+
default_capacity_provider_strategy {
59+
base = 1
60+
weight = 100
61+
capacity_provider = aws_ecs_capacity_provider.ecs_capacity_provider.name
62+
}
63+
}

ops/ecs/modules/cluster/output.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
output "cluster_id" {
2+
value = aws_ecs_cluster.cluster.id
3+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
variable "name" {
2+
type = string
3+
description = "The name of the cluster"
4+
}
5+
6+
variable "vpc_security_group_id" {
7+
type = string
8+
description = "The security group id for the ECS instances"
9+
}
10+
11+
variable "vpc_public_subnets" {
12+
type = list(string)
13+
description = "The public subnets for the ECS instances"
14+
}

ops/ecs/modules/grafana/iam.tf

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
resource "aws_iam_role" "execution_role" {
2+
name = "ecsBackendTaskExecutionRole"
3+
4+
assume_role_policy = jsonencode({
5+
Version = "2012-10-17"
6+
Statement = [
7+
{
8+
Action = "sts:AssumeRole"
9+
Effect = "Allow"
10+
Principal = {
11+
Service = "ecs-tasks.amazonaws.com"
12+
}
13+
},
14+
]
15+
})
16+
}
17+
18+
resource "aws_iam_policy" "bucket_policy" {
19+
name = "ecr-policy"
20+
description = "Policy to allow ECS to pull images from ECR"
21+
22+
policy = jsonencode({
23+
Version = "2012-10-17",
24+
Statement = [
25+
{
26+
Effect = "Allow",
27+
Action = [
28+
"ecr:*"
29+
],
30+
Resource = [
31+
data.aws_ecr_repository.repository.arn
32+
]
33+
},
34+
{
35+
Effect = "Allow",
36+
Action = [
37+
"ecr:GetAuthorizationToken"
38+
],
39+
Resource = [
40+
"*"
41+
]
42+
},
43+
{
44+
Effect = "Allow",
45+
Action = [
46+
"logs:CreateLogStream",
47+
"logs:CreateLogGroup",
48+
"logs:PutLogEvents"
49+
],
50+
Resource = [
51+
"*"
52+
]
53+
}
54+
]
55+
})
56+
}
57+
58+
59+
resource "aws_iam_role_policy_attachment" "ecsTaskExecutionRole_policy" {
60+
role = aws_iam_role.execution_role.name
61+
policy_arn = aws_iam_policy.bucket_policy.arn
62+
}

0 commit comments

Comments
 (0)