Contact Us | Stratusphere FinOps | StratusGrid Home | Blog
GitHub: StratusGrid/terraform-aws-ecs-fargate-codepipeline
This module creates an end-to-end fargate cluster with a single task (but can be multiple containers in the task), a CodeDeploy application deployment configuration, a CodePipeline to wrap around it, and all relevant iam roles etc.
If you get a Cycle: Error: on destroy, go remove the LB target group that is getting changes first.
terraform apply -target aws_lb_target_group.data_hub_web_http
If you get errors about the artifact.zip files, you must create the resources which get pulled into the file first, by targeting the iam roles and target groups.
terraform apply -target aws_lb_target group.<blue_target_group> -target aws_lb_target_group.<green_target_group>
terraform apply -target module.<ecs_iam_role1> -target module.<ecs_iam_role2>
Create a cluster with a single service, mapped to a single task, which has a single container:
module "ecs_app_iam_role" {
source = "StratusGrid/ecs-iam-role-builder/aws"
version = "~> 1.0"
cloudwatch_logs_policy = true
cloudwatch_logs_group_path = module.ecs_fargate_app.log_group_path
ecr_policy = true
ecr_repos = [
aws_ecr_repository.app.arn
]
custom_policy_jsons = [data.aws_iam_policy_document.bucket_access.json, data.aws_iam_policy_document.ssm_parameters.json]
role_name = "${var.name_prefix}-app${local.name_suffix}"
input_tags = merge(local.common_tags, {})
}
resource "aws_service_discovery_private_dns_namespace" "discovery_namespace" {
name = "discovery.${var.env_name}.mydomain.com"
description = "My services ${var.env_name} discovery namespace"
vpc = data.aws_vpc.vpc_microservices.id
tags = merge(local.common_tags, {})
}
resource "aws_service_discovery_service" "discovery_service" {
name = "myapp"
dns_config {
namespace_id = aws_service_discovery_private_dns_namespace.discovery_namespace.id
dns_records {
ttl = 10
type = "A"
}
}
tags = merge(local.common_tags, {})
}
Valid combinations of cpu/memory in task definition is found here
resource "aws_efs_file_system" "my_efs_vol" {
creation_token = "my-efs-vol"
tags = {
Name = "MyEFSVol"
}
}
module "ecs_fargate_app" {
source = "StratusGrid/ecs-fargate-codepipeline/aws"
# StratusGrid recommends pinning every module to a specific version
version = "x.x.x"
# source = "github.com/StratusGrid/terraform-aws-ecs-fargate-codepipeline"
ecs_cluster_name = "${var.name_prefix}-app${local.name_suffix}"
log_retention_days = 30
vpc_id = data.aws_vpc.vpc_microservices.id
input_tags = merge(local.common_tags, {})
codebuild_container_duplicator_name = aws_codebuild_project.codebuild_container_duplicator.name
ecs_services = {
service_name = local.service_name
}
}
# example of the locals file
locals {
service_name = {
service_name = "MyService"
platform_version = "1.4.0"
desired_count = 3
security_groups = ["sg-02f8f5de8655a798f","sg-031232157553fbec9"]
subnets = ["subnet-0735beb51e4293b3e","subnet-0fdc8f5dc6d101035"]
assign_public_ip = false
propagate_tags = "TASK_DEFINITION"
log_group_path = "/ecs/cluster_name/service_name"
enable_execute_command = true
service_registries = {}
# volume configs
efs_volume = {
name = "MyEFSVol"
file_system_id = aws_efs_file_system.my_efs_vol.id
root_directory = "/"
transit_encryption = null
transit_encryption_port = null
}
#NOTE: ALBs are not created by the module.
health_check_grace_period_seconds = 600
lb_listener_prod_arn = "arn:aws:elasticloadbalancing:us-east-1:123456789876:listener/app/my_prd_listener/ed9abd4ebab2925a/9176f3bfebd6457f"
lb_listener_test_arn = "arn:aws:elasticloadbalancing:us-east-1:123456789876:listener/app/my_test_listener/j6d77m8jttgd4g853/mqo39m4lcj3lfk3"
lb_target_group_blue_arn = "arn:aws:elasticloadbalancing:us-east-1:123456789876:targetgroup/my_blue_target_group/f1fec68432dd54c0"
lb_target_group_blue_name = my_blue_target_group
lb_target_group_green_name = my_green_target_group
lb_container_name = "containername" # has to match name in container definition within task_definition
lb_container_port = 8080 # has to match port in container definition within task_definition
codedeploy_role_arn = "arn:aws:iam::123456789876:role/my_codedeploy_role"
codedeploy_termination_wait_time = "5"
codebuild_auto_rollback_enabled = true
codebuild_auto_rollback_events = ["DEPLOYMENT_FAILURE"]
codepipeline_role_arn = "arn:aws:iam::123456789876:role/my_codepipeline_role"
codepipeline_source_bucket_id = "my_codepipeline_source_bucket_name"
codepipeline_source_object_key = "deployment/ecs/${var.application_name}-artifacts.zip"
container_repo_name = "my_ecr_repository"
container_target_tag = "latest" #
container_duplicate_targets = "${var.name_prefix}-${var.application_name}-ecr-repo-prd"
deployment_manual_approval = local.ecs_deployment_approval[var.env_name] // boolean for environment to deploy into (prd)
duplication_manual_approval = local.ecs_duplication_approval[var.env_name] // boolen for environment to duplicate from (dev)
use_custom_capacity_provider_strategy = true //if false, custom_capacity_provider_strategy needs to be an emtpy block = {}
custom_capacity_provider_strategy = {
primary_capacity_provider_base = 1
primary_capacity_provider = "FARGATE"
primary_capacity_provider_weight = 10
secondary_capacity_provider = "FARGATE_SPOT"
secondary_capacity_provider_weight = 1
}
taskdef_family = "MyService"
taskdef_execution_role_arn = "arn:aws:iam::123456789876:role/my_taskdef_role"
taskdef_task_role_arn = "arn:aws:iam::123456789876:role/my_taskdef_role"
taskdef_network_mode = "awsvpc"
taskdef_requires_compatibilities = [
"FARGATE"
]
taskdef_cpu = 2048
taskdef_memory = 4096
taskdef_container_definitions = <<-TASKDEF
[
{
"name": "containername",
"image": "IMAGE1_NAME",
"portMappings": [
{
"hostPort": 8080,
"protocol": "tcp",
"containerPort": 8080
}
]
}
]
TASKDEF
codepipeline_container_definitions = <<-CONTAINERDEF
[
{
"name": "containername",
"image": "<IMAGE1_NAME>",
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"secretOptions": null,
"options": {
"awslogs-group": "log-group",
"awslogs-region": "us-east-1",
"awslogs-stream-prefix": "ecs"
}
},
"portMappings": [
{
"hostPort": 8080,
"protocol": "tcp",
"containerPort": 8080
}
],
"mountPoints": [
{
"sourceVolume": "MyEFSVol",
"containerPath": "/container-mountpoint/",
"readOnly": false
}
],
"environment": [
{ "name": "ENVIRONMENT", "value": "${var.env_name == "prd" ? "production" : "development"}" }
]
}
]
CONTAINERDEF
postdeploy_codebuild_project_name = ["My_PostDeploy_Project"]
} # end of service definition
}
Name | Type |
---|---|
aws_cloudwatch_event_rule.this | resource |
aws_cloudwatch_event_target.this | resource |
aws_cloudwatch_log_group.this | resource |
aws_codedeploy_app.this | resource |
aws_codedeploy_deployment_group.this | resource |
aws_codepipeline.this | resource |
aws_ecs_cluster.this | resource |
aws_ecs_service.this | resource |
aws_ecs_task_definition.this | resource |
aws_iam_role.this | resource |
aws_iam_role_policy.this | resource |
aws_s3_bucket_object.artifacts_s3 | resource |
Name | Description | Type | Default | Required |
---|---|---|---|---|
codebuild_container_duplicator_name | Optional variable to be provided when you are pushing containers to another repo after a successful code pipeline | string |
"" |
no |
ecs_cluster_name | name to be used for ecs cluster and base log group | string |
n/a | yes |
ecs_services | List of Maps containing all settings which are configured per task definition. | map(object( |
n/a | yes |
env_name | name of environment/stage, passed in from root module | string |
n/a | yes |
input_tags | Map of tags to apply to resources | map(string) |
{ |
no |
log_retention_days | Number of days to retain logs for. Configured on Log Group which all log streams are put under. | number |
n/a | yes |
Name | Description |
---|---|
codedeploy_app_arns_map | Map of ARNs of CodeDeploy app created by this module. |
ecs_cluster_arn | ARN of ECS cluster created by this module. |
ecs_cluster_name | ARN of ECS cluster created by this module. |
- Chris Hurst GenesisChris
- Ivan Casco ivancasco-sg
- Jason Drouhard jason-drouhard
- Matt Barlow mattbarlow-sg
- Jonathan Woods stratusgrid-jw
- Angel Lopez angellopez-sg
NOTE: Manual changes to the README will be overwritten when the documentation is updated. To update the documentation, run terraform-docs -c .config/.terraform-docs.yml .