├── .github ├── FUNDING.yml ├── renovate.json └── workflows │ └── pipeline.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── examples └── test │ ├── main.tf │ └── mock_provider.tf ├── main.tf ├── outputs.tf ├── variables.tf └── versions.tf /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: jnonino 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "labels": ["enhancement"] 6 | } 7 | -------------------------------------------------------------------------------- /.github/workflows/pipeline.yml: -------------------------------------------------------------------------------- 1 | name: Terraform 2 | on: 3 | push: 4 | branches: [main] 5 | pull_request: 6 | types: [opened, reopened, synchronize] 7 | branches: [main] 8 | release: 9 | types: [published] 10 | 11 | env: 12 | DEFAULT_REGION: us-east-1 13 | AWS_ACCESS_KEY_ID: localstack 14 | AWS_SECRET_ACCESS_KEY: localstack 15 | 16 | jobs: 17 | check-format: 18 | runs-on: ubuntu-latest 19 | container: hashicorp/terraform 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | - name: Terraform Format Check 24 | run: terraform fmt -check -recursive -diff 25 | 26 | validations: 27 | runs-on: ubuntu-latest 28 | container: hashicorp/terraform 29 | strategy: 30 | matrix: { 31 | dir: ['examples/test'] 32 | } 33 | services: 34 | localstack: 35 | image: localstack/localstack 36 | env: 37 | SERVICES: apigateway,cloudformation,cloudwatch,dynamodb,es,firehose,iam,kinesis,lambda,route53,redshift,s3,secretsmanager,ses,sns,sqs,ssm,stepfunctions,sts 38 | ports: 39 | - 4566:4566 40 | steps: 41 | - name: Checkout repository 42 | uses: actions/checkout@v4 43 | - name: Terraform Init 44 | run: terraform init -upgrade 45 | working-directory: ${{ matrix.dir }} 46 | - name: Terraform Validate 47 | run: terraform validate 48 | working-directory: ${{ matrix.dir }} 49 | - name: Terraform Plan (Mock) 50 | run: terraform plan 51 | working-directory: ${{ matrix.dir }} 52 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .terraform.lock.hcl 2 | 3 | # Created by https://www.toptal.com/developers/gitignore/api/linux,macos,windows,terraform,sublimetext,visualstudiocode 4 | # Edit at https://www.toptal.com/developers/gitignore?templates=linux,macos,windows,terraform,sublimetext,visualstudiocode 5 | 6 | ### Linux ### 7 | *~ 8 | 9 | # temporary files which can be created if a process still has a handle open of a deleted file 10 | .fuse_hidden* 11 | 12 | # KDE directory preferences 13 | .directory 14 | 15 | # Linux trash folder which might appear on any partition or disk 16 | .Trash-* 17 | 18 | # .nfs files are created when an open file is removed but is still being accessed 19 | .nfs* 20 | 21 | ### macOS ### 22 | # General 23 | .DS_Store 24 | .AppleDouble 25 | .LSOverride 26 | 27 | # Icon must end with two \r 28 | Icon 29 | 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | .com.apple.timemachine.donotpresent 42 | 43 | # Directories potentially created on remote AFP share 44 | .AppleDB 45 | .AppleDesktop 46 | Network Trash Folder 47 | Temporary Items 48 | .apdisk 49 | 50 | ### macOS Patch ### 51 | # iCloud generated files 52 | *.icloud 53 | 54 | ### SublimeText ### 55 | # Cache files for Sublime Text 56 | *.tmlanguage.cache 57 | *.tmPreferences.cache 58 | *.stTheme.cache 59 | 60 | # Workspace files are user-specific 61 | *.sublime-workspace 62 | 63 | # Project files should be checked into the repository, unless a significant 64 | # proportion of contributors will probably not be using Sublime Text 65 | # *.sublime-project 66 | 67 | # SFTP configuration file 68 | sftp-config.json 69 | sftp-config-alt*.json 70 | 71 | # Package control specific files 72 | Package Control.last-run 73 | Package Control.ca-list 74 | Package Control.ca-bundle 75 | Package Control.system-ca-bundle 76 | Package Control.cache/ 77 | Package Control.ca-certs/ 78 | Package Control.merged-ca-bundle 79 | Package Control.user-ca-bundle 80 | oscrypto-ca-bundle.crt 81 | bh_unicode_properties.cache 82 | 83 | # Sublime-github package stores a github token in this file 84 | # https://packagecontrol.io/packages/sublime-github 85 | GitHub.sublime-settings 86 | 87 | ### Terraform ### 88 | # Local .terraform directories 89 | **/.terraform/* 90 | 91 | # .tfstate files 92 | *.tfstate 93 | *.tfstate.* 94 | 95 | # Crash log files 96 | crash.log 97 | crash.*.log 98 | 99 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 100 | # password, private keys, and other secrets. These should not be part of version 101 | # control as they are data points which are potentially sensitive and subject 102 | # to change depending on the environment. 103 | *.tfvars 104 | *.tfvars.json 105 | 106 | # Ignore override files as they are usually used to override resources locally and so 107 | # are not checked in 108 | override.tf 109 | override.tf.json 110 | *_override.tf 111 | *_override.tf.json 112 | 113 | # Include override files you do wish to add to version control using negated pattern 114 | # !example_override.tf 115 | 116 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 117 | # example: *tfplan* 118 | 119 | # Ignore CLI configuration files 120 | .terraformrc 121 | terraform.rc 122 | 123 | ### VisualStudioCode ### 124 | .vscode/* 125 | !.vscode/settings.json 126 | !.vscode/tasks.json 127 | !.vscode/launch.json 128 | !.vscode/extensions.json 129 | !.vscode/*.code-snippets 130 | 131 | # Local History for Visual Studio Code 132 | .history/ 133 | 134 | # Built Visual Studio Code Extensions 135 | *.vsix 136 | 137 | ### VisualStudioCode Patch ### 138 | # Ignore all local history of files 139 | .history 140 | .ionide 141 | 142 | ### Windows ### 143 | # Windows thumbnail cache files 144 | Thumbs.db 145 | Thumbs.db:encryptable 146 | ehthumbs.db 147 | ehthumbs_vista.db 148 | 149 | # Dump file 150 | *.stackdump 151 | 152 | # Folder config file 153 | [Dd]esktop.ini 154 | 155 | # Recycle Bin used on file shares 156 | $RECYCLE.BIN/ 157 | 158 | # Windows Installer files 159 | *.cab 160 | *.msi 161 | *.msix 162 | *.msm 163 | *.msp 164 | 165 | # Windows shortcuts 166 | *.lnk 167 | 168 | # End of https://www.toptal.com/developers/gitignore/api/linux,macos,windows,terraform,sublimetext,visualstudiocode 169 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.71.0 4 | hooks: 5 | - id: terraform_docs 6 | - id: terraform_fmt 7 | - id: terraform_validate 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2019 Julian Nonino, Maria Florencia Caro 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AWS ECS Service Autoscaling Module # 2 | 3 | This Terraform module deploys autoscaling alarms for an AWS ECS Fargate service. 4 | 5 | [![](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling/workflows/terraform/badge.svg)](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling/actions?query=workflow%3Aterraform) 6 | [![](https://img.shields.io/github/license/cn-terraform/terraform-aws-ecs-service-autoscaling)](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling) 7 | [![](https://img.shields.io/github/issues/cn-terraform/terraform-aws-ecs-service-autoscaling)](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling) 8 | [![](https://img.shields.io/github/issues-closed/cn-terraform/terraform-aws-ecs-service-autoscaling)](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling) 9 | [![](https://img.shields.io/github/languages/code-size/cn-terraform/terraform-aws-ecs-service-autoscaling)](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling) 10 | [![](https://img.shields.io/github/repo-size/cn-terraform/terraform-aws-ecs-service-autoscaling)](https://github.com/cn-terraform/terraform-aws-ecs-service-autoscaling) 11 | 12 | ## Usage 13 | 14 | Check valid versions on: 15 | * Github Releases: 16 | * Terraform Module Registry: 17 | 18 | ## Other modules that you may need to use this module 19 | 20 | The Networking module: 21 | * Github Releases: 22 | * Terraform Module Registry: 23 | 24 | The ECS cluster module: 25 | * Github Releases: 26 | * Terraform Module Registry: 27 | 28 | The ECS Task Definition: 29 | * Github Releases: 30 | * Terraform Module Registry: 31 | 32 | The ECS Service module: 33 | * Github Releases: 34 | * Terraform Module Registry: 35 | 36 | ## Install pre commit hooks. 37 | 38 | Pleas run this command right after cloning the repository. 39 | 40 | pre-commit install 41 | 42 | For that you may need to install the folowwing tools: 43 | * [Pre-commit](https://pre-commit.com/) 44 | * [Terraform Docs](https://terraform-docs.io/) 45 | 46 | In order to run all checks at any point run the following command: 47 | 48 | pre-commit run --all-files 49 | 50 | 51 | ## Requirements 52 | 53 | | Name | Version | 54 | |------|---------| 55 | | [terraform](#requirement\_terraform) | >= 0.13 | 56 | | [aws](#requirement\_aws) | >= 4 | 57 | 58 | ## Providers 59 | 60 | | Name | Version | 61 | |------|---------| 62 | | [aws](#provider\_aws) | 5.44.0 | 63 | 64 | ## Modules 65 | 66 | No modules. 67 | 68 | ## Resources 69 | 70 | | Name | Type | 71 | |------|------| 72 | | [aws_appautoscaling_policy.scale_down_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy) | resource | 73 | | [aws_appautoscaling_policy.scale_up_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy) | resource | 74 | | [aws_appautoscaling_target.scale_target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target) | resource | 75 | | [aws_cloudwatch_metric_alarm.cpu_high](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource | 76 | | [aws_cloudwatch_metric_alarm.cpu_low](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm) | resource | 77 | 78 | ## Inputs 79 | 80 | | Name | Description | Type | Default | Required | 81 | |------|-------------|------|---------|:--------:| 82 | | [cooldown](#input\_cooldown) | Cooldown period for scaling actions | `number` | `60` | no | 83 | | [ecs\_cluster\_name](#input\_ecs\_cluster\_name) | Name of the ECS cluster | `any` | n/a | yes | 84 | | [ecs\_service\_name](#input\_ecs\_service\_name) | Name of the ECS service | `any` | n/a | yes | 85 | | [max\_cpu\_evaluation\_period](#input\_max\_cpu\_evaluation\_period) | The number of periods over which data is compared to the specified threshold for max cpu metric alarm | `string` | `"3"` | no | 86 | | [max\_cpu\_period](#input\_max\_cpu\_period) | The period in seconds over which the specified statistic is applied for max cpu metric alarm | `string` | `"60"` | no | 87 | | [max\_cpu\_threshold](#input\_max\_cpu\_threshold) | Threshold for max CPU usage | `string` | `"85"` | no | 88 | | [min\_cpu\_evaluation\_period](#input\_min\_cpu\_evaluation\_period) | The number of periods over which data is compared to the specified threshold for min cpu metric alarm | `string` | `"3"` | no | 89 | | [min\_cpu\_period](#input\_min\_cpu\_period) | The period in seconds over which the specified statistic is applied for min cpu metric alarm | `string` | `"60"` | no | 90 | | [min\_cpu\_threshold](#input\_min\_cpu\_threshold) | Threshold for min CPU usage | `string` | `"10"` | no | 91 | | [name\_prefix](#input\_name\_prefix) | Name prefix for resources on AWS | `any` | n/a | yes | 92 | | [scale\_target\_max\_capacity](#input\_scale\_target\_max\_capacity) | The max capacity of the scalable target | `number` | `5` | no | 93 | | [scale\_target\_min\_capacity](#input\_scale\_target\_min\_capacity) | The min capacity of the scalable target | `number` | `1` | no | 94 | | [sns\_topic\_arn](#input\_sns\_topic\_arn) | The ARN of an SNS topic to send notifications on alarm actions. | `string` | `""` | no | 95 | | [tags](#input\_tags) | Resource tags | `map(string)` | `{}` | no | 96 | 97 | ## Outputs 98 | 99 | No outputs. 100 | 101 | -------------------------------------------------------------------------------- /examples/test/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | public_subnet_ids = [for s in module.base-network.public_subnets : s.id] 3 | private_subnet_ids = [for s in module.base-network.private_subnets : s.id] 4 | } 5 | 6 | module "cluster" { 7 | source = "cn-terraform/ecs-cluster/aws" 8 | name = "test" 9 | } 10 | 11 | module "base-network" { 12 | source = "cn-terraform/networking/aws" 13 | cidr_block = "192.168.0.0/16" 14 | 15 | vpc_additional_tags = { 16 | vpc_tag1 = "tag1", 17 | vpc_tag2 = "tag2", 18 | } 19 | 20 | public_subnets = { 21 | first_public_subnet = { 22 | availability_zone = "us-east-1a" 23 | cidr_block = "192.168.0.0/19" 24 | } 25 | second_public_subnet = { 26 | availability_zone = "us-east-1b" 27 | cidr_block = "192.168.32.0/19" 28 | } 29 | } 30 | 31 | public_subnets_additional_tags = { 32 | public_subnet_tag1 = "tag1", 33 | public_subnet_tag2 = "tag2", 34 | } 35 | 36 | private_subnets = { 37 | first_private_subnet = { 38 | availability_zone = "us-east-1a" 39 | cidr_block = "192.168.128.0/19" 40 | } 41 | second_private_subnet = { 42 | availability_zone = "us-east-1b" 43 | cidr_block = "192.168.160.0/19" 44 | } 45 | } 46 | 47 | private_subnets_additional_tags = { 48 | private_subnet_tag1 = "tag1", 49 | private_subnet_tag2 = "tag2", 50 | } 51 | } 52 | 53 | module "td" { 54 | source = "cn-terraform/ecs-fargate-task-definition/aws" 55 | name_prefix = "test" 56 | container_image = "ubuntu" 57 | container_name = "test" 58 | } 59 | 60 | module "service" { 61 | source = "cn-terraform/ecs-fargate-service/aws" 62 | name_prefix = "test" 63 | vpc_id = module.base-network.vpc_id 64 | ecs_cluster_arn = module.cluster.aws_ecs_cluster_cluster_arn 65 | task_definition_arn = module.td.aws_ecs_task_definition_td_arn 66 | public_subnets = local.public_subnet_ids 67 | private_subnets = local.private_subnet_ids 68 | container_name = "test" 69 | enable_autoscaling = false 70 | } 71 | 72 | module "ecs-service-autoscaling" { 73 | source = "../../" 74 | name_prefix = "test" 75 | ecs_cluster_name = module.cluster.aws_ecs_cluster_cluster_name 76 | ecs_service_name = module.service.aws_ecs_service_service_name 77 | # region = "us-east-1" 78 | # availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c", "us-east-1d"] 79 | # vpc_cidr_block = "192.168.0.0/16" 80 | # public_subnets_cidrs_per_availability_zone = ["192.168.0.0/19", "192.168.32.0/19", "192.168.64.0/19", "192.168.96.0/19"] 81 | # private_subnets_cidrs_per_availability_zone = ["192.168.128.0/19", "192.168.160.0/19", "192.168.192.0/19", "192.168.224.0/19"] 82 | } 83 | -------------------------------------------------------------------------------- /examples/test/mock_provider.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">= 4" 7 | } 8 | } 9 | } 10 | 11 | provider "aws" { 12 | region = "us-east-1" 13 | skip_credentials_validation = true 14 | skip_requesting_account_id = true 15 | skip_metadata_api_check = true 16 | s3_use_path_style = true 17 | 18 | endpoints { 19 | apigateway = "http://localstack:4566" 20 | cloudformation = "http://localstack:4566" 21 | cloudwatch = "http://localstack:4566" 22 | dynamodb = "http://localstack:4566" 23 | es = "http://localstack:4566" 24 | firehose = "http://localstack:4566" 25 | iam = "http://localstack:4566" 26 | kinesis = "http://localstack:4566" 27 | lambda = "http://localstack:4566" 28 | route53 = "http://localstack:4566" 29 | redshift = "http://localstack:4566" 30 | s3 = "http://localstack:4566" 31 | secretsmanager = "http://localstack:4566" 32 | ses = "http://localstack:4566" 33 | sns = "http://localstack:4566" 34 | sqs = "http://localstack:4566" 35 | ssm = "http://localstack:4566" 36 | stepfunctions = "http://localstack:4566" 37 | sts = "http://localstack:4566" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # AWS Auto Scaling - CloudWatch Alarm CPU High 3 | #------------------------------------------------------------------------------ 4 | resource "aws_cloudwatch_metric_alarm" "cpu_high" { 5 | alarm_name = "${var.name_prefix}-cpu-high" 6 | comparison_operator = "GreaterThanOrEqualToThreshold" 7 | evaluation_periods = var.max_cpu_evaluation_period 8 | metric_name = "CPUUtilization" 9 | namespace = "AWS/ECS" 10 | period = var.max_cpu_period 11 | statistic = "Maximum" 12 | threshold = var.max_cpu_threshold 13 | dimensions = { 14 | ClusterName = var.ecs_cluster_name 15 | ServiceName = var.ecs_service_name 16 | } 17 | alarm_actions = compact([ 18 | aws_appautoscaling_policy.scale_up_policy.arn, 19 | var.sns_topic_arn != "" ? var.sns_topic_arn : "" 20 | ]) 21 | tags = var.tags 22 | } 23 | 24 | #------------------------------------------------------------------------------ 25 | # AWS Auto Scaling - CloudWatch Alarm CPU Low 26 | #------------------------------------------------------------------------------ 27 | resource "aws_cloudwatch_metric_alarm" "cpu_low" { 28 | alarm_name = "${var.name_prefix}-cpu-low" 29 | comparison_operator = "LessThanOrEqualToThreshold" 30 | evaluation_periods = var.min_cpu_evaluation_period 31 | metric_name = "CPUUtilization" 32 | namespace = "AWS/ECS" 33 | period = var.min_cpu_period 34 | statistic = "Average" 35 | threshold = var.min_cpu_threshold 36 | dimensions = { 37 | ClusterName = var.ecs_cluster_name 38 | ServiceName = var.ecs_service_name 39 | } 40 | alarm_actions = compact([ 41 | aws_appautoscaling_policy.scale_down_policy.arn, 42 | var.sns_topic_arn != "" ? var.sns_topic_arn : "" 43 | ]) 44 | tags = var.tags 45 | } 46 | 47 | #------------------------------------------------------------------------------ 48 | # AWS Auto Scaling - Scaling Up Policy 49 | #------------------------------------------------------------------------------ 50 | resource "aws_appautoscaling_policy" "scale_up_policy" { 51 | name = "${var.name_prefix}-scale-up-policy" 52 | depends_on = [aws_appautoscaling_target.scale_target] 53 | service_namespace = "ecs" 54 | resource_id = "service/${var.ecs_cluster_name}/${var.ecs_service_name}" 55 | scalable_dimension = "ecs:service:DesiredCount" 56 | step_scaling_policy_configuration { 57 | adjustment_type = "ChangeInCapacity" 58 | cooldown = var.cooldown 59 | metric_aggregation_type = "Maximum" 60 | step_adjustment { 61 | metric_interval_lower_bound = 0 62 | scaling_adjustment = 1 63 | } 64 | } 65 | } 66 | 67 | #------------------------------------------------------------------------------ 68 | # AWS Auto Scaling - Scaling Down Policy 69 | #------------------------------------------------------------------------------ 70 | resource "aws_appautoscaling_policy" "scale_down_policy" { 71 | name = "${var.name_prefix}-scale-down-policy" 72 | depends_on = [aws_appautoscaling_target.scale_target] 73 | service_namespace = "ecs" 74 | resource_id = "service/${var.ecs_cluster_name}/${var.ecs_service_name}" 75 | scalable_dimension = "ecs:service:DesiredCount" 76 | step_scaling_policy_configuration { 77 | adjustment_type = "ChangeInCapacity" 78 | cooldown = var.cooldown 79 | metric_aggregation_type = "Maximum" 80 | step_adjustment { 81 | metric_interval_upper_bound = 0 82 | scaling_adjustment = -1 83 | } 84 | } 85 | } 86 | 87 | #------------------------------------------------------------------------------ 88 | # AWS Auto Scaling - Scaling Target 89 | #------------------------------------------------------------------------------ 90 | resource "aws_appautoscaling_target" "scale_target" { 91 | service_namespace = "ecs" 92 | resource_id = "service/${var.ecs_cluster_name}/${var.ecs_service_name}" 93 | scalable_dimension = "ecs:service:DesiredCount" 94 | min_capacity = var.scale_target_min_capacity 95 | max_capacity = var.scale_target_max_capacity 96 | } 97 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cn-terraform/terraform-aws-ecs-service-autoscaling/48f08572a659138f43ffe386c270df8d78aa0199/outputs.tf -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # Misc 3 | #------------------------------------------------------------------------------ 4 | variable "name_prefix" { 5 | description = "Name prefix for resources on AWS" 6 | } 7 | 8 | variable "tags" { 9 | type = map(string) 10 | default = {} 11 | description = "Resource tags" 12 | } 13 | 14 | #------------------------------------------------------------------------------ 15 | # AWS ECS SERVICE AUTOSCALING 16 | #------------------------------------------------------------------------------ 17 | variable "ecs_cluster_name" { 18 | description = "Name of the ECS cluster" 19 | } 20 | 21 | variable "ecs_service_name" { 22 | description = "Name of the ECS service" 23 | } 24 | 25 | variable "max_cpu_threshold" { 26 | description = "Threshold for max CPU usage" 27 | default = "85" 28 | type = string 29 | } 30 | variable "min_cpu_threshold" { 31 | description = "Threshold for min CPU usage" 32 | default = "10" 33 | type = string 34 | } 35 | 36 | variable "max_cpu_evaluation_period" { 37 | description = "The number of periods over which data is compared to the specified threshold for max cpu metric alarm" 38 | default = "3" 39 | type = string 40 | } 41 | variable "min_cpu_evaluation_period" { 42 | description = "The number of periods over which data is compared to the specified threshold for min cpu metric alarm" 43 | default = "3" 44 | type = string 45 | } 46 | 47 | variable "max_cpu_period" { 48 | description = "The period in seconds over which the specified statistic is applied for max cpu metric alarm" 49 | default = "60" 50 | type = string 51 | } 52 | variable "min_cpu_period" { 53 | description = "The period in seconds over which the specified statistic is applied for min cpu metric alarm" 54 | default = "60" 55 | type = string 56 | } 57 | 58 | variable "scale_target_max_capacity" { 59 | description = "The max capacity of the scalable target" 60 | default = 5 61 | type = number 62 | } 63 | 64 | variable "scale_target_min_capacity" { 65 | description = "The min capacity of the scalable target" 66 | default = 1 67 | type = number 68 | } 69 | 70 | variable "sns_topic_arn" { 71 | # Optional ARN of an SNS topic for sending notifications 72 | type = string 73 | description = "The ARN of an SNS topic to send notifications on alarm actions." 74 | default = "" # Set an empty string as default to avoid potential errors 75 | } 76 | variable "cooldown" { 77 | description = "Cooldown period for scaling actions" 78 | type = number 79 | default = 60 // Default value, adjust as needed 80 | } 81 | -------------------------------------------------------------------------------- /versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.13" 3 | required_providers { 4 | aws = { 5 | source = "hashicorp/aws" 6 | version = ">= 4" 7 | } 8 | } 9 | } 10 | --------------------------------------------------------------------------------