Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
60 changes: 47 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Simple Terraform module to deploy an ECS task using AWS Fargate including addons

## Example usage

### Bootstrapped setup

```hcl
module "ecr" {
source = "tbobm/ecs/aws"
Expand All @@ -19,6 +21,36 @@ module "ecr" {
}
```

### Restricted setup

Simply setup an ECS Cluster and Service based on `container.image`.

```hcl
module "ecr" {
source = "tbobm/ecs/aws"
version = "0.0.1"

container = {
image = "particuleio/helloworld"
}

vpc = {
id = "vpc-xxxxxxxx"
}
addons = {
iam = {
enabled = false
}
ecr = {
enabled = false
}
loadbalancer = {
enabled = false
}
}
}
```

## Doc generation

Code formatting and documentation for variables and outputs is generated using
Expand Down Expand Up @@ -60,27 +92,28 @@ No modules.

| Name | Type |
|------|------|
| [aws_ecr_repository.repository](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |
| [aws_ecr_repository_policy.policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource |
| [aws_ecs_cluster.cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |
| [aws_ecs_service.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_task_definition.task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |
| [aws_ecr_repository.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository) | resource |
| [aws_ecr_repository_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecr_repository_policy) | resource |
| [aws_ecs_cluster.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |
| [aws_ecs_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource |
| [aws_ecs_task_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource |
| [aws_iam_access_key.publisher](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
| [aws_iam_role.fargate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.fargate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_iam_user.publisher](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
| [aws_iam_user_policy.publisher](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy) | resource |
| [aws_lb.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource |
| [aws_lb_listener.front_end](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource |
| [aws_lb_target_group.group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource |
| [aws_subnet.subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
| [aws_subnet_ids.subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet_ids) | data source |
| [aws_vpc.vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source |
| [aws_lb.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource |
| [aws_lb_listener.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource |
| [aws_lb_target_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource |
| [aws_subnet.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
| [aws_subnet_ids.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet_ids) | data source |
| [aws_vpc.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/vpc) | data source |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_addons"></a> [addons](#input\_addons) | Configuration of each addon that can be toggles on and off | `any` | `{}` | no |
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region | `string` | `"eu-west-3"` | no |
| <a name="input_container"></a> [container](#input\_container) | Container configuration to deploy | `any` | `{}` | no |
| <a name="input_ecr_values"></a> [ecr\_values](#input\_ecr\_values) | AWS ECR configuration | `any` | `{}` | no |
Expand All @@ -92,6 +125,7 @@ No modules.

| Name | Description |
|------|-------------|
| <a name="output_addons"></a> [addons](#output\_addons) | The Addons configuration |
| <a name="output_app_url"></a> [app\_url](#output\_app\_url) | The public ALB DNS |
| <a name="output_aws_region"></a> [aws\_region](#output\_aws\_region) | The AWS region used |
| <a name="output_container_name"></a> [container\_name](#output\_container\_name) | Container name for the ECS task |
Expand Down
10 changes: 7 additions & 3 deletions ecr.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
resource "aws_ecr_repository" "repository" {
resource "aws_ecr_repository" "this" {
count = local.addons.ecr.enable ? 1 : 0

name = local.ecr["repository_name"]
image_tag_mutability = "MUTABLE"
}

resource "aws_ecr_repository_policy" "policy" {
repository = aws_ecr_repository.repository.name
resource "aws_ecr_repository_policy" "this" {
count = local.addons.ecr.enable ? 1 : 0

repository = aws_ecr_repository.this.0.name
policy = <<EOF
{
"Version": "2008-10-17",
Expand Down
26 changes: 15 additions & 11 deletions ecs.tf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
resource "aws_ecs_cluster" "cluster" {
resource "aws_ecs_cluster" "this" {
name = local.ecs["cluster_name"]
capacity_providers = ["FARGATE"]

Expand All @@ -8,12 +8,12 @@ resource "aws_ecs_cluster" "cluster" {
}
}

resource "aws_ecs_task_definition" "task" {
resource "aws_ecs_task_definition" "this" {
family = "service"
requires_compatibilities = [
"FARGATE",
]
execution_role_arn = aws_iam_role.fargate.arn
execution_role_arn = aws_iam_role.this.arn
network_mode = "awsvpc"
cpu = 256
memory = 512
Expand All @@ -33,21 +33,25 @@ resource "aws_ecs_task_definition" "task" {
])
}

resource "aws_ecs_service" "service" {
resource "aws_ecs_service" "this" {
name = local.ecs.service_name
cluster = aws_ecs_cluster.cluster.id
task_definition = aws_ecs_task_definition.task.arn
cluster = aws_ecs_cluster.this.id
task_definition = aws_ecs_task_definition.this.arn
desired_count = 1

network_configuration {
subnets = data.aws_subnet.subnets.*.id
subnets = data.aws_subnet_ids.this.ids
assign_public_ip = true
}

load_balancer {
target_group_arn = aws_lb_target_group.group.arn
container_name = local.container.name
container_port = 80
dynamic "load_balancer" {
for_each = local.addons.loadbalancer.enable ? [1] : []

content {
target_group_arn = aws_lb_target_group.this.0.arn
container_name = local.container.name
container_port = 80
}
}
deployment_controller {
type = "ECS"
Expand Down
19 changes: 17 additions & 2 deletions examples/main.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
module "ecs" {
source = "tbobm/ecs/aws"
version = "0.0.1"
source = "../"

container = {
image = var.container.image
Expand All @@ -9,6 +8,18 @@ module "ecs" {
vpc = {
id = var.vpc.id
}

addons = {
loadbalancer = {
enable = false
}
ecr = {
enable = false
}
iam = {
enable = false
}
}
}

provider "aws" {
Expand All @@ -35,3 +46,7 @@ output "this" {
sensitive = true
description = "The ECS module outputs."
}

output "addons" {
value = module.ecs.addons
}
16 changes: 10 additions & 6 deletions iam.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
resource "aws_iam_user" "publisher" {
count = local.addons.iam.enable ? 1 : 0

name = "ecr-publisher"
path = "/serviceaccounts/"
}

resource "aws_iam_role" "fargate" {
resource "aws_iam_role" "this" {
name = "fargate-role"
path = "/serviceaccounts/"
assume_role_policy = jsonencode({
Expand All @@ -26,8 +28,9 @@ resource "aws_iam_role" "fargate" {


resource "aws_iam_user_policy" "publisher" {
name = "ecr-publisher"
user = aws_iam_user.publisher.name
count = local.addons.iam.enable ? 1 : 0
name = "ecr-publisher"
user = aws_iam_user.publisher.0.name

policy = <<EOF
{
Expand Down Expand Up @@ -61,12 +64,13 @@ EOF
}

resource "aws_iam_access_key" "publisher" {
user = aws_iam_user.publisher.name
count = local.addons.iam.enable ? 1 : 0
user = aws_iam_user.publisher.0.name
}

resource "aws_iam_role_policy" "fargate" {
resource "aws_iam_role_policy" "this" {
name = "fargate-execution-role"
role = aws_iam_role.fargate.id
role = aws_iam_role.this.id

policy = <<EOF
{
Expand Down
22 changes: 14 additions & 8 deletions lb.tf
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
resource "aws_lb" "alb" {
resource "aws_lb" "this" {
count = local.addons.loadbalancer.enable == true ? 1 : 0

name = local.lb["name"]
internal = local.lb["internal"]
load_balancer_type = "application"
subnets = data.aws_subnet.subnets.*.id
subnets = data.aws_subnet.this.*.id
}

resource "aws_lb_target_group" "group" {
resource "aws_lb_target_group" "this" {
count = local.addons.loadbalancer.enable ? 1 : 0

name = local.lb.target_group["name"]
port = local.lb.target_group["port"]
protocol = local.lb.target_group["protocol"]
vpc_id = data.aws_vpc.vpc.id
vpc_id = data.aws_vpc.this.id
target_type = "ip"

depends_on = [aws_lb.alb]
depends_on = [aws_lb.this.0]
}

resource "aws_lb_listener" "front_end" {
load_balancer_arn = aws_lb.alb.arn
resource "aws_lb_listener" "this" {
count = local.addons.loadbalancer.enable ? 1 : 0

load_balancer_arn = aws_lb.this.0.arn
port = "80"
protocol = "HTTP"

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.group.arn
target_group_arn = aws_lb_target_group.this.0.arn
}
}
16 changes: 16 additions & 0 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,20 @@ locals {
ports = [80]
}
container = merge(local.container_defaults, var.container)

addons_defaults = {
loadbalancer = {
enable = true
}
ecr = {
enable = true
}
iam = {
enable = true
}
}
addons = {
for key, defaults in local.addons_defaults :
key => merge(defaults, lookup(var.addons, key, {}))
}
}
19 changes: 12 additions & 7 deletions output.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,47 @@ output "aws_region" {
}

output "app_url" {
value = aws_lb.alb.dns_name
value = local.addons.loadbalancer.enable ? aws_lb.this.0.dns_name : ""
description = "The public ALB DNS"
}

output "publisher_access_key" {
value = aws_iam_access_key.publisher.id
value = local.addons.iam.enable ? aws_iam_access_key.publisher.0.id : ""
description = "AWS_ACCESS_KEY to publish to ECR"
}

output "publisher_secret_key" {
value = aws_iam_access_key.publisher.secret
value = local.addons.iam.enable ? aws_iam_access_key.publisher.0.secret : ""
description = "AWS_SECRET_ACCESS_KEY to upload to the ECR"
sensitive = true
}

output "ecr_url" {
value = aws_ecr_repository.repository.repository_url
value = local.addons.ecr.enable ? aws_ecr_repository.this.0.repository_url : ""
description = "The ECR repository URL"
}

output "ecr_repository_name" {
value = aws_ecr_repository.repository.name
value = local.addons.ecr.enable ? aws_ecr_repository.this.0.name : ""
description = "The ECR repository name"
}

output "ecs_cluster" {
value = aws_ecs_cluster.cluster.name
value = aws_ecs_cluster.this.name
description = "The ECS cluster name"
}

output "ecs_service" {
value = aws_ecs_service.service.name
value = aws_ecs_service.this.name
description = "The ECS service name"
}

output "container_name" {
value = local.container.name
description = "Container name for the ECS task"
}

output "addons" {
value = local.addons
description = "The Addons configuration"
}
6 changes: 6 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,9 @@ variable "container" {
default = {}
description = "Container configuration to deploy"
}

variable "addons" {
type = any
default = {}
description = "Configuration of each addon that can be toggles on and off"
}
12 changes: 6 additions & 6 deletions vpc.tf
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
data "aws_vpc" "vpc" {
data "aws_vpc" "this" {
id = local.use_default_vpc ? null : local.vpc["id"]
default = local.use_default_vpc
}

data "aws_subnet_ids" "subnets" {
vpc_id = data.aws_vpc.vpc.id
data "aws_subnet_ids" "this" {
vpc_id = data.aws_vpc.this.id
}

data "aws_subnet" "subnets" {
for_each = data.aws_subnet_ids.subnets.ids
vpc_id = data.aws_vpc.vpc.id
data "aws_subnet" "this" {
for_each = data.aws_subnet_ids.this.ids
vpc_id = data.aws_vpc.this.id
id = each.value
# availability_zone = each.value
}