README ¶
tf-aws-module_collection-ecs_app
Overview
This module is a reference architecture terraform module that will provision a ECS service with all its dependencies in a provided ECS Cluster.
Note: Currently because of a bug with the provider, it is not possible to use terraform to perform redeploy
on the ECS Service. The bug https://github.com/hashicorp/terraform-provider-aws/issues/28070 restricts users to enable the flag force_new_deployement
on the terraform module. Hence, for now we can use this module to deploy the application to ECS Service for the first time but all the subsequent deployments needs to be performed some other way (using AWS CLI is one option).
Usage
A sample variable file example.tfvars
is available in the root directory which can be used to test this module. User needs to follow the below steps to execute this module
- Update the
example.tfvars
to manually enter values for all fields marked within<>
to make the variable file usable - Create a file
provider.tf
with the below contents
If usingprovider "aws" { profile = "<profile_name>" region = "<region_name>" }
SSO
, make sure you are logged inaws sso login --profile <profile_name>
- Make sure terraform binary is installed on your local. Use command
type terraform
to find the installation location. If you are usingasdf
, you can runasfd install
and it will install the correct terraform version for you..tool-version
contains all the dependencies. - Run the
terraform
to provision infrastructure on AWS# Initialize terraform init # Plan terraform plan -var-file example.tfvars # Apply (this is create the actual infrastructure) terraform apply -var-file example.tfvars -auto-approve
Known Issues
- When
force_new_deployment=true
, we get this error: https://github.com/hashicorp/terraform-provider-aws/issues/28070 - Access Logs in ALB: https://github.com/hashicorp/terraform-provider-aws/issues/16674
Pre-Commit hooks
.pre-commit-config.yaml file defines certain pre-commit
hooks that are relevant to terraform, golang and common linting tasks. There are no custom hooks added.
commitlint
hook enforces commit message in certain format. The commit contains the following structural elements, to communicate intent to the consumers of your commit messages:
- fix: a commit of the type
fix
patches a bug in your codebase (this correlates with PATCH in Semantic Versioning). - feat: a commit of the type
feat
introduces a new feature to the codebase (this correlates with MINOR in Semantic Versioning). - BREAKING CHANGE: a commit that has a footer
BREAKING CHANGE:
, or appends a!
after the type/scope, introduces a breaking API change (correlating with MAJOR in Semantic Versioning). A BREAKING CHANGE can be part of commits of any type. footers other than BREAKING CHANGE: may be provided and follow a convention similar to git trailer format. - build: a commit of the type
build
adds changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) - chore: a commit of the type
chore
adds changes that don't modify src or test files - ci: a commit of the type
ci
adds changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) - docs: a commit of the type
docs
adds documentation only changes - perf: a commit of the type
perf
adds code change that improves performance - refactor: a commit of the type
refactor
adds code change that neither fixes a bug nor adds a feature - revert: a commit of the type
revert
reverts a previous commit - style: a commit of the type
style
adds code changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) - test: a commit of the type
test
adds missing tests or correcting existing tests
Base configuration used for this project is commitlint-config-conventional (based on the Angular convention)
If you are a developer using vscode, this plugin may be helpful.
detect-secrets-hook
prevents new secrets from being introduced into the baseline. TODO: INSERT DOC LINK ABOUT HOOKS
In order for pre-commit
hooks to work properly
- You need to have the pre-commit package manager installed. Here are the installation instructions.
pre-commit
would install all the hooks when commit message is added by default except forcommitlint
hook.commitlint
hook would need to be installed manually using the command below
pre-commit install --hook-type commit-msg
To test the resource group module locally
- For development/enhancements to this module locally, you'll need to install all of its components. This is controlled by the
configure
target in the project'sMakefile
. Before you can runconfigure
, familiarize yourself with the variables in theMakefile
and ensure they're pointing to the right places.
make configure
This adds in several files and directories that are ignored by git
. They expose many new Make targets.
- The first target you care about is
env
. This is the common interface for setting up environment variables. The values of the environment variables will be used to authenticate with cloud provider from local development workstation.
make configure
command will bring down aws_env.sh
file on local workstation. Developer would need to modify this file, replace the environment variable values with relevant values.
These environment variables are used by terratest
integration suit.
Then run this make target to set the environment variables on developer workstation.
make env
- The first target you care about is
check
.
Pre-requisites
Before running this target it is important to ensure that, developer has created files mentioned below on local workstation under root directory of git repository that contains code for primitives/segments. Note that these files are aws
specific. If primitive/segment under development uses any other cloud provider than AWS, this section may not be relevant.
- A file named
provider.tf
with contents below
provider "aws" {
profile = "<profile_name>"
region = "<region_name>"
}
- A file named
terraform.tfvars
which contains key value pairs of variables used.
Note that since these files are added in gitignore
they would not be checked in into primitive/segment's git repo.
After creating these files, for running tests associated with the primitive/segment, run
make check
If make check
target is successful, developer is good to commit the code to primitive/segment's git repo.
make check
target
- runs
terraform commands
tolint
,validate
andplan
terraform code. - runs
conftests
.conftests
make surepolicy
checks are successful. - runs
terratest
. This is integration test suit. - runs
opa
tests
Requirements
Name | Version |
---|---|
terraform | ~> 1.0 |
aws | ~> 5.0 |
Providers
Name | Version |
---|---|
aws | 5.66.0 |
Modules
Name | Source | Version |
---|---|---|
resource_names | terraform.registry.launch.nttdata.com/module_library/resource_name/launch | ~> 2.0 |
config_bucket | terraform.registry.launch.nttdata.com/module_collection/s3_bucket/aws | ~> 1.0 |
s3_bucket | terraform-aws-modules/s3-bucket/aws | ~> 3.14.1 |
s3_bucket_objects | terraform-aws-modules/s3-bucket/aws//modules/object | ~> 3.15.1 |
sg_ecs_service | terraform-aws-modules/security-group/aws | ~> 4.17.1 |
sg_alb | terraform-aws-modules/security-group/aws | ~> 4.17.1 |
acm | terraform-aws-modules/acm/aws | ~> 4.3.2 |
alb | terraform-aws-modules/alb/aws | ~> 8.7 |
ecr | terraform.registry.launch.nttdata.com/module_collection/ecr/aws | ~> 1.0 |
container_definitions | git::https://github.com/cloudposse/terraform-aws-ecs-container-definition.git | 0.58.2 |
service_discovery_service | terraform.registry.launch.nttdata.com/module_primitive/service_discovery_service/aws | ~> 1.0 |
ecs_task_execution_policy | cloudposse/iam-policy/aws | ~> 0.4.0 |
ecs_task_policy | cloudposse/iam-policy/aws | ~> 0.4.0 |
ecs_alb_service_task | cloudposse/ecs-alb-service-task/aws | ~> 0.67.1 |
alb_dns_record | terraform.registry.launch.nttdata.com/module_primitive/dns_record/aws | ~> 1.0 |
additional_cnames | terraform.registry.launch.nttdata.com/module_primitive/dns_record/aws | ~> 1.0 |
Resources
Name | Type |
---|---|
aws_route53_zone.dns_zone | data source |
Inputs
Name | Description | Type | Default | Required |
---|---|---|---|---|
logical_product_family | (Required) Name of the product family for which the resource is created. Example: org_name, department_name. |
string |
"launch" |
no |
logical_product_service | (Required) Name of the product service for which the resource is created. For example, backend, frontend, middleware etc. |
string |
"ecs" |
no |
environment | Environment in which the resource should be provisioned like dev, qa, prod etc. | string |
"dev" |
no |
environment_number | The environment count for the respective environment. Defaults to 000. Increments in value of 1 | string |
"000" |
no |
resource_number | The resource count for the respective resource. Defaults to 000. Increments in value of 1 | string |
"000" |
no |
region | AWS Region in which the infra needs to be provisioned | string |
"us-east-2" |
no |
resource_names_map | A map of key to resource_name that will be used by tf-launch-module_library-resource_name to generate resource names | map(object({ |
{ |
no |
vpc_id | The VPC ID of the VPC where infrastructure will be provisioned | string |
n/a | yes |
private_subnets | List of private subnets. ECS services provisioned in private subnets would need NAT gateway to access internet. Internal ALBs must be provisioned in private subnets |
list(string) |
n/a | yes |
public_subnets | List of public subnets. ECS services provisioned in public subnets can access internet directly. External ALBs must be provisioned in public subnets |
list(string) |
[] |
no |
subnet_mapping | A list of subnet mapping blocks describing subnets to attach to network load balancer | list(map(string)) |
[] |
no |
ecs_cluster_arn | ARN of the ECS cluster | string |
n/a | yes |
ecs_svc_security_group | Security group for the Virtual Gateway ECS application. By default, it allows traffic from ALB on the app_port More details on how to set the below fields can be found at https://github.com/terraform-aws-modules/terraform-aws-security-group/blob/master/rules.tf |
object({ |
null |
no |
alb_sg | Security Group for the ALB. The ingress rules specified determine what ports on ALB are open to clients and the egress rules specify how ALB can talk to upstream servers (ECS in this case) More details on how to fill the below fields can be found at https://github.com/terraform-aws-modules/terraform-aws-security-group/blob/master/rules.tf |
object({ |
n/a | yes |
target_groups | List of target groups for the ALB The health_check can accept the following keys - enabled, interval, port, path, healthy_threshold, unhealthy_threshold, timeout, protocol, matcher |
list(object({ |
n/a | yes |
load_balancer_type | The type of the load balancer. Default is 'application'. Valid values are 'application' and 'network' | string |
"application" |
no |
is_internal | Whether this load balancer is internal or public facing. If is_internal=false, then var.public_subnets must be specified | bool |
true |
no |
http_tcp_listeners | List of HTTP TCP listeners | list(object({ |
[] |
no |
https_listeners | List of HTTPs listeners | list(object({ |
[] |
no |
listener_ssl_policy_default | The security policy if using HTTPS externally on the load balancer. See. | string |
"ELBSecurityPolicy-TLS13-1-0-2021-06" |
no |
redirect_to_https | Whether all http traffic should be redirected to https. Valid only for ALB when https listeners are configured | bool |
false |
no |
enable_http2 | Whether to enable HTTP/2.0 on the Application Load Balancer (not NLB). Default is false | bool |
false |
no |
enable_cross_zone_load_balancing | Indicates whether cross zone load balancing should be enabled in application load balancers. | bool |
false |
no |
subject_alternate_names | Additional domain names to be added to the certificate created for ALB. Domain names must be FQDN. | list(string) |
[] |
no |
alb_logs_bucket_id | S3 bucket ID for ALB logs | string |
"" |
no |
alb_logs_bucket_prefix | S3 bucket prefix for ALB logs | string |
null |
no |
dns_zone_name | Name of the Route53 DNS Zone where custom DNS records will be created. Required if use_https_listeners=true. var.private_zone must also be specified if this variable is not empty. By default, an A record will be created for the ALB with the name as generated by module.resource_names["alb"].standard In case, additional cnames are required, they can be specified in the additional_cnames variable |
string |
"" |
no |
private_zone | Whether the dns_zone_name provided above is a private or public hosted zone. Required if dns_zone_name is not empty. private_zone=true means the hosted zone is private and false means it is public. |
bool |
null |
no |
additional_cnames | Additional CNAME records to be created in the DNS zone pointing to the ALB. Must be FQDN in form of .<dns_zone_name> | list(string) |
[] |
no |
print_container_json | Print the container JSON object as output. Useful for debugging | bool |
false |
no |
app_environment | Environment variables to be injected into the application containers | map(string) |
{} |
no |
app_secrets | Secrets to be injected into the application containers. Map of secret Manager ARNs | map(string) |
{} |
no |
app_image | Image to be used for the application container in the form of <image>:<tag> When var.create_ecr_repo is true, this variable must be specified as <ACCOUNT_ID>.dkr.ecr.<AWS_REGION>.amazonaws.com/<var.ecr_repo_name>:<tag> . |
string |
n/a | yes |
containers | Specifications for containers to be launched in ECS for this task | list(object({ |
[] |
no |
otel_config_file_name | OpenTelemetry Configuration file name | string |
"" |
no |
bind_mount_volumes | Extra bind mount volumes to be created for this task | list(object({ name = string })) |
[] |
no |
ecs_launch_type | The launch type of the ECS service. Default is FARGATE | string |
"FARGATE" |
no |
network_mode | The network_mode of the ECS service. Default is awsvpc | string |
"awsvpc" |
no |
ignore_changes_task_definition | Lifecycle ignore policy for task definition. If true, terraform won't detect changes when task_definition is changed outside of terraform | bool |
true |
no |
assign_public_ip | If true, public IP will be assigned to this service task, else private IP | bool |
false |
no |
ignore_changes_desired_count | Lifecycle ignore policy for desired_count. If true, terraform won't detect changes when desired_count is changed outside of terraform | bool |
true |
no |
task_cpu | Amount of CPU to be allocated to the task | string |
512 |
no |
task_memory | Amount of Memory to be allocated to the task | number |
1024 |
no |
health_check_grace_period_seconds | Seconds to ignore failing load balancer health checks on newly instantiated tasks to prevent premature shutdown, up to 7200. Only valid for services configured to use load balancers | number |
0 |
no |
deployment_minimum_healthy_percent | The lower limit (as a percentage of desired_count ) of the number of tasks that must remain running and healthy in a service during a deployment |
number |
100 |
no |
deployment_maximum_percent | The upper limit of the number of tasks (as a percentage of desired_count ) that can be running in a service during a deployment |
number |
200 |
no |
desired_count | The number of instances of the task definition to place and keep running | number |
1 |
no |
deployment_controller_type | Type of deployment controller. Valid values are CODE_DEPLOY and ECS |
string |
"ECS" |
no |
wait_for_steady_state | If true, it will wait for the service to reach a steady state (like aws ecs wait services-stable) before continuing | bool |
false |
no |
redeploy_on_apply | Redeploys the service everytime a terraform apply is executed. force_new_deployment should also be true for this flag to work | bool |
false |
no |
force_new_deployment | Enable to force a new task deployment of the service when terraform apply is executed. | bool |
false |
no |
enable_service_discovery | If true, the service discovery is enabled for this ECS Service | bool |
false |
no |
service_discovery_container_name | The container name used for service discovery. Should match the name in var.containers. Mandatory in case of multiple containers | string |
"" |
no |
cloud_map_namespace_id | Cloud Map Namespace ID | string |
"" |
no |
service_discovery_service_name | Name of the Service Discovery Service | string |
"" |
no |
ecs_exec_role_custom_policy_json | Custom policy to attach to ecs task execution role. Document must be valid json. | string |
"" |
no |
ecs_role_custom_policy_json | Custom policy to attach to ecs task role. Document must be valid json. | string |
"" |
no |
create_config_bucket | Whether to create a config s3 bucket to store configurations | bool |
false |
no |
config_objects | A map of objects to be created in config_bucket, where key is the object key in s3 bucket and value is the path of the file | map(string) |
{} |
no |
kms_s3_key_arn | ARN of the AWS S3 key used for the config S3 bucket encryption | string |
"" |
no |
runtime_platform | Zero or one runtime platform configurations that containers in your task may use. Map of strings with optional keys operating_system_family and cpu_architecture .See runtime_platform docs https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition#runtime_platform |
list(map(string)) |
[] |
no |
create_ecr_repo | Whether to create an ECR repository for the application? When create_ecr_repo=true, an ecr will be created as <ACCOUNT_ID>.dkr.ecr.<AWS_REGION>.amazonaws.com/<var.ecr_repo_name> The very first apply is expected to fail, as the ECR repo will be empty. One needs to push an image to this repo and then trigger the apply again. |
bool |
false |
no |
ecr_repo_name | Name of the ECR repository. | string |
null |
no |
force_delete | Whether to delete the repository even if it contains images | bool |
false |
no |
image_tag_mutability | The tag mutability setting for the repository. Must be one of: MUTABLE or IMMUTABLE |
string |
"MUTABLE" |
no |
principals_full_access | Principal ARNs to provide with full access to the ECR | list(string) |
[] |
no |
principals_pull_though_access | Principal ARNs to provide with pull though access to the ECR | list(string) |
[] |
no |
principals_push_access | Principal ARNs to provide with push access to the ECR | list(string) |
[] |
no |
scan_images_on_push | Indicates whether images are scanned after being pushed to the repository (true) or not (false) | bool |
true |
no |
tags | A map of custom tags to be associated with the provisioned infrastructures. | map(string) |
{} |
no |
Outputs
Name | Description |
---|---|
container_json | Container json for the ECS Task Definition |
alb_dns | DNS of the Application Load Balancer |
alb_arn | ARN of the Application Load Balancer |
alb_dns_records | Custom DNS records for the ALB |
alb_additional_dns_names | Additional DNS records for the ALB |
alb_target_group_arns | ARNs of the ALB Target Groups |
alb_target_group_names | Names of the ALB Target Groups |
s3_logs_arn | ARN of S3 bucket for logs |
s3_logs_id | ID of S3 bucket for logs |
service_discovery_service_arn | ARN of Service Discovery Service |
service_discovery_service_id | ID of Service Discovery Service |
config_bucket_name | ID of the config S3 bucket |
ecs_service_arn | ECS Service ARN |
ecs_service_name | ECS Service name |
ecs_task_definition_arn | ECS task definition ARN |
ecr_repository_url | ECR Repository URL. Only valid when var.create_ecr_repo=true |