├── .github └── workflows │ └── ci.yaml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── iac ├── base-infra-cfn.yaml ├── ecr-images.yaml └── load-test-cfn.yaml ├── images ├── 500-error.png ├── Yelb-example.png ├── cfn-outputs.png ├── cloudformation-launch-stack.png ├── cloudmap.png ├── ecs-namespaces-sc-migration.png ├── ecs-namespaces.png ├── lb-example-1.png ├── lb-example-monitoring-1.png ├── monitoring-spike-example.png ├── new-ecs-console.png ├── sc-loadtest-appserver-example.png ├── sc-monitoring-example.png ├── sd-loadtest-appserver-example.png ├── service-connect-cloudmap-empty.png ├── service-connect-cloudmap-not-empty.png ├── service-connect-migration-example.png ├── service-discovery-architecture-overview.png ├── service-discovery-cloudmap-not-empty.png ├── services-example-1.png ├── services-running.png ├── tasks-example-1.png └── tasks-running.png ├── sc-update ├── svc-appserver.json ├── svc-db.json ├── svc-redis.json └── svc-ui.json └── scripts ├── cleanup.sh ├── env.sh ├── generate-traffic.sh ├── remove-service-connect.sh ├── setup.sh └── use-service-connect.sh /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "scripts/**" 9 | - "sc-update/**" 10 | - "iac/**" 11 | pull_request: 12 | branches: 13 | - main 14 | paths: 15 | - "scripts/**" 16 | - "sc-update/**" 17 | - "iac/**" 18 | 19 | env: 20 | AWS_REGION : "us-east-2" 21 | 22 | permissions: 23 | id-token: write # This is required for requesting the JWT 24 | contents: read # This is required for actions/checkout 25 | 26 | jobs: 27 | ci: 28 | strategy: 29 | max-parallel: 1 30 | matrix: 31 | include: 32 | - { os: windows-latest, shell: bash } 33 | - { os: ubuntu-latest, shell: dash } 34 | - { os: macos-latest, shell: bash } 35 | runs-on: ${{ matrix.os }} 36 | defaults: 37 | run: 38 | shell: ${{ matrix.shell}} {0} 39 | steps: 40 | - name: Checkout 41 | uses: actions/checkout@v2 42 | 43 | - name: Configure AWS credentials 44 | uses: aws-actions/configure-aws-credentials@v1 45 | with: 46 | role-to-assume: ${{ secrets.AWS_ODIC }} 47 | aws-region: ${{ env.AWS_REGION }} 48 | 49 | - name: Setup Default Profile 50 | run: | 51 | aws configure set aws_access_key_id ${{ env.AWS_ACCESS_KEY_ID }} --profile default 52 | aws configure set aws_secret_access_key ${{ env.AWS_SECRET_ACCESS_KEY }} --profile default 53 | aws configure set aws_session_token ${{ env.AWS_SESSION_TOKEN }} --profile default 54 | 55 | - name: Test Setup Script 56 | run: | 57 | ./scripts/setup.sh default ${{ env.AWS_REGION }} 58 | 59 | - name: Test Generate Traffic Script 60 | run: | 61 | ./scripts/generate-traffic.sh 62 | 63 | sleep 120 64 | 65 | - name: Test Use Service Connect Script 66 | run: | 67 | ./scripts/use-service-connect.sh 68 | 69 | sleep 300 70 | 71 | - name: Test Cleanup Script 72 | run: | 73 | ./scripts/cleanup.sh 74 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CI 2 | 3 | # Deploying Sample Yelb Application with Amazon ECS, AWS CloudFormation, and an Application Load Balancer 4 | 5 | ## Sample Application for Service Discovery to Amazon ECS Service Connect Migration 6 | 7 | This repo was created in conjunction with the AWS Blog Post [Migrate Existing Amazon ECS Services to Amazon ECS Service Connect Configured Services](https://aws.amazon.com/blogs/containers/migrate-existing-amazon-ecs-services-from-service-discovery-to-amazon-ecs-service-connect/). 8 | 9 | The Yelb application used in this demo was adapated from Massimo Re Ferrè's original application [here](https://github.com/mreferre/yelb). 10 | 11 | This reference architecture provides an easy to use YAML template for deploying a sample Yelb application using service discovery to [Amazon Elastic Container Service (Amazon ECS)](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html) with [AWS CloudFormation](https://aws.amazon.com/cloudformation/). 12 | 13 | To launch the [CloudFormation stack](iac/base-infra-cfn.yaml) you can use the 14 | provided [setup.sh](scripts/setup.sh) script located in the `scripts` folder. To 15 | run the script, you will need to have the AWS CLI installed on your system, and 16 | the minimum required AWS CLI version is `2.9.2`. 17 | 18 | The script accepts 4 optional arguments: 19 | 20 | 1. `AWS_PROFILE`: Name of the AWS CLI profile you wish to use. If you do not provide a value `default` will be used. 21 | 2. `AWS_DEFAULT_REGION`: Default Region where Cloud Formation Resources will be deployed. If you do not provide a value `us-west-2` will be used. 22 | 3. `ENVIRONMENT_NAME`: Environment Name for the Amazon ECS cluster. If you do not provide a value `ecs` will be used. 23 | 4. `CLUSTER_NAME`: Desired Amazon ECS Cluster Name. If you do not provide a value `yelb-cluster` will be used. 24 | 25 | To use the setup script with all arguments in the `us-east-2` region, you would run the following command: 26 | 27 | ```sh 28 | ./scripts/setup.sh my-profile us-east-2 my-ecs-environment my-ecs-cluster 29 | ``` 30 | 31 | The setup script will take around 5 minutes to complete. 32 | 33 | ## Overview 34 | 35 | ![infrastructure-overview](images/service-discovery-architecture-overview.png) 36 | 37 | The repository consists of a single cloudformation template that deploys the following: 38 | 39 | - An [Amazon VPC](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Introduction.html) with public and private subnets. 40 | - A highly available Amazon ECS cluster deployed across two [Availability Zones](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html). 41 | - A pair of [NAT gateways](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-nat-gateway.html) (one in each zone) to handle outbound traffic. 42 | - Four microservices deployed as [Amazon ECS services](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html) (yelb-ui, yelb-appserver, yelb-db, yelb-redis). 43 | - An [Application Load Balancer (ALB)](https://aws.amazon.com/elasticloadbalancing/applicationloadbalancer/) to the public subnets to handle inbound traffic. 44 | - Internal Load Balancer used to handle internal traffic through a private hosted zone using Route 53. 45 | - Centralized container logging with [Amazon CloudWatch Logs](http://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/WhatIsCloudWatchLogs.html). 46 | - Amazon ECS Service Definitions and Task Defintions for `yelb-db`, `yelb-redis`, `yelb-appserver`, and `yelb-ui`. 47 | 48 | ## Why use AWS CloudFormation with Amazon ECS? 49 | 50 | Using CloudFormation to deploy and manage services with Amazon ECS has a number of nice benefits over more traditional methods ([AWS CLI](https://aws.amazon.com/cli), scripting, etc.). 51 | 52 | #### Infrastructure-as-Code 53 | 54 | A template can be used repeatedly to create identical copies of the same stack (or to use as a foundation to start a new stack). Templates are simple YAML- or JSON-formatted text files that can be placed under your normal source control mechanisms, stored in private or public locations such as Amazon S3, and exchanged via email. With CloudFormation, you can see exactly which AWS resources make up a stack. You retain full control and have the ability to modify any of the AWS resources created as part of a stack. 55 | 56 | #### Self-documenting 57 | 58 | Fed up with outdated documentation on your infrastructure or environments? Still keep manual documentation of IP ranges, security group rules, etc.? 59 | 60 | With CloudFormation, your template becomes your documentation. Want to see exactly what you have deployed? Just look at your template. If you keep it in source control, then you can also look back at exactly which changes were made and by whom. 61 | 62 | #### Intelligent updating & rollback 63 | 64 | CloudFormation not only handles the initial deployment of your infrastructure and environments, but it can also manage the whole lifecycle, including future updates. During updates, you have fine-grained control and visibility over how changes are applied, using functionality such as [change sets](https://aws.amazon.com/blogs/aws/new-change-sets-for-aws-cloudformation/), [rolling update policies](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html) and [stack policies](http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/protect-stack-resources.html). 65 | 66 | ## How do I...? 67 | 68 | ### Change the VPC or subnet IP ranges 69 | 70 | The provided [CloudFormation template](iac/base-infra-cfn.yaml) deploys the following network design: 71 | 72 | | Item | CIDR Range | Usable IPs | Description | 73 | | -------------- | ------------ | ---------- | -------------------------------------------------- | 74 | | VPC | 10.0.0.0/16 | 65,534 | The whole range used for the VPC and all subnets | 75 | | Public Subnet | 10.0.0.0/19 | 8,190 | The public subnet in the first Availability Zone | 76 | | Public Subnet | 10.0.32.0/19 | 8,190 | The public subnet in the second Availability Zone | 77 | | Private Subnet | 10.0.64.0/19 | 8,190 | The private subnet in the first Availability Zone | 78 | | Private Subnet | 10.0.96.0/19 | 8,190 | The private subnet in the second Availability Zone | 79 | 80 | You can adjust the CIDR ranges used in `Mappings:` section of the [iac/ base-infra-cfn.yaml](iac/base-infra-cfn.yaml) template. Below is an example: 81 | 82 | ```yaml 83 | Mappings: 84 | # Hard values for the subnet masks. These masks define 85 | # the range of internal IP addresses that can be assigned. 86 | # The VPC can have all IP's from 10.0.0.0 to 10.0.255.255 87 | # There are four subnets which cover the ranges: 88 | # 89 | # 10.0.0.0 - 10.0.31.255 90 | # 10.0.32.0 - 10.0.63.255 91 | # 10.0.64.0 - 10.0.95.255 92 | # 10.0.96.0 - 10.0.127.255 93 | # 94 | # If you need more IP addresses (perhaps you have so many 95 | # instances that you run out) then you can customize these 96 | # ranges to add more 97 | SubnetConfig: 98 | VPC: 99 | CIDR: "10.0.0.0/16" 100 | Public1: 101 | CIDR: "10.0.0.0/19" 102 | Public2: 103 | CIDR: "10.0.32.0/19" 104 | Private1: 105 | CIDR: "10.0.64.0/19" 106 | Private2: 107 | CIDR: "10.0.96.0/19" 108 | ``` 109 | 110 | ### Generate Load Balancer traffic for Internal Load Balancer 111 | 112 | Now that you have your sample application and all required infrastructure deployed, you are ready to generate some traffic using the application endpoint. To do this, use the ./scripts/generate-traffic.sh script by running the following command: 113 | 114 | ```sh 115 | 116 | ./scripts/generate-traffic.sh 117 | ``` 118 | 119 | Once the script completes, you will see a message similar to the following: 120 | 121 | ```sh 122 | Successfully created/updated stack - hey-loadtest 123 | 124 | Running Hey Loadtest with 100 workers and 10,000 requests for 2 minutes... 125 | 126 | Please wait... 127 | 128 | Hey Loadtest for: http://yelb-serviceconnect-319970139.us-east-2.elb.amazonaws.com/ complete! 129 | View the Amazon EC2 Load Balancer Console here: https://console.aws.amazon.com/ec2/home#LoadBalancers 130 | Be sure to choose the correct region for your deployment. 131 | ``` 132 | 133 | ### Migrate from Service Discovery to Amazon ECS Service Connect 134 | 135 | Now you are ready to migrate from service discovery to Amazon ECS Service Connect. 136 | 137 | To simplify the commands needed, use the ./scripts/use-service-connect.sh script by running the following command in the shell environment of your choice: 138 | 139 | ```sh 140 | ./scripts/use-service-connect.sh 141 | ``` 142 | 143 | Once the script completes, you should see output similar to the following example: 144 | 145 | ```sh 146 | Updating yelb-db... 147 | Updating yelb-redis... 148 | Updating yelb-appserver... 149 | Updating yelb-ui... 150 | Amazon ECS Service Connect migration complete! 151 | ``` 152 | 153 | After the migration is complete, the sample application architecture will look like this: 154 | 155 | ![](images/service-connect-migration-example.png) 156 | 157 | ### Clean up 158 | 159 | To avoid future charges, clean up the resources created in this blog post. To make it easier, we created a `./scripts/cleanup.sh` script for you to use. 160 | 161 | Run the following command: 162 | 163 | ```sh 164 | ./scripts/cleanup.sh 165 | ``` 166 | 167 | > Note: The clean up script will take around 20 minutes to complete. 168 | 169 | ### Add a new item to this list 170 | 171 | If you found yourself wishing this set of frequently asked questions had an answer for a particular problem, please [submit a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/). The chances are that others will also benefit from having the answer listed here. 172 | 173 | ## Contributing 174 | 175 | Please [create a new GitHub issue](https://github.com/awslabs/ecs-refarch-cloudformation/issues/new) for any feature requests, bugs, or documentation improvements. 176 | 177 | Where possible, please also [submit a pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/) for the change. 178 | 179 | ## License 180 | 181 | MIT License 182 | 183 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 184 | 185 | Permission is hereby granted, free of charge, to any person obtaining a copy of 186 | this software and associated documentation files (the "Software"), to deal in 187 | the Software without restriction, including without limitation the rights to 188 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 189 | the Software, and to permit persons to whom the Software is furnished to do so. 190 | 191 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 192 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 193 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 194 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 195 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 196 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 197 | -------------------------------------------------------------------------------- /iac/base-infra-cfn.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: > 3 | This template provisions the infrastructure and deploys the Fargate services for use with the YELB sample application and Service Connect migration blog post. 4 | 5 | Parameters: 6 | EnvironmentName: 7 | Type: String 8 | Default: "ecs" 9 | Description: An environment name that will be prefixed to resource names 10 | 11 | HostedZoneDomainName: 12 | Type: String 13 | Default: "yelb.lb.internal" 14 | Description: Private Hosted Zone Domain Name 15 | 16 | YelbCloudMapDomain: 17 | Type: String 18 | Default: "yelb.cloudmap.internal" 19 | Description: An arbitrary internal domain name for the Yelb Ui application. It must be unique across multiple deployments. 20 | 21 | YelbServiceConnectNS: 22 | Type: String 23 | Default: "yelb.sc.internal" 24 | Description: Service connect namespace. 25 | 26 | ClusterName: 27 | Type: String 28 | Default: "yelb-cluster" 29 | Description: ECS Cluster name 30 | 31 | YelbUiServiceName: 32 | Type: String 33 | Default: "yelb-ui" 34 | Description: ECS Yelb Ui Service name 35 | 36 | YelbAppserverServiceName: 37 | Type: String 38 | Default: "yelb-appserver" 39 | Description: ECS Yelb Appserver Service name 40 | 41 | YelbRedisServiceName: 42 | Type: String 43 | Default: "yelb-redis" 44 | Description: ECS Yelb Appserver Service name 45 | 46 | YelbDbServiceName: 47 | Type: String 48 | Default: "yelb-db" 49 | Description: ECS Yelb Db Service name 50 | 51 | CentralLogGroup: 52 | Type: String 53 | Default: "ecs/serviceconnectdemo" 54 | Description: CloudWatch Log Group Name 55 | 56 | Mappings: 57 | # Hard values for the subnet masks. These masks define 58 | # the range of internal IP addresses that can be assigned. 59 | # The VPC can have all IP's from 10.0.0.0 to 10.0.255.255 60 | # There are four subnets which cover the ranges: 61 | # 62 | # 10.0.0.0 - 10.0.31.255 63 | # 10.0.32.0 - 10.0.63.255 64 | # 10.0.64.0 - 10.0.95.255 65 | # 10.0.96.0 - 10.0.127.255 66 | # 67 | # If you need more IP addresses (perhaps you have so many 68 | # instances that you run out) then you can customize these 69 | # ranges to add more 70 | SubnetConfig: 71 | VPC: 72 | CIDR: "10.0.0.0/16" 73 | Public1: 74 | CIDR: "10.0.0.0/19" 75 | Public2: 76 | CIDR: "10.0.32.0/19" 77 | Private1: 78 | CIDR: "10.0.64.0/19" 79 | Private2: 80 | CIDR: "10.0.96.0/19" 81 | 82 | Resources: 83 | # VPC in which containers will be networked. 84 | # It has two public subnets, and two private subnets. 85 | # We distribute the subnets across the first two available subnets 86 | # for the region, for high availability. 87 | VPC: 88 | Type: AWS::EC2::VPC 89 | Properties: 90 | CidrBlock: !FindInMap ["SubnetConfig", "VPC", "CIDR"] 91 | EnableDnsSupport: true 92 | EnableDnsHostnames: true 93 | Tags: 94 | - Key: Name 95 | Value: !Ref EnvironmentName 96 | 97 | # Two public subnets, where containers can have public IP addresses 98 | PublicSubnet1: 99 | Type: AWS::EC2::Subnet 100 | Properties: 101 | AvailabilityZone: 102 | Fn::Select: 103 | - 0 104 | - Fn::GetAZs: { Ref: "AWS::Region" } 105 | VpcId: !Ref "VPC" 106 | CidrBlock: !FindInMap ["SubnetConfig", "Public1", "CIDR"] 107 | MapPublicIpOnLaunch: true 108 | Tags: 109 | - Key: Name 110 | Value: !Sub ${EnvironmentName} Public Subnet (AZ1) 111 | 112 | PublicSubnet2: 113 | Type: AWS::EC2::Subnet 114 | Properties: 115 | AvailabilityZone: 116 | Fn::Select: 117 | - 1 118 | - Fn::GetAZs: { Ref: "AWS::Region" } 119 | VpcId: !Ref "VPC" 120 | CidrBlock: !FindInMap ["SubnetConfig", "Public2", "CIDR"] 121 | MapPublicIpOnLaunch: true 122 | Tags: 123 | - Key: Name 124 | Value: !Sub ${EnvironmentName} Public Subnet (AZ2) 125 | 126 | # Two private subnets where containers will only have private 127 | # IP addresses, and will only be reachable by other members of theVPC 128 | PrivateSubnet1: 129 | Type: AWS::EC2::Subnet 130 | Properties: 131 | AvailabilityZone: 132 | Fn::Select: 133 | - 0 134 | - Fn::GetAZs: { Ref: "AWS::Region" } 135 | VpcId: !Ref "VPC" 136 | CidrBlock: !FindInMap ["SubnetConfig", "Private1", "CIDR"] 137 | Tags: 138 | - Key: Name 139 | Value: !Sub ${EnvironmentName} Private Subnet (AZ1) 140 | 141 | PrivateSubnet2: 142 | Type: AWS::EC2::Subnet 143 | Properties: 144 | AvailabilityZone: 145 | Fn::Select: 146 | - 1 147 | - Fn::GetAZs: { Ref: "AWS::Region" } 148 | VpcId: !Ref "VPC" 149 | CidrBlock: !FindInMap ["SubnetConfig", "Private2", "CIDR"] 150 | Tags: 151 | - Key: Name 152 | Value: !Sub ${EnvironmentName} Private Subnet (AZ2) 153 | 154 | # Setup networking resources for the public subnets. Containers 155 | # in the public subnets have public IP addresses and the routing table sends network traffic via the internet gateway. 156 | InternetGateway: 157 | Type: AWS::EC2::InternetGateway 158 | Properties: 159 | Tags: 160 | - Key: Name 161 | Value: !Ref EnvironmentName 162 | 163 | InternetGatewayAttachment: 164 | Type: AWS::EC2::VPCGatewayAttachment 165 | Properties: 166 | InternetGatewayId: !Ref InternetGateway 167 | VpcId: !Ref VPC 168 | 169 | PublicRouteTable: 170 | Type: AWS::EC2::RouteTable 171 | Properties: 172 | VpcId: !Ref VPC 173 | Tags: 174 | - Key: Name 175 | Value: !Sub ${EnvironmentName} Public Routes 176 | 177 | DefaultPublicRoute: 178 | Type: AWS::EC2::Route 179 | DependsOn: InternetGatewayAttachment 180 | Properties: 181 | RouteTableId: !Ref PublicRouteTable 182 | DestinationCidrBlock: 0.0.0.0/0 183 | GatewayId: !Ref InternetGateway 184 | 185 | PublicSubnetOneRouteTableAssociation: 186 | Type: AWS::EC2::SubnetRouteTableAssociation 187 | Properties: 188 | RouteTableId: !Ref PublicRouteTable 189 | SubnetId: !Ref PublicSubnet1 190 | 191 | PublicSubnetTwoRouteTableAssociation: 192 | Type: AWS::EC2::SubnetRouteTableAssociation 193 | Properties: 194 | RouteTableId: !Ref PublicRouteTable 195 | SubnetId: !Ref PublicSubnet2 196 | 197 | # Setup networking resources for the private subnets. Containers 198 | # in these subnets have only private IP addresses, and must use a NAT gateway to talk to the internet. We launch two NAT gateways, one for each public subnet. 199 | NatGatewayOneEIP: 200 | Type: AWS::EC2::EIP 201 | DependsOn: InternetGatewayAttachment 202 | Properties: 203 | Domain: vpc 204 | 205 | NatGatewayTwoEIP: 206 | Type: AWS::EC2::EIP 207 | DependsOn: InternetGatewayAttachment 208 | Properties: 209 | Domain: vpc 210 | 211 | NatGateway1: 212 | Type: AWS::EC2::NatGateway 213 | Properties: 214 | AllocationId: !GetAtt NatGatewayOneEIP.AllocationId 215 | SubnetId: !Ref PublicSubnet1 216 | 217 | NatGateway2: 218 | Type: AWS::EC2::NatGateway 219 | Properties: 220 | AllocationId: !GetAtt NatGatewayTwoEIP.AllocationId 221 | SubnetId: !Ref PublicSubnet2 222 | 223 | PrivateRouteTableOne: 224 | Type: AWS::EC2::RouteTable 225 | Properties: 226 | VpcId: !Ref VPC 227 | Tags: 228 | - Key: Name 229 | Value: !Sub ${EnvironmentName} Private Routes (AZ1) 230 | 231 | DefaultPrivateRouteOne: 232 | Type: AWS::EC2::Route 233 | Properties: 234 | RouteTableId: !Ref PrivateRouteTableOne 235 | DestinationCidrBlock: 0.0.0.0/0 236 | NatGatewayId: !Ref NatGateway1 237 | 238 | PrivateSubnetOneRouteTableAssociation: 239 | Type: AWS::EC2::SubnetRouteTableAssociation 240 | Properties: 241 | RouteTableId: !Ref PrivateRouteTableOne 242 | SubnetId: !Ref PrivateSubnet1 243 | 244 | PrivateRouteTableTwo: 245 | Type: AWS::EC2::RouteTable 246 | Properties: 247 | VpcId: !Ref VPC 248 | Tags: 249 | - Key: Name 250 | Value: !Sub ${EnvironmentName} Private Routes (AZ2) 251 | 252 | DefaultPrivateRouteTwo: 253 | Type: AWS::EC2::Route 254 | Properties: 255 | RouteTableId: !Ref PrivateRouteTableTwo 256 | DestinationCidrBlock: 0.0.0.0/0 257 | NatGatewayId: !Ref NatGateway2 258 | 259 | PrivateSubnet2RouteTableAssociation: 260 | Type: AWS::EC2::SubnetRouteTableAssociation 261 | Properties: 262 | RouteTableId: !Ref PrivateRouteTableTwo 263 | SubnetId: !Ref PrivateSubnet2 264 | 265 | # ECS Resources 266 | ECSCluster: 267 | Type: AWS::ECS::Cluster 268 | Properties: 269 | ClusterName: !Ref ClusterName 270 | 271 | # Security Groups 272 | YelbDbSecurityGroup: 273 | Type: AWS::EC2::SecurityGroup 274 | Properties: 275 | GroupDescription: yelb-db security group 276 | GroupName: yelb-db-sg 277 | SecurityGroupIngress: 278 | - SourceSecurityGroupId: !Ref YelbAppServerSecurityGroup 279 | IpProtocol: tcp 280 | ToPort: 5432 281 | FromPort: 5432 282 | VpcId: !Ref VPC 283 | 284 | YelbRedisSecurityGroup: 285 | Type: AWS::EC2::SecurityGroup 286 | Properties: 287 | GroupDescription: yelb-redis security group 288 | GroupName: yelb-redis-sg 289 | SecurityGroupIngress: 290 | - SourceSecurityGroupId: !Ref YelbAppServerSecurityGroup 291 | IpProtocol: tcp 292 | ToPort: 6379 293 | FromPort: 6379 294 | VpcId: !Ref VPC 295 | 296 | YelbAppServerSecurityGroup: 297 | Type: AWS::EC2::SecurityGroup 298 | Properties: 299 | GroupDescription: yelb-appserver security group 300 | GroupName: yelb-appserver-sg 301 | VpcId: !Ref VPC 302 | SecurityGroupIngress: 303 | - SourceSecurityGroupId: !Ref YelbAppServerAlbSecurityGroup 304 | IpProtocol: tcp 305 | ToPort: 4567 306 | FromPort: 4567 307 | - SourceSecurityGroupId: !Ref YelbUiSecurityGroup 308 | IpProtocol: tcp 309 | ToPort: 4567 310 | FromPort: 4567 311 | 312 | YelbAppServerAlbSecurityGroup: 313 | Type: AWS::EC2::SecurityGroup 314 | Properties: 315 | GroupDescription: yelb-appserver ALB security group 316 | GroupName: yelb-appserver-alb-sg 317 | VpcId: !Ref VPC 318 | SecurityGroupIngress: 319 | - SourceSecurityGroupId: !Ref YelbUiSecurityGroup 320 | IpProtocol: tcp 321 | ToPort: 4567 322 | FromPort: 4567 323 | 324 | YelbUiSecurityGroup: 325 | Type: AWS::EC2::SecurityGroup 326 | Properties: 327 | GroupDescription: yelb-ui security group 328 | GroupName: yelb-ui-sg 329 | SecurityGroupIngress: 330 | - SourceSecurityGroupId: !Ref YelbLBSecurityGroup 331 | IpProtocol: tcp 332 | ToPort: 80 333 | FromPort: 80 334 | VpcId: !Ref VPC 335 | 336 | YelbLBSecurityGroup: 337 | Type: AWS::EC2::SecurityGroup 338 | Properties: 339 | GroupDescription: yelb load balancer security group 340 | GroupName: yelb-lb-sg 341 | SecurityGroupIngress: 342 | - CidrIp: "0.0.0.0/0" 343 | IpProtocol: tcp 344 | ToPort: 80 345 | FromPort: 80 346 | VpcId: !Ref VPC 347 | 348 | # Service Discovery 349 | YelbServiceConnectNameSpace: 350 | Type: AWS::ServiceDiscovery::HttpNamespace 351 | Properties: 352 | Description: "Service Connect Http Namespace for Yelb Application" 353 | Name: !Ref "YelbServiceConnectNS" 354 | 355 | YelbServiceDiscoveryNameSpace: 356 | Type: AWS::ServiceDiscovery::PrivateDnsNamespace 357 | Properties: 358 | Description: "Service Discovery Namespace for Yelb Application" 359 | Vpc: !Ref VPC 360 | Name: !Ref "YelbCloudMapDomain" 361 | 362 | YelbDbServiceDiscoveryEntry: 363 | Type: AWS::ServiceDiscovery::Service 364 | Properties: 365 | Name: !Ref YelbDbServiceName 366 | DnsConfig: 367 | DnsRecords: 368 | - Type: A 369 | TTL: "10" 370 | NamespaceId: !Ref "YelbServiceDiscoveryNameSpace" 371 | HealthCheckCustomConfig: 372 | FailureThreshold: "1" 373 | 374 | YelbRedisServiceDiscoveryEntry: 375 | Type: AWS::ServiceDiscovery::Service 376 | Properties: 377 | Name: !Ref YelbRedisServiceName 378 | DnsConfig: 379 | DnsRecords: 380 | - Type: A 381 | TTL: "10" 382 | NamespaceId: !Ref "YelbServiceDiscoveryNameSpace" 383 | HealthCheckCustomConfig: 384 | FailureThreshold: "1" 385 | 386 | # External ELB and Target Groups 387 | EcsLoadBalancer: 388 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer 389 | Properties: 390 | IpAddressType: ipv4 391 | Name: yelb-serviceconnect 392 | Scheme: internet-facing 393 | SecurityGroups: 394 | - !Ref YelbLBSecurityGroup 395 | Subnets: 396 | - !Ref PublicSubnet1 397 | - !Ref PublicSubnet2 398 | Type: application 399 | 400 | EcsLbTargetGroup: 401 | Type: AWS::ElasticLoadBalancingV2::TargetGroup 402 | Properties: 403 | Name: yelb-serviceconnect 404 | VpcId: !Ref VPC 405 | Protocol: HTTP 406 | Port: 80 407 | TargetGroupAttributes: 408 | - Key: deregistration_delay.timeout_seconds 409 | Value: '20' 410 | TargetType: ip 411 | IpAddressType: ipv4 412 | HealthCheckIntervalSeconds: 10 # Default is 30 413 | HealthyThresholdCount: 2 # Default is 5 414 | UnhealthyThresholdCount: 2 # Default is 2 415 | 416 | EcsLbListener: 417 | Type: "AWS::ElasticLoadBalancingV2::Listener" 418 | Properties: 419 | DefaultActions: 420 | - Type: forward 421 | TargetGroupArn: !Ref EcsLbTargetGroup 422 | LoadBalancerArn: !Ref EcsLoadBalancer 423 | Port: 80 424 | Protocol: HTTP 425 | 426 | # Internal ELB and Target Groups 427 | EcsInternalLoadBalancer: 428 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer 429 | Properties: 430 | IpAddressType: ipv4 431 | Name: serviceconnect-appserver 432 | Scheme: internal 433 | SecurityGroups: 434 | - !Ref YelbAppServerAlbSecurityGroup 435 | Subnets: 436 | - !Ref PrivateSubnet1 437 | - !Ref PrivateSubnet2 438 | Type: application 439 | 440 | EcsInternalTargetGroup: 441 | Type: AWS::ElasticLoadBalancingV2::TargetGroup 442 | Properties: 443 | Name: serviceconnect-appserver 444 | VpcId: !Ref VPC 445 | Protocol: HTTP 446 | Port: 4567 447 | TargetGroupAttributes: 448 | - Key: deregistration_delay.timeout_seconds 449 | Value: '20' 450 | TargetType: ip 451 | IpAddressType: ipv4 452 | HealthCheckPath: "/api/getvotes" 453 | HealthCheckIntervalSeconds: 10 # Default is 30 454 | HealthyThresholdCount: 2 # Default is 5 455 | UnhealthyThresholdCount: 2 # Default is 2 456 | 457 | EcsInternalListener: 458 | Type: "AWS::ElasticLoadBalancingV2::Listener" 459 | Properties: 460 | DefaultActions: 461 | - Type: forward 462 | TargetGroupArn: !Ref EcsInternalTargetGroup 463 | LoadBalancerArn: !Ref EcsInternalLoadBalancer 464 | Port: 4567 465 | Protocol: HTTP 466 | 467 | PrivateHostedZone: 468 | Type: "AWS::Route53::HostedZone" 469 | Properties: 470 | Name: !Ref "HostedZoneDomainName" 471 | VPCs: 472 | - VPCId: !Ref VPC 473 | VPCRegion: !Sub "${AWS::Region}" 474 | 475 | RecordSetLB: 476 | Type: AWS::Route53::RecordSet 477 | Properties: 478 | AliasTarget: 479 | DNSName: !GetAtt EcsInternalLoadBalancer.DNSName 480 | HostedZoneId: !GetAtt EcsInternalLoadBalancer.CanonicalHostedZoneID 481 | HostedZoneId: !Ref PrivateHostedZone 482 | Name: !Sub "${YelbAppserverServiceName}.${HostedZoneDomainName}" 483 | Type: A 484 | 485 | YelbECSTaskExecutionRole: 486 | Type: AWS::IAM::Role 487 | Properties: 488 | AssumeRolePolicyDocument: 489 | Statement: 490 | - Effect: Allow 491 | Principal: 492 | Service: [ecs-tasks.amazonaws.com] 493 | Action: ["sts:AssumeRole"] 494 | Path: / 495 | ManagedPolicyArns: 496 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" 497 | 498 | # Yelb DB Service and Task Definition 499 | ServiceYelbDb: 500 | Type: AWS::ECS::Service 501 | Properties: 502 | ServiceName: !Ref YelbDbServiceName 503 | LaunchType: FARGATE 504 | Cluster: !Ref ECSCluster 505 | DeploymentConfiguration: 506 | MaximumPercent: 200 507 | MinimumHealthyPercent: 0 508 | DesiredCount: 1 509 | TaskDefinition: !Ref "TaskDefinitionYelbDb" 510 | NetworkConfiguration: 511 | AwsvpcConfiguration: 512 | AssignPublicIp: DISABLED 513 | Subnets: [!Ref "PrivateSubnet1", !Ref "PrivateSubnet2"] 514 | SecurityGroups: [!Ref "YelbDbSecurityGroup"] 515 | ServiceRegistries: 516 | - RegistryArn: !GetAtt YelbDbServiceDiscoveryEntry.Arn 517 | 518 | TaskDefinitionYelbDb: 519 | Type: AWS::ECS::TaskDefinition 520 | Properties: 521 | Family: yelb-db 522 | NetworkMode: awsvpc 523 | Cpu: "256" 524 | Memory: "512" 525 | RequiresCompatibilities: 526 | - FARGATE 527 | ExecutionRoleArn: !Ref "YelbECSTaskExecutionRole" 528 | ContainerDefinitions: 529 | - Name: yelb-db 530 | Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/yelb-db:latest 531 | Cpu: 100 532 | Essential: true 533 | PortMappings: 534 | - Name: yelb-db 535 | ContainerPort: 5432 536 | Protocol: tcp 537 | LogConfiguration: 538 | LogDriver: awslogs 539 | Options: 540 | awslogs-group: !Ref CentralLogGroup 541 | awslogs-region: !Ref AWS::Region 542 | awslogs-stream-prefix: "yelb" 543 | 544 | # Yelb Redis Service and Task Definition 545 | ServiceRedisServer: 546 | Type: AWS::ECS::Service 547 | Properties: 548 | ServiceName: !Ref YelbRedisServiceName 549 | LaunchType: FARGATE 550 | Cluster: !Ref ECSCluster 551 | DeploymentConfiguration: 552 | MaximumPercent: 200 553 | MinimumHealthyPercent: 0 554 | DesiredCount: 1 555 | TaskDefinition: !Ref "TaskDefinitionRedisServer" 556 | NetworkConfiguration: 557 | AwsvpcConfiguration: 558 | AssignPublicIp: DISABLED 559 | Subnets: [!Ref "PrivateSubnet1", !Ref "PrivateSubnet2"] 560 | SecurityGroups: [!Ref "YelbRedisSecurityGroup"] 561 | ServiceRegistries: 562 | - RegistryArn: !GetAtt YelbRedisServiceDiscoveryEntry.Arn 563 | 564 | TaskDefinitionRedisServer: 565 | Type: AWS::ECS::TaskDefinition 566 | Properties: 567 | Family: redis-server 568 | NetworkMode: awsvpc 569 | Cpu: "256" 570 | Memory: "512" 571 | RequiresCompatibilities: 572 | - FARGATE 573 | ExecutionRoleArn: !Ref "YelbECSTaskExecutionRole" 574 | ContainerDefinitions: 575 | - Name: redis-server 576 | Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/redis:latest 577 | Cpu: 100 578 | Essential: true 579 | PortMappings: 580 | - Name: yelb-redis 581 | ContainerPort: 6379 582 | Protocol: tcp 583 | LogConfiguration: 584 | LogDriver: awslogs 585 | Options: 586 | awslogs-group: !Ref CentralLogGroup 587 | awslogs-region: !Ref AWS::Region 588 | awslogs-stream-prefix: "yelb" 589 | 590 | # Yelb App Server Service and Task Definition 591 | ServiceYelbAppserver: 592 | Type: AWS::ECS::Service 593 | DependsOn: 594 | - "EcsInternalLoadBalancer" 595 | - "EcsInternalTargetGroup" 596 | - "EcsInternalListener" 597 | Properties: 598 | LaunchType: FARGATE 599 | ServiceName: !Ref YelbAppserverServiceName 600 | Cluster: !Ref ECSCluster 601 | DeploymentConfiguration: 602 | MaximumPercent: 200 603 | MinimumHealthyPercent: 50 604 | DeploymentCircuitBreaker: 605 | Enable: true 606 | Rollback: true 607 | DesiredCount: 3 608 | TaskDefinition: !Ref "TaskDefinitionYelbAppserver" 609 | NetworkConfiguration: 610 | AwsvpcConfiguration: 611 | AssignPublicIp: DISABLED 612 | Subnets: [!Ref "PrivateSubnet1", !Ref "PrivateSubnet2"] 613 | SecurityGroups: [!Ref "YelbAppServerSecurityGroup"] 614 | LoadBalancers: 615 | - TargetGroupArn: !Ref EcsInternalTargetGroup 616 | ContainerName: yelb-appserver 617 | ContainerPort: 4567 618 | 619 | TaskDefinitionYelbAppserver: 620 | Type: AWS::ECS::TaskDefinition 621 | Properties: 622 | Family: yelb-appserver 623 | NetworkMode: awsvpc 624 | Cpu: "256" 625 | Memory: "512" 626 | RequiresCompatibilities: 627 | - FARGATE 628 | ExecutionRoleArn: !Ref "YelbECSTaskExecutionRole" 629 | ContainerDefinitions: 630 | - Name: yelb-appserver 631 | Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/yelb-appserver:latest 632 | Essential: true 633 | PortMappings: 634 | - Name: yelb-appserver 635 | ContainerPort: 4567 636 | Protocol: tcp 637 | AppProtocol: http 638 | Environment: 639 | - Name: APP_PORT 640 | Value: "4567" 641 | - Name: RACK_ENV 642 | Value: "custom" 643 | - Name: YELB_DB_SERVER_ENDPOINT 644 | Value: !Sub "${YelbDbServiceName}.${YelbCloudMapDomain}" 645 | - Name: REDIS_SERVER_ENDPOINT 646 | Value: !Sub "${YelbRedisServiceName}.${YelbCloudMapDomain}" 647 | LogConfiguration: 648 | LogDriver: awslogs 649 | Options: 650 | awslogs-group: !Ref CentralLogGroup 651 | awslogs-region: !Ref AWS::Region 652 | awslogs-stream-prefix: "yelb" 653 | 654 | # Yelb UI Service and Task Definition 655 | ServiceYelbUi: 656 | Type: AWS::ECS::Service 657 | DependsOn: 658 | - "EcsLoadBalancer" 659 | - "EcsLbTargetGroup" 660 | - "EcsLbListener" 661 | Properties: 662 | LaunchType: FARGATE 663 | ServiceName: !Ref YelbUiServiceName 664 | Cluster: !Ref ECSCluster 665 | DeploymentConfiguration: 666 | MaximumPercent: 200 667 | MinimumHealthyPercent: 50 668 | DeploymentCircuitBreaker: 669 | Enable: true 670 | Rollback: true 671 | DesiredCount: 3 672 | TaskDefinition: !Ref "TaskDefinitionYelbUi" 673 | NetworkConfiguration: 674 | AwsvpcConfiguration: 675 | AssignPublicIp: DISABLED 676 | Subnets: [!Ref "PrivateSubnet1", !Ref "PrivateSubnet2"] 677 | SecurityGroups: [!Ref "YelbUiSecurityGroup"] 678 | LoadBalancers: 679 | - ContainerName: "yelb-ui" 680 | ContainerPort: 80 681 | TargetGroupArn: !Ref EcsLbTargetGroup 682 | ServiceConnectConfiguration: 683 | Enabled: false 684 | 685 | TaskDefinitionYelbUi: 686 | Type: AWS::ECS::TaskDefinition 687 | Properties: 688 | Family: yelb-ui 689 | NetworkMode: awsvpc 690 | Cpu: "256" 691 | Memory: "512" 692 | RequiresCompatibilities: 693 | - FARGATE 694 | ExecutionRoleArn: !Ref "YelbECSTaskExecutionRole" 695 | ContainerDefinitions: 696 | - Name: yelb-ui 697 | Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/yelb-ui:latest 698 | PortMappings: 699 | - Name: yelb-ui 700 | ContainerPort: 80 701 | Protocol: tcp 702 | AppProtocol: http 703 | Environment: 704 | - Name: YELB_APPSERVER_ENDPOINT 705 | Value: !Sub "http://${YelbAppserverServiceName}.${HostedZoneDomainName}:4567" 706 | LogConfiguration: 707 | LogDriver: awslogs 708 | Options: 709 | awslogs-group: !Ref CentralLogGroup 710 | awslogs-region: !Ref AWS::Region 711 | awslogs-stream-prefix: "yelb" 712 | 713 | # Cloudwatch Logs 714 | CloudWatchLogGroup: 715 | Type: AWS::Logs::LogGroup 716 | Properties: 717 | LogGroupName: !Ref CentralLogGroup 718 | RetentionInDays: 7 719 | 720 | Outputs: 721 | VPC: 722 | Description: A reference to the created VPC 723 | Value: !Ref VPC 724 | Export: 725 | Name: vpcId 726 | 727 | AccountId: 728 | Description: Outputs the Account ID the stack resources are deployed to 729 | Value: !Sub "${AWS::AccountId}" 730 | Export: 731 | Name: awsAccountId 732 | 733 | StackName: 734 | Description: Outputs the stack name 735 | Value: !Sub "${AWS::StackName}" 736 | Export: 737 | Name: awsStackName 738 | 739 | ClusterName: 740 | Description: Outputs the ECS Cluster Name 741 | Value: !Ref ECSCluster 742 | Export: 743 | Name: clusterName 744 | 745 | PrivateSubnet1: 746 | Description: Outputs Private Subnet ID 747 | Value: !Ref PrivateSubnet1 748 | Export: 749 | Name: privateSubnet1 750 | 751 | Region: 752 | Description: Outputs the region the stack resources are deployed to 753 | Value: !Sub "${AWS::Region}" 754 | Export: 755 | Name: awsRegion 756 | 757 | EcsLoadBalancerDns: 758 | Description: DNS Name (ARN) of the load balancer 759 | Value: !Join 760 | - "" 761 | - - "http://" 762 | - !GetAtt EcsLoadBalancer.DNSName 763 | - "/" 764 | Export: 765 | Name: yelbEcsLoadBalancerDns 766 | -------------------------------------------------------------------------------- /iac/ecr-images.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | Description: > 3 | This template provides the ECR repositories that are used by the yelb 4 | application and is a prerequisite to the ECS resources 5 | 6 | Resources: 7 | # ECR Repositories 8 | YelbAppServerRepository: 9 | Type: AWS::ECR::Repository 10 | Properties: 11 | RepositoryName: yelb-appserver 12 | EmptyOnDelete: true 13 | 14 | YelbUiRepository: 15 | Type: AWS::ECR::Repository 16 | Properties: 17 | RepositoryName: yelb-ui 18 | EmptyOnDelete: true 19 | 20 | YelbDbRepository: 21 | Type: AWS::ECR::Repository 22 | Properties: 23 | RepositoryName: yelb-db 24 | EmptyOnDelete: true 25 | 26 | RedisRepository: 27 | Type: AWS::ECR::Repository 28 | Properties: 29 | RepositoryName: redis 30 | EmptyOnDelete: true 31 | 32 | LoadTestRepository: 33 | Type: AWS::ECR::Repository 34 | Properties: 35 | RepositoryName: hey-loadtest 36 | EmptyOnDelete: true -------------------------------------------------------------------------------- /iac/load-test-cfn.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: > 3 | Deploy a Fargate task that uses hey to generate parallel concurrent traffic 4 | Parameters: 5 | URL: 6 | Type: String 7 | Description: Url for load test 8 | 9 | Resources: 10 | # ECS Loadtest Task Execution Role 11 | ECSLoadTaskExecutionRole: 12 | Type: AWS::IAM::Role 13 | Properties: 14 | AssumeRolePolicyDocument: 15 | Statement: 16 | - Effect: Allow 17 | Principal: 18 | Service: [ecs-tasks.amazonaws.com] 19 | Action: ["sts:AssumeRole"] 20 | Path: / 21 | ManagedPolicyArns: 22 | - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" 23 | 24 | # Fargate Task 25 | TaskDefinition: 26 | Type: AWS::ECS::TaskDefinition 27 | Properties: 28 | Family: "yelb-loadtest" 29 | NetworkMode: awsvpc 30 | Cpu: "256" 31 | Memory: "512" 32 | RequiresCompatibilities: 33 | - FARGATE 34 | ExecutionRoleArn: !Ref "ECSLoadTaskExecutionRole" 35 | ContainerDefinitions: 36 | - Name: yelb-loadtest 37 | Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/hey-loadtest:latest 38 | Command: 39 | - -c 40 | - 100 41 | - -n 42 | - 10000 43 | - -z 44 | - 2m 45 | - !Sub "${URL}" 46 | LogConfiguration: 47 | LogDriver: "awslogs" 48 | Options: 49 | awslogs-group: ecs/serviceconnectdemo 50 | awslogs-region: !Ref "AWS::Region" 51 | awslogs-stream-prefix: "loadtest" 52 | -------------------------------------------------------------------------------- /images/500-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/500-error.png -------------------------------------------------------------------------------- /images/Yelb-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/Yelb-example.png -------------------------------------------------------------------------------- /images/cfn-outputs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/cfn-outputs.png -------------------------------------------------------------------------------- /images/cloudformation-launch-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/cloudformation-launch-stack.png -------------------------------------------------------------------------------- /images/cloudmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/cloudmap.png -------------------------------------------------------------------------------- /images/ecs-namespaces-sc-migration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/ecs-namespaces-sc-migration.png -------------------------------------------------------------------------------- /images/ecs-namespaces.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/ecs-namespaces.png -------------------------------------------------------------------------------- /images/lb-example-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/lb-example-1.png -------------------------------------------------------------------------------- /images/lb-example-monitoring-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/lb-example-monitoring-1.png -------------------------------------------------------------------------------- /images/monitoring-spike-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/monitoring-spike-example.png -------------------------------------------------------------------------------- /images/new-ecs-console.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/new-ecs-console.png -------------------------------------------------------------------------------- /images/sc-loadtest-appserver-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/sc-loadtest-appserver-example.png -------------------------------------------------------------------------------- /images/sc-monitoring-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/sc-monitoring-example.png -------------------------------------------------------------------------------- /images/sd-loadtest-appserver-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/sd-loadtest-appserver-example.png -------------------------------------------------------------------------------- /images/service-connect-cloudmap-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/service-connect-cloudmap-empty.png -------------------------------------------------------------------------------- /images/service-connect-cloudmap-not-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/service-connect-cloudmap-not-empty.png -------------------------------------------------------------------------------- /images/service-connect-migration-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/service-connect-migration-example.png -------------------------------------------------------------------------------- /images/service-discovery-architecture-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/service-discovery-architecture-overview.png -------------------------------------------------------------------------------- /images/service-discovery-cloudmap-not-empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/service-discovery-cloudmap-not-empty.png -------------------------------------------------------------------------------- /images/services-example-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/services-example-1.png -------------------------------------------------------------------------------- /images/services-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/services-running.png -------------------------------------------------------------------------------- /images/tasks-example-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/tasks-example-1.png -------------------------------------------------------------------------------- /images/tasks-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/ecs-service-connect-yelb-sample-app/4be3335ea86b01a1ca3868117fa2b33ecd161596/images/tasks-running.png -------------------------------------------------------------------------------- /sc-update/svc-appserver.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "namespace": "yelb.sc.internal", 4 | "services": [ 5 | { 6 | "portName": "yelb-appserver", 7 | "clientAliases": [ 8 | { 9 | "port": 4567, 10 | "dnsName": "yelb-appserver.yelb.lb.internal" 11 | } 12 | ] 13 | } 14 | ], 15 | "logConfiguration": { 16 | "logDriver": "awslogs", 17 | "options": { 18 | "awslogs-group": "ecs/serviceconnectdemo", 19 | "awslogs-region": "us-west-2", 20 | "awslogs-stream-prefix": "appserver-envoy" 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /sc-update/svc-db.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "namespace": "yelb.sc.internal", 4 | "services": [ 5 | { 6 | "portName": "yelb-db", 7 | "clientAliases": [ 8 | { 9 | "port": 5432, 10 | "dnsName": "yelb-db.yelb.cloudmap.internal" 11 | } 12 | ] 13 | } 14 | ], 15 | "logConfiguration": { 16 | "logDriver": "awslogs", 17 | "options": { 18 | "awslogs-group": "ecs/serviceconnectdemo", 19 | "awslogs-region": "us-west-2", 20 | "awslogs-stream-prefix": "db-envoy" 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /sc-update/svc-redis.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "namespace": "yelb.sc.internal", 4 | "services": [ 5 | { 6 | "portName": "yelb-redis", 7 | "clientAliases": [ 8 | { 9 | "port": 6379, 10 | "dnsName": "yelb-redis.yelb.cloudmap.internal" 11 | } 12 | ] 13 | } 14 | ], 15 | "logConfiguration": { 16 | "logDriver": "awslogs", 17 | "options": { 18 | "awslogs-group": "ecs/serviceconnectdemo", 19 | "awslogs-region": "us-west-2", 20 | "awslogs-stream-prefix": "redis-envoy" 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /sc-update/svc-ui.json: -------------------------------------------------------------------------------- 1 | { 2 | "enabled": true, 3 | "namespace": "yelb.sc.internal", 4 | "logConfiguration": { 5 | "logDriver": "awslogs", 6 | "options": { 7 | "awslogs-group": "ecs/serviceconnectdemo", 8 | "awslogs-region": "us-west-2", 9 | "awslogs-stream-prefix": "ui-envoy" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /scripts/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # This script will clean up the resources created by the CloudFormation template deployment. 5 | 6 | # Requirements: 7 | # AWS CLI Version: 2.9.2 or higher 8 | 9 | # source functions and arguments script 10 | # must use . instead of 'source' for linux runs to support /bin/dash instead of /bin/bash 11 | . ./scripts/env.sh 12 | 13 | # Get deployed region 14 | echo "Checking Cloudformation deployment region..." 15 | AWS_DEFAULT_REGION=$(cat .region) 16 | echo "Cloudformation deployment region found: ${AWS_DEFAULT_REGION}" 17 | 18 | linebreak 19 | 20 | echo "Getting AWS ECS Cluster Name..." 21 | CLUSTER_NAME=$(getOutput 'ClusterName') 22 | echo "Cluster ${CLUSTER_NAME} found!" 23 | 24 | linebreak 25 | 26 | # Clean up cloud map namespace services 27 | . ./scripts/remove-service-connect.sh 28 | 29 | linebreak 30 | 31 | # Clean up remaining deployed infrastructure by deleting the Cloud Formation Stack and wait for the delete to complete 32 | deleteCfnStack 'hey-loadtest' 33 | 34 | linebreak 35 | 36 | deleteCfnStack 'yelb-serviceconnect' 37 | 38 | linebreak 39 | 40 | deleteCfnStack 'yelb-ecr-repositories' 41 | 42 | # Final cleanup of tmp files and restore any sc-update files to original state 43 | rm -rf .region 44 | 45 | git restore ./sc-update/svc-appserver.json 46 | git restore ./sc-update/svc-db.json 47 | git restore ./sc-update/svc-redis.json 48 | git restore ./sc-update/svc-ui.json 49 | -------------------------------------------------------------------------------- /scripts/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Requirements: 5 | # AWS CLI Version: 2.9.2 or higher 6 | 7 | # This script will store all functions and arguments for the 8 | # service connect demo 9 | 10 | # NOTE: POSIX syntax does not use function and mandates the use of parenthesis 11 | 12 | # Get outputs from Cloudformation deployment 13 | getOutput () { 14 | echo $(\ 15 | aws cloudformation --region ${AWS_DEFAULT_REGION} \ 16 | describe-stacks --stack-name yelb-serviceconnect \ 17 | --query "Stacks[0].Outputs[?OutputKey=='$1'].OutputValue" --output text) 18 | } 19 | 20 | # Get Service ID for AWS Cloud Map Namespaces 21 | getServiceId () { 22 | export namespaceId=$(getNamespaceId) 23 | echo $(\ 24 | aws --region ${AWS_DEFAULT_REGION} \ 25 | servicediscovery list-services \ 26 | --filters Name="NAMESPACE_ID",Values=$namespaceId,Condition="EQ" \ 27 | --query "Services[*].Id" \ 28 | --output text 29 | ) 30 | } 31 | 32 | # Get Namespace ID for AWS Cloud Map Namespaces 33 | getNamespaceId () { 34 | echo $(\ 35 | aws --region ${AWS_DEFAULT_REGION} \ 36 | servicediscovery list-namespaces \ 37 | --query "Namespaces[?contains(Name, 'yelb.sc.internal')].Id" \ 38 | --output text 39 | ) 40 | } 41 | 42 | # Progress Spinner 43 | spinner () { 44 | local pid=$! 45 | while ps -a | awk '{print $1}' | grep -q "${pid}"; do 46 | for c in / - \\ \|; do # Loop over the sequence of spinner chars. 47 | # Print next spinner char. 48 | printf '%s\b' "$c" 49 | 50 | sleep .1 # Sleep, then continue the loop. 51 | done 52 | done 53 | } 54 | 55 | # Linebreak carriage return 56 | linebreak () { 57 | printf ' \n ' 58 | } 59 | 60 | # Delete CFN Stack 61 | deleteCfnStack () { 62 | echo "Deleting '$1' CloudFormation Stack now..." 63 | echo "Please wait..." 64 | aws --profile "${AWS_PROFILE}" \ 65 | --region "${AWS_DEFAULT_REGION}" \ 66 | cloudformation delete-stack \ 67 | --stack-name "$1" 68 | 69 | aws --profile "${AWS_PROFILE}" \ 70 | --region "${AWS_DEFAULT_REGION}" \ 71 | cloudformation wait stack-delete-complete \ 72 | --stack-name "$1" && echo "CloudFormation Stack '$1' deleted succcessfully." 73 | } 74 | 75 | # Drain Service Connect services from AWS Cloud Map 76 | drainServiceConnect () { 77 | # Update YAML files enabled key to false for roll back 78 | sed -i.bak '/"enabled":/ s/"enabled":[^,]*/"enabled": 'false'/' sc-update/svc-db.json 79 | 80 | sed -i.bak '/"enabled":/ s/"enabled":[^,]*/"enabled": 'false'/' sc-update/svc-appserver.json 81 | 82 | sed -i.bak '/"enabled":/ s/"enabled":[^,]*/"enabled": 'false'/' sc-update/svc-redis.json 83 | 84 | sed -i.bak '/"enabled":/ s/"enabled":[^,]*/"enabled": 'false'/' sc-update/svc-ui.json 85 | 86 | # make directory to store created .bak files 87 | mkdir sc-update/bak/; mv sc-update/*.bak sc-update/bak/ 88 | 89 | # # delete unnecessary files 90 | rm -rf sc-update/bak 91 | 92 | # Update services 93 | echo "Draining $SVC_DB..." 94 | aws ecs update-service \ 95 | --region "${AWS_DEFAULT_REGION}" \ 96 | --cluster $ecsName \ 97 | --service $SVC_DB \ 98 | --service-connect-configuration file://sc-update/svc-db.json >/dev/null 99 | 100 | echo "Draining $SVC_REDIS..." 101 | aws ecs update-service \ 102 | --region "${AWS_DEFAULT_REGION}" \ 103 | --cluster $ecsName \ 104 | --service $SVC_REDIS \ 105 | --service-connect-configuration file://sc-update/svc-redis.json >/dev/null 106 | 107 | echo "Draining $SVC_APPSERVER..." 108 | aws ecs update-service \ 109 | --region "${AWS_DEFAULT_REGION}" \ 110 | --cluster $ecsName \ 111 | --service $SVC_APPSERVER \ 112 | --service-connect-configuration file://sc-update/svc-appserver.json >/dev/null 113 | 114 | echo "Draining $SVC_UI..." 115 | echo "Please wait..." 116 | aws ecs update-service \ 117 | --region "${AWS_DEFAULT_REGION}" \ 118 | --cluster $ecsName \ 119 | --service $SVC_UI \ 120 | --service-connect-configuration file://sc-update/svc-ui.json >/dev/null 121 | } 122 | 123 | # Environment Variables 124 | # Namespace Records 125 | export SERVICE_CONNECT_NS="yelb.sc.internal" 126 | export CLOUD_MAP_NS="yelb.cloudmap.internal" 127 | export PRIVATE_HOSTED_ZONE_DN="yelb.lb.internal" 128 | 129 | # Service Names 130 | export SVC_APPSERVER=yelb-appserver 131 | export SVC_UI=yelb-ui 132 | export SVC_REDIS=yelb-redis 133 | export SVC_DB=yelb-db 134 | 135 | # Current working directory set as source path 136 | export SPATH=$(pwd) 137 | -------------------------------------------------------------------------------- /scripts/generate-traffic.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Requirements: 5 | # AWS CLI Version: 2.9.2 or higher 6 | 7 | # source functions and arguments script 8 | # must use . instead of 'source' for linux runs to support /bin/dash instead of /bin/bash 9 | . ./scripts/env.sh 10 | 11 | # Get deployed region 12 | echo "Checking Cloudformation deployment region..." 13 | AWS_DEFAULT_REGION=$(cat .region) 14 | echo "Cloudformation deployment region found: ${AWS_DEFAULT_REGION}" 15 | 16 | linebreak 17 | 18 | # Get outputs from CFN Setup 19 | export ecsName=$(getOutput 'ClusterName') 20 | export appEndpoint=$(getOutput 'EcsLoadBalancerDns') 21 | export privateSubnet1=$(getOutput 'PrivateSubnet1') 22 | 23 | # Deploy Hey in Fargate 24 | echo "Creating ECS Fargate Task for Load Test using Hey..." 25 | aws --region "${AWS_DEFAULT_REGION}" \ 26 | cloudformation deploy \ 27 | --stack-name "hey-loadtest" \ 28 | --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ 29 | --template-file "${SPATH}/iac/load-test-cfn.yaml" \ 30 | --parameter-overrides \ 31 | EnvironmentName="${ENVIRONMENT_NAME}" \ 32 | URL="${appEndpoint}/api/getvotes" 33 | 34 | linebreak 35 | 36 | # Run Task 37 | echo "Running Hey Loadtest with 100 workers and 10,000 requests for 2 minutes..." 38 | aws ecs run-task --region "${AWS_DEFAULT_REGION}" \ 39 | --cluster ${ecsName} \ 40 | --task-definition "yelb-loadtest" \ 41 | --network-configuration "awsvpcConfiguration={subnets=[${privateSubnet1}],assignPublicIp=DISABLED}" \ 42 | --count 1 \ 43 | --launch-type FARGATE > /dev/null 44 | 45 | linebreak 46 | 47 | echo "Please wait..." 48 | linebreak 49 | 50 | sleep 120 & 51 | spinner 52 | 53 | echo "Hey Loadtest for: ${appEndpoint} complete!" 54 | 55 | linebreak 56 | 57 | echo "View the Amazon EC2 Load Balancer Console here: https://console.aws.amazon.com/ec2/home#LoadBalancers" 58 | echo "Be sure to choose the correct region for your deployment." 59 | -------------------------------------------------------------------------------- /scripts/remove-service-connect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # source functions and arguments script 5 | # must use . instead of 'source' for linux runs to support /bin/dash instead of /bin/bash 6 | . ./scripts/env.sh 7 | 8 | # Get outputs from CFN Setup 9 | export ecsName=$(getOutput 'ClusterName') 10 | export serviceId=$(getServiceId) 11 | 12 | if [[ $serviceId ]]; then 13 | echo "Draining AWS Cloud Map and Amazon ECS Service Connect instances..." 14 | drainServiceConnect 15 | while [ -n "$serviceId" ]; do 16 | serviceId=$(getServiceId) && sleep 15; 17 | done 18 | echo 'Amazon ECS Service Connect Drain Complete!' 19 | fi 20 | -------------------------------------------------------------------------------- /scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # This script will run a CloudFormation template deployment to deploy all the 5 | # required resources into the AWS Account specified. 6 | 7 | # Requirements: 8 | # AWS CLI Version: 2.9.2 or higher 9 | 10 | # source functions and exports 11 | # must use . instead of 'source' for linux runs to support /bin/dash instead of /bin/bash 12 | . ./scripts/env.sh 13 | 14 | # Arguments 15 | # The name of the AWS CLI profile you wish to use 16 | AWS_PROFILE=$1 17 | AWS_PROFILE=${AWS_PROFILE:-default} 18 | 19 | # The default region where the CloudFormation Stack and all Resources will be deployed 20 | AWS_DEFAULT_REGION=$2 21 | AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION:-us-west-2} 22 | 23 | # Environment Name for the ECS cluster 24 | ENVIRONMENT_NAME=$3 25 | ENVIRONMENT_NAME=${ENVIRONMENT_NAME:-ecs} 26 | 27 | # ECS Cluster Name 28 | CLUSTER_NAME=$4 29 | CLUSTER_NAME=${CLUSTER_NAME:-yelb-cluster} 30 | 31 | # Get AWS Account ID and set it as environment variable 32 | if [ -z "${AWS_ACCOUNT_ID}" ]; then 33 | echo "Getting AWS Account ID..." 34 | AWS_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text) || { 35 | echo "Failed to get AWS Account ID" 36 | exit 1 37 | } 38 | fi 39 | 40 | # Create the ECR repositories 41 | echo "Creating ECR repositories" 42 | aws --profile "${AWS_PROFILE}" \ 43 | --region "${AWS_DEFAULT_REGION}" \ 44 | cloudformation deploy \ 45 | --stack-name "yelb-ecr-repositories" \ 46 | --template-file "${SPATH}/iac/ecr-images.yaml" \ 47 | 48 | # Check for container runtime 49 | if command -v docker &> /dev/null; then 50 | echo "Using Docker as container runtime" 51 | CONTAINER_CMD="docker" 52 | elif command -v finch &> /dev/null; then 53 | echo "Using Finch as container runtime" 54 | CONTAINER_CMD="finch" 55 | elif command -v podman &> /dev/null; then 56 | echo "Using Podman as container runtime" 57 | CONTAINER_CMD="podman" 58 | elif command -v nerdctl &> /dev/null; then 59 | echo "Using Nerdctl as container runtime" 60 | CONTAINER_CMD="nerdctl" 61 | else 62 | echo "No container runtime found. Please install Docker, Finch, Podman, or Nerdctl" 63 | exit 1 64 | fi 65 | 66 | # Login to ECR (required before pushing) 67 | echo "Logging into Amazon ECR" 68 | aws ecr get-login-password --region $AWS_DEFAULT_REGION | $CONTAINER_CMD login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com 69 | 70 | declare -A images=( 71 | ["mreferre/yelb-db:0.6"]="yelb-db" 72 | ["mreferre/yelb-ui:0.10"]="yelb-ui" 73 | ["mreferre/yelb-appserver:0.7"]="yelb-appserver" 74 | ["public.ecr.aws/docker/library/redis:5.0.14"]="redis" 75 | ["jldeen/hey-loadtest:1.0"]="hey-loadtest" 76 | ) 77 | 78 | # Loop through the images 79 | echo "Download the container images" 80 | for source_image in "${!images[@]}"; do 81 | repo_name="${images[$source_image]}" 82 | target_image="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$repo_name:latest" 83 | 84 | echo "Processing $source_image -> $target_image" 85 | 86 | # Pull the image 87 | echo "Pulling $source_image..." 88 | $CONTAINER_CMD pull "$source_image" 89 | 90 | # Tag the image 91 | echo "Tagging as $target_image..." 92 | $CONTAINER_CMD tag "$source_image" "$target_image" 93 | 94 | # Push to ECR 95 | echo "Pushing to ECR..." 96 | $CONTAINER_CMD push "$target_image" 97 | 98 | echo "Completed processing $repo_name" 99 | echo "----------------------------------------" 100 | done 101 | echo "All images have been processed" 102 | 103 | linebreak 104 | 105 | # Deploy the infrastructure, service definitions, and task definitions WITHOUT ECS Service Connect 106 | echo "Creating the Base Infrastructure" 107 | aws --profile "${AWS_PROFILE}" \ 108 | --region "${AWS_DEFAULT_REGION}" \ 109 | cloudformation deploy \ 110 | --stack-name "yelb-serviceconnect" \ 111 | --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM \ 112 | --template-file "${SPATH}/iac/base-infra-cfn.yaml" \ 113 | --parameter-overrides \ 114 | EnvironmentName="${ENVIRONMENT_NAME}" \ 115 | YelbCloudMapDomain="${CLOUD_MAP_NS}" \ 116 | HostedZoneDomainName="${PRIVATE_HOSTED_ZONE_DN}" \ 117 | ClusterName="${CLUSTER_NAME}" 118 | 119 | linebreak 120 | 121 | # store region for future use 122 | echo "$(getOutput 'Region')" > .region 123 | 124 | # get ELB output 125 | appEndpoint=$(getOutput 'EcsLoadBalancerDns') 126 | 127 | echo "Access your Yelb application here: ${appEndpoint}" 128 | -------------------------------------------------------------------------------- /scripts/use-service-connect.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Requirements: 5 | # AWS CLI Version: 2.9.2 or higher 6 | 7 | # source functions and arguments script 8 | # must use . instead of 'source' for linux runs to support /bin/dash instead of /bin/bash 9 | . ./scripts/env.sh 10 | 11 | # Get deployed region 12 | echo "Checking Cloudformation deployment region..." 13 | AWS_DEFAULT_REGION=$(cat .region) 14 | echo "Cloudformation deployment region found: ${AWS_DEFAULT_REGION}" 15 | 16 | linebreak 17 | 18 | # Get outputs from CFN Setup 19 | export ecsName=$(getOutput 'ClusterName') 20 | 21 | # Update YAML files with AWS_DEFAULT_REGION argument 22 | sed -i.bak 's/"awslogs-region": .*"/"awslogs-region": '\"${AWS_DEFAULT_REGION}\"'/g' sc-update/svc-db.json 23 | 24 | sed -i.bak 's/"awslogs-region": .*"/"awslogs-region": '\"${AWS_DEFAULT_REGION}\"'/g' sc-update/svc-appserver.json 25 | 26 | sed -i.bak 's/"awslogs-region": .*"/"awslogs-region": '\"${AWS_DEFAULT_REGION}\"'/g' sc-update/svc-redis.json 27 | 28 | sed -i.bak 's/"awslogs-region": .*"/"awslogs-region": '\"${AWS_DEFAULT_REGION}\"'/g' sc-update/svc-ui.json 29 | 30 | # make directory to store created .bak files 31 | mkdir sc-update/bak/; mv sc-update/*.bak sc-update/bak/ 32 | 33 | # delete unnecessary files 34 | rm -rf sc-update/bak 35 | 36 | # Update services 37 | echo "Updating $SVC_DB..." 38 | aws ecs update-service \ 39 | --region "${AWS_DEFAULT_REGION}" \ 40 | --cluster $ecsName \ 41 | --service $SVC_DB \ 42 | --service-connect-configuration file://sc-update/svc-db.json >/dev/null 43 | 44 | echo "Updating $SVC_REDIS..." 45 | aws ecs update-service \ 46 | --region "${AWS_DEFAULT_REGION}" \ 47 | --cluster $ecsName \ 48 | --service $SVC_REDIS \ 49 | --service-connect-configuration file://sc-update/svc-redis.json >/dev/null 50 | 51 | echo "Updating $SVC_APPSERVER..." 52 | aws ecs update-service \ 53 | --region "${AWS_DEFAULT_REGION}" \ 54 | --cluster $ecsName \ 55 | --service $SVC_APPSERVER \ 56 | --load-balancers "[]" \ 57 | --service-connect-configuration file://sc-update/svc-appserver.json >/dev/null 58 | 59 | echo "Updating $SVC_UI..." 60 | aws ecs update-service \ 61 | --region "${AWS_DEFAULT_REGION}" \ 62 | --cluster $ecsName \ 63 | --service $SVC_UI \ 64 | --service-connect-configuration file://sc-update/svc-ui.json >/dev/null && echo "Amazon ECS Service Connect migration complete!" 65 | --------------------------------------------------------------------------------