├── .gitignore
├── LICENSE.txt
├── README.md
├── fargate-networking-stacks
├── public-private-vpc.yml
└── public-vpc.yml
├── images
├── local-networking.png
├── private-task-private-loadbalancer.svg
├── private-task-public-loadbalancer.svg
├── private-task.svg
├── public-task-public-loadbalancer.svg
└── public-task.svg
└── service-stacks
├── private-subnet-private-loadbalancer.yml
├── private-subnet-public-loadbalancer.yml
└── public-subnet-public-loadbalancer.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
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 [yyyy] [name of copyright owner]
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 |
2 | # CloudFormation Templates for AWS Fargate deployments
3 |
4 | __Note: I have created a much more up to date collection of patterns at [Containers on AWS patterns for CloudFormation and Fargate](https://containersonaws.com/pattern/?tool=cloudformation). This collection covers a broader set of use cases, and you can use filters to more easily explore different dimensions, including various ECS features, and capacity types like EC2 as well__
5 |
6 | This is a collection of CloudFormation templates for launching containers in Fargate with a variety of different networking approaches. Fargate is designed to give you significant control over how the networking of your containers works, and these templates show how to host public facing containers, containers which are indirectly accessible to the public via a load balancer but hosted within a private network, and private containers that can not be accessed by the public.
7 |
8 | ## Instructions
9 |
10 | ### 1. Choose a Fargate cluster networking stack:
11 |
12 | Launch the stack of your choice, and give it a friendly name in CloudFormation. For example "production" or "qa". You'll be using the name of this stack later for launching a service.
13 |
14 | Choose one of the following:
15 |
16 | #### [Public VPC](fargate-networking-stacks/public-vpc.yml):
17 |
18 | 
19 |
20 | Fully public networking stack. All containers launched in this stack will have public IP addresses and can be directly accessible on the internet via an internet gateway, or indirectly accessible via a public facing load balancer. (Note that by default the security groups are configured so that the containers only accept traffic from the load balancer, even though they have public IP addresses. The capability for direct access is there if the security group is changed though.)
21 |
22 | #### [Public + Private VPC](fargate-networking-stacks/public-private-vpc.yml):
23 |
24 | 
25 |
26 | Networking stack with both public and private subnets. This stack offers the most flexibility, with the ability to host both public facing services, as well as private, internal services for which there is no public access.
27 | Containers that are run in the private subnet can access the internet via NAT
28 | gateway.
29 |
30 | ### 2. Choose a service template:
31 |
32 | There are three service templates to choose between.
33 |
34 | #### [Public Subnet, Public Load Balancer](service-stacks/public-subnet-public-loadbalancer.yml):
35 |
36 | 
37 |
38 | This template requires the public subnet or public + private subnet networking stack. It launches containers that have public IP addresses in a public subnet, so they are directly accessible to the public. It also associates the containers with a public facing load balancer.
39 |
40 | #### [Private Subnet, Public Load Balancer](service-stacks/private-subnet-public-loadbalancer.yml):
41 |
42 | 
43 |
44 | This template requires the public + private subnet networking stack. It launches containers that have no public IP address, and which are hosted in private subnet. If they need to make external requests, they can initiate outbound network traffic through a NAT gateway in the public subnets. The only way to get network traffic to these private containers is via a public facing load balancer which is hosted in the public subnets.
45 |
46 | #### [Private Subnet, Private Load Balancer](service-stacks/private-subnet-private-loadbalancer.yml):
47 |
48 | 
49 |
50 | This template requires the public + private subnet networking stack. It launches containers that are hosted in a private subnet, and have no public IP address. The containers are behind an internal load balancer which is hosted in the private subnet, with no public IP address either. This allows other containers in the subnet to make requests against the load balancer, but the load balancer is not accessible to the public internet. These private services can still initiate outbound access the internet via the NAT gateway hosted in the public subnets.
51 |
52 |
53 | Each of the above CF stacks has default values prefilled for launching a simple Nginx container, but can be customized. It's important to make sure the "StackName" value is filled in with the same name that you selected for the name of your networking stack chosen in step #1.
54 |
--------------------------------------------------------------------------------
/fargate-networking-stacks/public-private-vpc.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: This stack deploys a Fargate cluster that is in a VPC with both
3 | public and private subnets. Containers can be deployed into either
4 | the public subnets or the private subnets, and there are two load
5 | balancers. One is inside the public subnet, which can be used to
6 | send traffic to the containers in the private subnet, and one in
7 | the private subnet, which can be used for private internal traffic
8 | between internal services.
9 | Mappings:
10 | # Hard values for the subnet masks. These masks define
11 | # the range of internal IP addresses that can be assigned.
12 | # The VPC can have all IP's from 10.0.0.0 to 10.0.255.255
13 | # There are four subnets which cover the ranges:
14 | #
15 | # 10.0.0.0 - 10.0.0.255
16 | # 10.0.1.0 - 10.0.1.255
17 | # 10.0.2.0 - 10.0.2.255
18 | # 10.0.3.0 - 10.0.3.255
19 | #
20 | # If you need more IP addresses (perhaps you have so many
21 | # instances that you run out) then you can customize these
22 | # ranges to add more
23 | SubnetConfig:
24 | VPC:
25 | CIDR: '10.0.0.0/16'
26 | PublicOne:
27 | CIDR: '10.0.0.0/24'
28 | PublicTwo:
29 | CIDR: '10.0.1.0/24'
30 | PrivateOne:
31 | CIDR: '10.0.2.0/24'
32 | PrivateTwo:
33 | CIDR: '10.0.3.0/24'
34 | Resources:
35 | # VPC in which containers will be networked.
36 | # It has two public subnets, and two private subnets.
37 | # We distribute the subnets across the first two available subnets
38 | # for the region, for high availability.
39 | VPC:
40 | Type: AWS::EC2::VPC
41 | Properties:
42 | EnableDnsSupport: true
43 | EnableDnsHostnames: true
44 | CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
45 |
46 | # Two public subnets, where containers can have public IP addresses
47 | PublicSubnetOne:
48 | Type: AWS::EC2::Subnet
49 | Properties:
50 | AvailabilityZone:
51 | Fn::Select:
52 | - 0
53 | - Fn::GetAZs: {Ref: 'AWS::Region'}
54 | VpcId: !Ref 'VPC'
55 | CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
56 | MapPublicIpOnLaunch: true
57 | PublicSubnetTwo:
58 | Type: AWS::EC2::Subnet
59 | Properties:
60 | AvailabilityZone:
61 | Fn::Select:
62 | - 1
63 | - Fn::GetAZs: {Ref: 'AWS::Region'}
64 | VpcId: !Ref 'VPC'
65 | CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
66 | MapPublicIpOnLaunch: true
67 |
68 | # Two private subnets where containers will only have private
69 | # IP addresses, and will only be reachable by other members of the
70 | # VPC
71 | PrivateSubnetOne:
72 | Type: AWS::EC2::Subnet
73 | Properties:
74 | AvailabilityZone:
75 | Fn::Select:
76 | - 0
77 | - Fn::GetAZs: {Ref: 'AWS::Region'}
78 | VpcId: !Ref 'VPC'
79 | CidrBlock: !FindInMap ['SubnetConfig', 'PrivateOne', 'CIDR']
80 | PrivateSubnetTwo:
81 | Type: AWS::EC2::Subnet
82 | Properties:
83 | AvailabilityZone:
84 | Fn::Select:
85 | - 1
86 | - Fn::GetAZs: {Ref: 'AWS::Region'}
87 | VpcId: !Ref 'VPC'
88 | CidrBlock: !FindInMap ['SubnetConfig', 'PrivateTwo', 'CIDR']
89 |
90 | # Setup networking resources for the public subnets. Containers
91 | # in the public subnets have public IP addresses and the routing table
92 | # sends network traffic via the internet gateway.
93 | InternetGateway:
94 | Type: AWS::EC2::InternetGateway
95 | GatewayAttachement:
96 | Type: AWS::EC2::VPCGatewayAttachment
97 | Properties:
98 | VpcId: !Ref 'VPC'
99 | InternetGatewayId: !Ref 'InternetGateway'
100 | PublicRouteTable:
101 | Type: AWS::EC2::RouteTable
102 | Properties:
103 | VpcId: !Ref 'VPC'
104 | PublicRoute:
105 | Type: AWS::EC2::Route
106 | DependsOn: GatewayAttachement
107 | Properties:
108 | RouteTableId: !Ref 'PublicRouteTable'
109 | DestinationCidrBlock: '0.0.0.0/0'
110 | GatewayId: !Ref 'InternetGateway'
111 | PublicSubnetOneRouteTableAssociation:
112 | Type: AWS::EC2::SubnetRouteTableAssociation
113 | Properties:
114 | SubnetId: !Ref PublicSubnetOne
115 | RouteTableId: !Ref PublicRouteTable
116 | PublicSubnetTwoRouteTableAssociation:
117 | Type: AWS::EC2::SubnetRouteTableAssociation
118 | Properties:
119 | SubnetId: !Ref PublicSubnetTwo
120 | RouteTableId: !Ref PublicRouteTable
121 |
122 | # Setup networking resources for the private subnets. Containers
123 | # in these subnets have only private IP addresses, and must use a NAT
124 | # gateway to talk to the internet. We launch two NAT gateways, one for
125 | # each private subnet.
126 | NatGatewayOneAttachment:
127 | Type: AWS::EC2::EIP
128 | DependsOn: GatewayAttachement
129 | Properties:
130 | Domain: vpc
131 | NatGatewayTwoAttachment:
132 | Type: AWS::EC2::EIP
133 | DependsOn: GatewayAttachement
134 | Properties:
135 | Domain: vpc
136 | NatGatewayOne:
137 | Type: AWS::EC2::NatGateway
138 | Properties:
139 | AllocationId: !GetAtt NatGatewayOneAttachment.AllocationId
140 | SubnetId: !Ref PublicSubnetOne
141 | NatGatewayTwo:
142 | Type: AWS::EC2::NatGateway
143 | Properties:
144 | AllocationId: !GetAtt NatGatewayTwoAttachment.AllocationId
145 | SubnetId: !Ref PublicSubnetTwo
146 | PrivateRouteTableOne:
147 | Type: AWS::EC2::RouteTable
148 | Properties:
149 | VpcId: !Ref 'VPC'
150 | PrivateRouteOne:
151 | Type: AWS::EC2::Route
152 | Properties:
153 | RouteTableId: !Ref PrivateRouteTableOne
154 | DestinationCidrBlock: 0.0.0.0/0
155 | NatGatewayId: !Ref NatGatewayOne
156 | PrivateRouteTableOneAssociation:
157 | Type: AWS::EC2::SubnetRouteTableAssociation
158 | Properties:
159 | RouteTableId: !Ref PrivateRouteTableOne
160 | SubnetId: !Ref PrivateSubnetOne
161 | PrivateRouteTableTwo:
162 | Type: AWS::EC2::RouteTable
163 | Properties:
164 | VpcId: !Ref 'VPC'
165 | PrivateRouteTwo:
166 | Type: AWS::EC2::Route
167 | Properties:
168 | RouteTableId: !Ref PrivateRouteTableTwo
169 | DestinationCidrBlock: 0.0.0.0/0
170 | NatGatewayId: !Ref NatGatewayTwo
171 | PrivateRouteTableTwoAssociation:
172 | Type: AWS::EC2::SubnetRouteTableAssociation
173 | Properties:
174 | RouteTableId: !Ref PrivateRouteTableTwo
175 | SubnetId: !Ref PrivateSubnetTwo
176 |
177 | # OPTIONAL: VPC Endpoint for DynamoDB
178 | # If a container needs to access DynamoDB this allows a container in the private subnet
179 | # to talk to DynamoDB directly without needing to go via the NAT gateway. This reduces
180 | # the amount of bandwidth through the gateway, meaning that the gateway is free to serve
181 | # your other traffic.
182 | DynamoDBEndpoint:
183 | Type: AWS::EC2::VPCEndpoint
184 | Properties:
185 | PolicyDocument:
186 | Version: "2012-10-17"
187 | Statement:
188 | - Effect: Allow
189 | Action: "*"
190 | Principal: "*"
191 | Resource: "*"
192 | RouteTableIds:
193 | - !Ref 'PrivateRouteTableOne'
194 | - !Ref 'PrivateRouteTableTwo'
195 | ServiceName: !Join [ "", [ "com.amazonaws.", { "Ref": "AWS::Region" }, ".dynamodb" ] ]
196 | VpcId: !Ref 'VPC'
197 |
198 | # ECS Resources
199 | ECSCluster:
200 | Type: AWS::ECS::Cluster
201 |
202 | # A security group for the containers we will run in Fargate.
203 | # Three rules, allowing network traffic from a public facing load
204 | # balancer, a private internal load balancer, and from other members
205 | # of the security group.
206 | #
207 | # Remove any of the following ingress rules that are not needed.
208 | FargateContainerSecurityGroup:
209 | Type: AWS::EC2::SecurityGroup
210 | Properties:
211 | GroupDescription: Access to the Fargate containers
212 | VpcId: !Ref 'VPC'
213 | EcsSecurityGroupIngressFromPublicALB:
214 | Type: AWS::EC2::SecurityGroupIngress
215 | Properties:
216 | Description: Ingress from the public ALB
217 | GroupId: !Ref 'FargateContainerSecurityGroup'
218 | IpProtocol: -1
219 | SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'
220 | EcsSecurityGroupIngressFromPrivateALB:
221 | Type: AWS::EC2::SecurityGroupIngress
222 | Properties:
223 | Description: Ingress from the private ALB
224 | GroupId: !Ref 'FargateContainerSecurityGroup'
225 | IpProtocol: -1
226 | SourceSecurityGroupId: !Ref 'PrivateLoadBalancerSG'
227 | EcsSecurityGroupIngressFromSelf:
228 | Type: AWS::EC2::SecurityGroupIngress
229 | Properties:
230 | Description: Ingress from other containers in the same security group
231 | GroupId: !Ref 'FargateContainerSecurityGroup'
232 | IpProtocol: -1
233 | SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup'
234 |
235 | # Load balancers for getting traffic to containers.
236 | # This sample template creates two load balancers:
237 | #
238 | # - One public load balancer, hosted in public subnets that is accessible
239 | # to the public, and is intended to route traffic to one or more public
240 | # facing services.
241 | # - One private load balancer, hosted in private subnets, that only
242 | # accepts traffic from other containers in the Fargate cluster, and is
243 | # intended for private services that should not be accessed directly
244 | # by the public.
245 |
246 | # A public facing load balancer, this is used for accepting traffic from the public
247 | # internet and directing it to public facing microservices
248 | PublicLoadBalancerSG:
249 | Type: AWS::EC2::SecurityGroup
250 | Properties:
251 | GroupDescription: Access to the public facing load balancer
252 | VpcId: !Ref 'VPC'
253 | SecurityGroupIngress:
254 | # Allow access to ALB from anywhere on the internet
255 | - CidrIp: 0.0.0.0/0
256 | IpProtocol: -1
257 | PublicLoadBalancer:
258 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer
259 | Properties:
260 | Scheme: internet-facing
261 | LoadBalancerAttributes:
262 | - Key: idle_timeout.timeout_seconds
263 | Value: '30'
264 | Subnets:
265 | # The load balancer is placed into the public subnets, so that traffic
266 | # from the internet can reach the load balancer directly via the internet gateway
267 | - !Ref PublicSubnetOne
268 | - !Ref PublicSubnetTwo
269 | SecurityGroups: [!Ref 'PublicLoadBalancerSG']
270 | # A dummy target group is used to setup the ALB to just drop traffic
271 | # initially, before any real service target groups have been added.
272 | DummyTargetGroupPublic:
273 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
274 | Properties:
275 | HealthCheckIntervalSeconds: 6
276 | HealthCheckPath: /
277 | HealthCheckProtocol: HTTP
278 | HealthCheckTimeoutSeconds: 5
279 | HealthyThresholdCount: 2
280 | Name: !Join ['-', [!Ref 'AWS::StackName', 'drop-1']]
281 | Port: 80
282 | Protocol: HTTP
283 | UnhealthyThresholdCount: 2
284 | VpcId: !Ref 'VPC'
285 | PublicLoadBalancerListener:
286 | Type: AWS::ElasticLoadBalancingV2::Listener
287 | DependsOn:
288 | - PublicLoadBalancer
289 | Properties:
290 | DefaultActions:
291 | - TargetGroupArn: !Ref 'DummyTargetGroupPublic'
292 | Type: 'forward'
293 | LoadBalancerArn: !Ref 'PublicLoadBalancer'
294 | Port: 80
295 | Protocol: HTTP
296 |
297 | # An internal load balancer, this would be used for a service that is not
298 | # directly accessible to the public, but instead should only receive traffic
299 | # from your other services.
300 | PrivateLoadBalancerSG:
301 | Type: AWS::EC2::SecurityGroup
302 | Properties:
303 | GroupDescription: Access to the internal load balancer
304 | VpcId: !Ref 'VPC'
305 | PrivateLoadBalancerIngressFromECS:
306 | Type: AWS::EC2::SecurityGroupIngress
307 | Properties:
308 | Description: Only accept traffic from a container in the fargate container security group
309 | GroupId: !Ref 'PrivateLoadBalancerSG'
310 | IpProtocol: -1
311 | SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup'
312 | PrivateLoadBalancer:
313 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer
314 | Properties:
315 | Scheme: internal
316 | LoadBalancerAttributes:
317 | - Key: idle_timeout.timeout_seconds
318 | Value: '30'
319 | Subnets:
320 | # This load balancer is put into the private subnet, so that there is no
321 | # route for the public to even be able to access the private load balancer.
322 | - !Ref PrivateSubnetOne
323 | - !Ref PrivateSubnetTwo
324 | SecurityGroups: [!Ref 'PrivateLoadBalancerSG']
325 | # This dummy target group is used to setup the ALB to just drop traffic
326 | # initially, before any real service target groups have been added.
327 | DummyTargetGroupPrivate:
328 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
329 | Properties:
330 | HealthCheckIntervalSeconds: 6
331 | HealthCheckPath: /
332 | HealthCheckProtocol: HTTP
333 | HealthCheckTimeoutSeconds: 5
334 | HealthyThresholdCount: 2
335 | Name: !Join ['-', [!Ref 'AWS::StackName', 'drop-2']]
336 | Port: 80
337 | Protocol: HTTP
338 | UnhealthyThresholdCount: 2
339 | VpcId: !Ref 'VPC'
340 | PrivateLoadBalancerListener:
341 | Type: AWS::ElasticLoadBalancingV2::Listener
342 | DependsOn:
343 | - PrivateLoadBalancer
344 | Properties:
345 | DefaultActions:
346 | - TargetGroupArn: !Ref 'DummyTargetGroupPrivate'
347 | Type: 'forward'
348 | LoadBalancerArn: !Ref 'PrivateLoadBalancer'
349 | Port: 80
350 | Protocol: HTTP
351 |
352 | # This is an IAM role which authorizes ECS to manage resources on your
353 | # account on your behalf, such as updating your load balancer with the
354 | # details of where your containers are, so that traffic can reach your
355 | # containers.
356 | ECSRole:
357 | Type: AWS::IAM::Role
358 | Properties:
359 | AssumeRolePolicyDocument:
360 | Statement:
361 | - Effect: Allow
362 | Principal:
363 | Service: [ecs.amazonaws.com]
364 | Action: ['sts:AssumeRole']
365 | Path: /
366 | Policies:
367 | - PolicyName: ecs-service
368 | PolicyDocument:
369 | Statement:
370 | - Effect: Allow
371 | Action:
372 | # Rules which allow ECS to attach network interfaces to instances
373 | # on your behalf in order for awsvpc networking mode to work right
374 | - 'ec2:AttachNetworkInterface'
375 | - 'ec2:CreateNetworkInterface'
376 | - 'ec2:CreateNetworkInterfacePermission'
377 | - 'ec2:DeleteNetworkInterface'
378 | - 'ec2:DeleteNetworkInterfacePermission'
379 | - 'ec2:Describe*'
380 | - 'ec2:DetachNetworkInterface'
381 |
382 | # Rules which allow ECS to update load balancers on your behalf
383 | # with the information sabout how to send traffic to your containers
384 | - 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
385 | - 'elasticloadbalancing:DeregisterTargets'
386 | - 'elasticloadbalancing:Describe*'
387 | - 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
388 | - 'elasticloadbalancing:RegisterTargets'
389 | Resource: '*'
390 |
391 | # This is a role which is used by the ECS tasks themselves.
392 | ECSTaskExecutionRole:
393 | Type: AWS::IAM::Role
394 | Properties:
395 | AssumeRolePolicyDocument:
396 | Statement:
397 | - Effect: Allow
398 | Principal:
399 | Service: [ecs-tasks.amazonaws.com]
400 | Action: ['sts:AssumeRole']
401 | Path: /
402 | Policies:
403 | - PolicyName: AmazonECSTaskExecutionRolePolicy
404 | PolicyDocument:
405 | Statement:
406 | - Effect: Allow
407 | Action:
408 | # Allow the ECS Tasks to download images from ECR
409 | - 'ecr:GetAuthorizationToken'
410 | - 'ecr:BatchCheckLayerAvailability'
411 | - 'ecr:GetDownloadUrlForLayer'
412 | - 'ecr:BatchGetImage'
413 |
414 | # Allow the ECS tasks to upload logs to CloudWatch
415 | - 'logs:CreateLogStream'
416 | - 'logs:PutLogEvents'
417 | Resource: '*'
418 |
419 | # These are the values output by the CloudFormation template. Be careful
420 | # about changing any of them, because of them are exported with specific
421 | # names so that the other task related CF templates can use them.
422 | Outputs:
423 | ClusterName:
424 | Description: The name of the ECS cluster
425 | Value: !Ref 'ECSCluster'
426 | Export:
427 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ClusterName' ] ]
428 | InternalUrl:
429 | Description: The url of the internal load balancer
430 | Value: !Join ['', ['http://', !GetAtt 'PrivateLoadBalancer.DNSName']]
431 | Export:
432 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'InternalUrl' ] ]
433 | ExternalUrl:
434 | Description: The url of the external load balancer
435 | Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']]
436 | Export:
437 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ExternalUrl' ] ]
438 | ECSRole:
439 | Description: The ARN of the ECS role
440 | Value: !GetAtt 'ECSRole.Arn'
441 | Export:
442 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSRole' ] ]
443 | ECSTaskExecutionRole:
444 | Description: The ARN of the ECS role
445 | Value: !GetAtt 'ECSTaskExecutionRole.Arn'
446 | Export:
447 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSTaskExecutionRole' ] ]
448 | PublicListener:
449 | Description: The ARN of the public load balancer's Listener
450 | Value: !Ref PublicLoadBalancerListener
451 | Export:
452 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicListener' ] ]
453 | PrivateListener:
454 | Description: The ARN of the public load balancer's Listener
455 | Value: !Ref PrivateLoadBalancerListener
456 | Export:
457 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateListener' ] ]
458 | VPCId:
459 | Description: The ID of the VPC that this stack is deployed in
460 | Value: !Ref 'VPC'
461 | Export:
462 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'VPCId' ] ]
463 | PublicSubnetOne:
464 | Description: Public subnet one
465 | Value: !Ref 'PublicSubnetOne'
466 | Export:
467 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetOne' ] ]
468 | PublicSubnetTwo:
469 | Description: Public subnet two
470 | Value: !Ref 'PublicSubnetTwo'
471 | Export:
472 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetTwo' ] ]
473 | PrivateSubnetOne:
474 | Description: Private subnet one
475 | Value: !Ref 'PrivateSubnetOne'
476 | Export:
477 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetOne' ] ]
478 | PrivateSubnetTwo:
479 | Description: Private subnet two
480 | Value: !Ref 'PrivateSubnetTwo'
481 | Export:
482 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PrivateSubnetTwo' ] ]
483 | FargateContainerSecurityGroup:
484 | Description: A security group used to allow Fargate containers to receive traffic
485 | Value: !Ref 'FargateContainerSecurityGroup'
486 | Export:
487 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'FargateContainerSecurityGroup' ] ]
488 |
--------------------------------------------------------------------------------
/fargate-networking-stacks/public-vpc.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: A stack for deploying containerized applications in AWS Fargate.
3 | This stack runs containers in a public VPC subnet, and includes a
4 | public facing load balancer to register the services in.
5 | Mappings:
6 | # Hard values for the subnet masks. These masks define
7 | # the range of internal IP addresses that can be assigned.
8 | # The VPC can have all IP's from 10.0.0.0 to 10.0.255.255
9 | # There are two subnets which cover the ranges:
10 | #
11 | # 10.0.0.0 - 10.0.0.255
12 | # 10.0.1.0 - 10.0.1.255
13 | #
14 | # If you need more IP addresses (perhaps you have so many
15 | # instances that you run out) then you can customize these
16 | # ranges to add more
17 | SubnetConfig:
18 | VPC:
19 | CIDR: '10.0.0.0/16'
20 | PublicOne:
21 | CIDR: '10.0.0.0/24'
22 | PublicTwo:
23 | CIDR: '10.0.1.0/24'
24 | Resources:
25 | # VPC in which containers will be networked.
26 | # It has two public subnets
27 | # We distribute the subnets across the first two available subnets
28 | # for the region, for high availability.
29 | VPC:
30 | Type: AWS::EC2::VPC
31 | Properties:
32 | EnableDnsSupport: true
33 | EnableDnsHostnames: true
34 | CidrBlock: !FindInMap ['SubnetConfig', 'VPC', 'CIDR']
35 |
36 | # Two public subnets, where containers can have public IP addresses
37 | PublicSubnetOne:
38 | Type: AWS::EC2::Subnet
39 | Properties:
40 | AvailabilityZone:
41 | Fn::Select:
42 | - 0
43 | - Fn::GetAZs: {Ref: 'AWS::Region'}
44 | VpcId: !Ref 'VPC'
45 | CidrBlock: !FindInMap ['SubnetConfig', 'PublicOne', 'CIDR']
46 | MapPublicIpOnLaunch: true
47 | PublicSubnetTwo:
48 | Type: AWS::EC2::Subnet
49 | Properties:
50 | AvailabilityZone:
51 | Fn::Select:
52 | - 1
53 | - Fn::GetAZs: {Ref: 'AWS::Region'}
54 | VpcId: !Ref 'VPC'
55 | CidrBlock: !FindInMap ['SubnetConfig', 'PublicTwo', 'CIDR']
56 | MapPublicIpOnLaunch: true
57 |
58 | # Setup networking resources for the public subnets. Containers
59 | # in the public subnets have public IP addresses and the routing table
60 | # sends network traffic via the internet gateway.
61 | InternetGateway:
62 | Type: AWS::EC2::InternetGateway
63 | GatewayAttachement:
64 | Type: AWS::EC2::VPCGatewayAttachment
65 | Properties:
66 | VpcId: !Ref 'VPC'
67 | InternetGatewayId: !Ref 'InternetGateway'
68 | PublicRouteTable:
69 | Type: AWS::EC2::RouteTable
70 | Properties:
71 | VpcId: !Ref 'VPC'
72 | PublicRoute:
73 | Type: AWS::EC2::Route
74 | DependsOn: GatewayAttachement
75 | Properties:
76 | RouteTableId: !Ref 'PublicRouteTable'
77 | DestinationCidrBlock: '0.0.0.0/0'
78 | GatewayId: !Ref 'InternetGateway'
79 | PublicSubnetOneRouteTableAssociation:
80 | Type: AWS::EC2::SubnetRouteTableAssociation
81 | Properties:
82 | SubnetId: !Ref PublicSubnetOne
83 | RouteTableId: !Ref PublicRouteTable
84 | PublicSubnetTwoRouteTableAssociation:
85 | Type: AWS::EC2::SubnetRouteTableAssociation
86 | Properties:
87 | SubnetId: !Ref PublicSubnetTwo
88 | RouteTableId: !Ref PublicRouteTable
89 |
90 | # ECS Resources
91 | ECSCluster:
92 | Type: AWS::ECS::Cluster
93 |
94 | # A security group for the containers we will run in Fargate.
95 | # Two rules, allowing network traffic from a public facing load
96 | # balancer and from other members of the security group.
97 | #
98 | # Remove any of the following ingress rules that are not needed.
99 | # If you want to make direct requests to a container using its
100 | # public IP address you'll need to add a security group rule
101 | # to allow traffic from all IP addresses.
102 | FargateContainerSecurityGroup:
103 | Type: AWS::EC2::SecurityGroup
104 | Properties:
105 | GroupDescription: Access to the Fargate containers
106 | VpcId: !Ref 'VPC'
107 | EcsSecurityGroupIngressFromPublicALB:
108 | Type: AWS::EC2::SecurityGroupIngress
109 | Properties:
110 | Description: Ingress from the public ALB
111 | GroupId: !Ref 'FargateContainerSecurityGroup'
112 | IpProtocol: -1
113 | SourceSecurityGroupId: !Ref 'PublicLoadBalancerSG'
114 | EcsSecurityGroupIngressFromSelf:
115 | Type: AWS::EC2::SecurityGroupIngress
116 | Properties:
117 | Description: Ingress from other containers in the same security group
118 | GroupId: !Ref 'FargateContainerSecurityGroup'
119 | IpProtocol: -1
120 | SourceSecurityGroupId: !Ref 'FargateContainerSecurityGroup'
121 |
122 | # Load balancers for getting traffic to containers.
123 | # This sample template creates one load balancer:
124 | #
125 | # - One public load balancer, hosted in public subnets that is accessible
126 | # to the public, and is intended to route traffic to one or more public
127 | # facing services.
128 |
129 | # A public facing load balancer, this is used for accepting traffic from the public
130 | # internet and directing it to public facing microservices
131 | PublicLoadBalancerSG:
132 | Type: AWS::EC2::SecurityGroup
133 | Properties:
134 | GroupDescription: Access to the public facing load balancer
135 | VpcId: !Ref 'VPC'
136 | SecurityGroupIngress:
137 | # Allow access to ALB from anywhere on the internet
138 | - CidrIp: 0.0.0.0/0
139 | IpProtocol: -1
140 | PublicLoadBalancer:
141 | Type: AWS::ElasticLoadBalancingV2::LoadBalancer
142 | Properties:
143 | Scheme: internet-facing
144 | LoadBalancerAttributes:
145 | - Key: idle_timeout.timeout_seconds
146 | Value: '30'
147 | Subnets:
148 | # The load balancer is placed into the public subnets, so that traffic
149 | # from the internet can reach the load balancer directly via the internet gateway
150 | - !Ref PublicSubnetOne
151 | - !Ref PublicSubnetTwo
152 | SecurityGroups: [!Ref 'PublicLoadBalancerSG']
153 | # A dummy target group is used to setup the ALB to just drop traffic
154 | # initially, before any real service target groups have been added.
155 | DummyTargetGroupPublic:
156 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
157 | Properties:
158 | HealthCheckIntervalSeconds: 6
159 | HealthCheckPath: /
160 | HealthCheckProtocol: HTTP
161 | HealthCheckTimeoutSeconds: 5
162 | HealthyThresholdCount: 2
163 | Name: !Join ['-', [!Ref 'AWS::StackName', 'drop-1']]
164 | Port: 80
165 | Protocol: HTTP
166 | UnhealthyThresholdCount: 2
167 | VpcId: !Ref 'VPC'
168 | PublicLoadBalancerListener:
169 | Type: AWS::ElasticLoadBalancingV2::Listener
170 | DependsOn:
171 | - PublicLoadBalancer
172 | Properties:
173 | DefaultActions:
174 | - TargetGroupArn: !Ref 'DummyTargetGroupPublic'
175 | Type: 'forward'
176 | LoadBalancerArn: !Ref 'PublicLoadBalancer'
177 | Port: 80
178 | Protocol: HTTP
179 |
180 | # This is an IAM role which authorizes ECS to manage resources on your
181 | # account on your behalf, such as updating your load balancer with the
182 | # details of where your containers are, so that traffic can reach your
183 | # containers.
184 | ECSRole:
185 | Type: AWS::IAM::Role
186 | Properties:
187 | AssumeRolePolicyDocument:
188 | Statement:
189 | - Effect: Allow
190 | Principal:
191 | Service: [ecs.amazonaws.com]
192 | Action: ['sts:AssumeRole']
193 | Path: /
194 | Policies:
195 | - PolicyName: ecs-service
196 | PolicyDocument:
197 | Statement:
198 | - Effect: Allow
199 | Action:
200 | # Rules which allow ECS to attach network interfaces to instances
201 | # on your behalf in order for awsvpc networking mode to work right
202 | - 'ec2:AttachNetworkInterface'
203 | - 'ec2:CreateNetworkInterface'
204 | - 'ec2:CreateNetworkInterfacePermission'
205 | - 'ec2:DeleteNetworkInterface'
206 | - 'ec2:DeleteNetworkInterfacePermission'
207 | - 'ec2:Describe*'
208 | - 'ec2:DetachNetworkInterface'
209 |
210 | # Rules which allow ECS to update load balancers on your behalf
211 | # with the information sabout how to send traffic to your containers
212 | - 'elasticloadbalancing:DeregisterInstancesFromLoadBalancer'
213 | - 'elasticloadbalancing:DeregisterTargets'
214 | - 'elasticloadbalancing:Describe*'
215 | - 'elasticloadbalancing:RegisterInstancesWithLoadBalancer'
216 | - 'elasticloadbalancing:RegisterTargets'
217 | Resource: '*'
218 |
219 | # This is a role which is used by the ECS tasks themselves.
220 | ECSTaskExecutionRole:
221 | Type: AWS::IAM::Role
222 | Properties:
223 | AssumeRolePolicyDocument:
224 | Statement:
225 | - Effect: Allow
226 | Principal:
227 | Service: [ecs-tasks.amazonaws.com]
228 | Action: ['sts:AssumeRole']
229 | Path: /
230 | Policies:
231 | - PolicyName: AmazonECSTaskExecutionRolePolicy
232 | PolicyDocument:
233 | Statement:
234 | - Effect: Allow
235 | Action:
236 | # Allow the ECS Tasks to download images from ECR
237 | - 'ecr:GetAuthorizationToken'
238 | - 'ecr:BatchCheckLayerAvailability'
239 | - 'ecr:GetDownloadUrlForLayer'
240 | - 'ecr:BatchGetImage'
241 |
242 | # Allow the ECS tasks to upload logs to CloudWatch
243 | - 'logs:CreateLogStream'
244 | - 'logs:PutLogEvents'
245 | Resource: '*'
246 |
247 | # These are the values output by the CloudFormation template. Be careful
248 | # about changing any of them, because of them are exported with specific
249 | # names so that the other task related CF templates can use them.
250 | Outputs:
251 | ClusterName:
252 | Description: The name of the ECS cluster
253 | Value: !Ref 'ECSCluster'
254 | Export:
255 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ClusterName' ] ]
256 | ExternalUrl:
257 | Description: The url of the external load balancer
258 | Value: !Join ['', ['http://', !GetAtt 'PublicLoadBalancer.DNSName']]
259 | Export:
260 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ExternalUrl' ] ]
261 | ECSRole:
262 | Description: The ARN of the ECS role
263 | Value: !GetAtt 'ECSRole.Arn'
264 | Export:
265 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSRole' ] ]
266 | ECSTaskExecutionRole:
267 | Description: The ARN of the ECS role
268 | Value: !GetAtt 'ECSTaskExecutionRole.Arn'
269 | Export:
270 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'ECSTaskExecutionRole' ] ]
271 | PublicListener:
272 | Description: The ARN of the public load balancer's Listener
273 | Value: !Ref PublicLoadBalancerListener
274 | Export:
275 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicListener' ] ]
276 | VPCId:
277 | Description: The ID of the VPC that this stack is deployed in
278 | Value: !Ref 'VPC'
279 | Export:
280 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'VPCId' ] ]
281 | PublicSubnetOne:
282 | Description: Public subnet one
283 | Value: !Ref 'PublicSubnetOne'
284 | Export:
285 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetOne' ] ]
286 | PublicSubnetTwo:
287 | Description: Public subnet two
288 | Value: !Ref 'PublicSubnetTwo'
289 | Export:
290 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnetTwo' ] ]
291 | FargateContainerSecurityGroup:
292 | Description: A security group used to allow Fargate containers to receive traffic
293 | Value: !Ref 'FargateContainerSecurityGroup'
294 | Export:
295 | Name: !Join [ ':', [ !Ref 'AWS::StackName', 'FargateContainerSecurityGroup' ] ]
296 |
--------------------------------------------------------------------------------
/images/local-networking.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nathanpeck/aws-cloudformation-fargate/30238130d6105769283a69be6b2c40cb921b5bc5/images/local-networking.png
--------------------------------------------------------------------------------
/images/private-task-public-loadbalancer.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/images/private-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/images/public-task-public-loadbalancer.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/images/public-task.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/service-stacks/private-subnet-private-loadbalancer.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: Deploy a service on AWS Fargate, hosted in a private subnet, behind a private load balancer.
3 | Parameters:
4 | StackName:
5 | Type: String
6 | Default: production
7 | Description: The name of the parent Fargate networking stack that you created. Necessary
8 | to locate and reference resources created by that stack.
9 | ServiceName:
10 | Type: String
11 | Default: nginx
12 | Description: A name for the service
13 | ImageUrl:
14 | Type: String
15 | Default: nginx
16 | Description: The url of a docker image that contains the application process that
17 | will handle the traffic for this service
18 | ContainerPort:
19 | Type: Number
20 | Default: 80
21 | Description: What port number the application inside the docker container is binding to
22 | ContainerCpu:
23 | Type: Number
24 | Default: 256
25 | Description: How much CPU to give the container. 1024 is 1 CPU
26 | ContainerMemory:
27 | Type: Number
28 | Default: 512
29 | Description: How much memory in megabytes to give the container
30 | Path:
31 | Type: String
32 | Default: "*"
33 | Description: A path on the public load balancer that this service
34 | should be connected to. Use * to send all load balancer
35 | traffic to this service.
36 | Priority:
37 | Type: Number
38 | Default: 1
39 | Description: The priority for the routing rule added to the load balancer.
40 | This only applies if your have multiple services which have been
41 | assigned to different paths on the load balancer.
42 | DesiredCount:
43 | Type: Number
44 | Default: 2
45 | Description: How many copies of the service task to run
46 | Role:
47 | Type: String
48 | Default: ""
49 | Description: (Optional) An IAM role to give the service's containers if the code within needs to
50 | access other AWS resources like S3 buckets, DynamoDB tables, etc
51 |
52 | Conditions:
53 | HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
54 |
55 | Resources:
56 |
57 | # The task definition. This is a simple metadata description of what
58 | # container to run, and what resource requirements it has.
59 | TaskDefinition:
60 | Type: AWS::ECS::TaskDefinition
61 | Properties:
62 | Family: !Ref 'ServiceName'
63 | Cpu: !Ref 'ContainerCpu'
64 | Memory: !Ref 'ContainerMemory'
65 | NetworkMode: awsvpc
66 | RequiresCompatibilities:
67 | - FARGATE
68 | ExecutionRoleArn:
69 | Fn::ImportValue:
70 | !Join [':', [!Ref 'StackName', 'ECSTaskExecutionRole']]
71 | TaskRoleArn:
72 | Fn::If:
73 | - 'HasCustomRole'
74 | - !Ref 'Role'
75 | - !Ref "AWS::NoValue"
76 | ContainerDefinitions:
77 | - Name: !Ref 'ServiceName'
78 | Cpu: !Ref 'ContainerCpu'
79 | Memory: !Ref 'ContainerMemory'
80 | Image: !Ref 'ImageUrl'
81 | PortMappings:
82 | - ContainerPort: !Ref 'ContainerPort'
83 |
84 | # The service. The service is a resource which allows you to run multiple
85 | # copies of a type of task, and gather up their logs and metrics, as well
86 | # as monitor the number of running tasks and replace any that have crashed
87 | Service:
88 | Type: AWS::ECS::Service
89 | DependsOn: LoadBalancerRule
90 | Properties:
91 | ServiceName: !Ref 'ServiceName'
92 | Cluster:
93 | Fn::ImportValue:
94 | !Join [':', [!Ref 'StackName', 'ClusterName']]
95 | LaunchType: FARGATE
96 | DeploymentConfiguration:
97 | MaximumPercent: 200
98 | MinimumHealthyPercent: 75
99 | DesiredCount: !Ref 'DesiredCount'
100 | NetworkConfiguration:
101 | AwsvpcConfiguration:
102 | AssignPublicIp: ENABLED
103 | SecurityGroups:
104 | - Fn::ImportValue:
105 | !Join [':', [!Ref 'StackName', 'FargateContainerSecurityGroup']]
106 | Subnets:
107 | - Fn::ImportValue:
108 | !Join [':', [!Ref 'StackName', 'PrivateSubnetOne']]
109 | - Fn::ImportValue:
110 | !Join [':', [!Ref 'StackName', 'PrivateSubnetTwo']]
111 | TaskDefinition: !Ref 'TaskDefinition'
112 | LoadBalancers:
113 | - ContainerName: !Ref 'ServiceName'
114 | ContainerPort: !Ref 'ContainerPort'
115 | TargetGroupArn: !Ref 'TargetGroup'
116 |
117 | # A target group. This is used for keeping track of all the tasks, and
118 | # what IP addresses / port numbers they have. You can query it yourself,
119 | # to use the addresses yourself, but most often this target group is just
120 | # connected to an application load balancer, or network load balancer, so
121 | # it can automatically distribute traffic across all the targets.
122 | TargetGroup:
123 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
124 | Properties:
125 | HealthCheckIntervalSeconds: 6
126 | HealthCheckPath: /
127 | HealthCheckProtocol: HTTP
128 | HealthCheckTimeoutSeconds: 5
129 | HealthyThresholdCount: 2
130 | TargetType: ip
131 | Name: !Ref 'ServiceName'
132 | Port: !Ref 'ContainerPort'
133 | Protocol: HTTP
134 | UnhealthyThresholdCount: 2
135 | VpcId:
136 | Fn::ImportValue:
137 | !Join [':', [!Ref 'StackName', 'VPCId']]
138 |
139 | # Create a rule on the load balancer for routing traffic to the target group
140 | LoadBalancerRule:
141 | Type: AWS::ElasticLoadBalancingV2::ListenerRule
142 | Properties:
143 | Actions:
144 | - TargetGroupArn: !Ref 'TargetGroup'
145 | Type: 'forward'
146 | Conditions:
147 | - Field: path-pattern
148 | Values: [!Ref 'Path']
149 | ListenerArn:
150 | Fn::ImportValue:
151 | !Join [':', [!Ref 'StackName', 'PrivateListener']]
152 | Priority: !Ref 'Priority'
153 |
--------------------------------------------------------------------------------
/service-stacks/private-subnet-public-loadbalancer.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: Deploy a service on AWS Fargate, hosted in a private subnet, but accessible via a public load balancer.
3 | Parameters:
4 | StackName:
5 | Type: String
6 | Default: production
7 | Description: The name of the parent Fargate networking stack that you created. Necessary
8 | to locate and reference resources created by that stack.
9 | ServiceName:
10 | Type: String
11 | Default: nginx
12 | Description: A name for the service
13 | ImageUrl:
14 | Type: String
15 | Default: nginx
16 | Description: The url of a docker image that contains the application process that
17 | will handle the traffic for this service
18 | ContainerPort:
19 | Type: Number
20 | Default: 80
21 | Description: What port number the application inside the docker container is binding to
22 | ContainerCpu:
23 | Type: Number
24 | Default: 256
25 | Description: How much CPU to give the container. 1024 is 1 CPU
26 | ContainerMemory:
27 | Type: Number
28 | Default: 512
29 | Description: How much memory in megabytes to give the container
30 | Path:
31 | Type: String
32 | Default: "*"
33 | Description: A path on the public load balancer that this service
34 | should be connected to. Use * to send all load balancer
35 | traffic to this service.
36 | Priority:
37 | Type: Number
38 | Default: 1
39 | Description: The priority for the routing rule added to the load balancer.
40 | This only applies if your have multiple services which have been
41 | assigned to different paths on the load balancer.
42 | DesiredCount:
43 | Type: Number
44 | Default: 2
45 | Description: How many copies of the service task to run
46 | Role:
47 | Type: String
48 | Default: ""
49 | Description: (Optional) An IAM role to give the service's containers if the code within needs to
50 | access other AWS resources like S3 buckets, DynamoDB tables, etc
51 |
52 | Conditions:
53 | HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
54 |
55 | Resources:
56 |
57 | # The task definition. This is a simple metadata description of what
58 | # container to run, and what resource requirements it has.
59 | TaskDefinition:
60 | Type: AWS::ECS::TaskDefinition
61 | Properties:
62 | Family: !Ref 'ServiceName'
63 | Cpu: !Ref 'ContainerCpu'
64 | Memory: !Ref 'ContainerMemory'
65 | NetworkMode: awsvpc
66 | RequiresCompatibilities:
67 | - FARGATE
68 | ExecutionRoleArn:
69 | Fn::ImportValue:
70 | !Join [':', [!Ref 'StackName', 'ECSTaskExecutionRole']]
71 | TaskRoleArn:
72 | Fn::If:
73 | - 'HasCustomRole'
74 | - !Ref 'Role'
75 | - !Ref "AWS::NoValue"
76 | ContainerDefinitions:
77 | - Name: !Ref 'ServiceName'
78 | Cpu: !Ref 'ContainerCpu'
79 | Memory: !Ref 'ContainerMemory'
80 | Image: !Ref 'ImageUrl'
81 | PortMappings:
82 | - ContainerPort: !Ref 'ContainerPort'
83 |
84 | # The service. The service is a resource which allows you to run multiple
85 | # copies of a type of task, and gather up their logs and metrics, as well
86 | # as monitor the number of running tasks and replace any that have crashed
87 | Service:
88 | Type: AWS::ECS::Service
89 | DependsOn: LoadBalancerRule
90 | Properties:
91 | ServiceName: !Ref 'ServiceName'
92 | Cluster:
93 | Fn::ImportValue:
94 | !Join [':', [!Ref 'StackName', 'ClusterName']]
95 | LaunchType: FARGATE
96 | DeploymentConfiguration:
97 | MaximumPercent: 200
98 | MinimumHealthyPercent: 75
99 | DesiredCount: !Ref 'DesiredCount'
100 | NetworkConfiguration:
101 | AwsvpcConfiguration:
102 | SecurityGroups:
103 | - Fn::ImportValue:
104 | !Join [':', [!Ref 'StackName', 'FargateContainerSecurityGroup']]
105 | Subnets:
106 | - Fn::ImportValue:
107 | !Join [':', [!Ref 'StackName', 'PrivateSubnetOne']]
108 | - Fn::ImportValue:
109 | !Join [':', [!Ref 'StackName', 'PrivateSubnetTwo']]
110 | TaskDefinition: !Ref 'TaskDefinition'
111 | LoadBalancers:
112 | - ContainerName: !Ref 'ServiceName'
113 | ContainerPort: !Ref 'ContainerPort'
114 | TargetGroupArn: !Ref 'TargetGroup'
115 |
116 | # A target group. This is used for keeping track of all the tasks, and
117 | # what IP addresses / port numbers they have. You can query it yourself,
118 | # to use the addresses yourself, but most often this target group is just
119 | # connected to an application load balancer, or network load balancer, so
120 | # it can automatically distribute traffic across all the targets.
121 | TargetGroup:
122 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
123 | Properties:
124 | HealthCheckIntervalSeconds: 6
125 | HealthCheckPath: /
126 | HealthCheckProtocol: HTTP
127 | HealthCheckTimeoutSeconds: 5
128 | HealthyThresholdCount: 2
129 | TargetType: ip
130 | Name: !Ref 'ServiceName'
131 | Port: !Ref 'ContainerPort'
132 | Protocol: HTTP
133 | UnhealthyThresholdCount: 2
134 | VpcId:
135 | Fn::ImportValue:
136 | !Join [':', [!Ref 'StackName', 'VPCId']]
137 |
138 | # Create a rule on the load balancer for routing traffic to the target group
139 | LoadBalancerRule:
140 | Type: AWS::ElasticLoadBalancingV2::ListenerRule
141 | Properties:
142 | Actions:
143 | - TargetGroupArn: !Ref 'TargetGroup'
144 | Type: 'forward'
145 | Conditions:
146 | - Field: path-pattern
147 | Values: [!Ref 'Path']
148 | ListenerArn:
149 | Fn::ImportValue:
150 | !Join [':', [!Ref 'StackName', 'PublicListener']]
151 | Priority: !Ref 'Priority'
152 |
--------------------------------------------------------------------------------
/service-stacks/public-subnet-public-loadbalancer.yml:
--------------------------------------------------------------------------------
1 | AWSTemplateFormatVersion: '2010-09-09'
2 | Description: Deploy a service on AWS Fargate, hosted in a public subnet, and accessible via a public load balancer.
3 | Parameters:
4 | StackName:
5 | Type: String
6 | Default: production
7 | Description: The name of the parent Fargate networking stack that you created. Necessary
8 | to locate and reference resources created by that stack.
9 | ServiceName:
10 | Type: String
11 | Default: nginx
12 | Description: A name for the service
13 | ImageUrl:
14 | Type: String
15 | Default: nginx
16 | Description: The url of a docker image that contains the application process that
17 | will handle the traffic for this service
18 | ContainerPort:
19 | Type: Number
20 | Default: 80
21 | Description: What port number the application inside the docker container is binding to
22 | ContainerCpu:
23 | Type: Number
24 | Default: 256
25 | Description: How much CPU to give the container. 1024 is 1 CPU
26 | ContainerMemory:
27 | Type: Number
28 | Default: 512
29 | Description: How much memory in megabytes to give the container
30 | Path:
31 | Type: String
32 | Default: "*"
33 | Description: A path on the public load balancer that this service
34 | should be connected to. Use * to send all load balancer
35 | traffic to this service.
36 | Priority:
37 | Type: Number
38 | Default: 1
39 | Description: The priority for the routing rule added to the load balancer.
40 | This only applies if your have multiple services which have been
41 | assigned to different paths on the load balancer.
42 | DesiredCount:
43 | Type: Number
44 | Default: 2
45 | Description: How many copies of the service task to run
46 | Role:
47 | Type: String
48 | Default: ""
49 | Description: (Optional) An IAM role to give the service's containers if the code within needs to
50 | access other AWS resources like S3 buckets, DynamoDB tables, etc
51 |
52 | Conditions:
53 | HasCustomRole: !Not [ !Equals [!Ref 'Role', ''] ]
54 |
55 | Resources:
56 |
57 | # The task definition. This is a simple metadata description of what
58 | # container to run, and what resource requirements it has.
59 | TaskDefinition:
60 | Type: AWS::ECS::TaskDefinition
61 | Properties:
62 | Family: !Ref 'ServiceName'
63 | Cpu: !Ref 'ContainerCpu'
64 | Memory: !Ref 'ContainerMemory'
65 | NetworkMode: awsvpc
66 | RequiresCompatibilities:
67 | - FARGATE
68 | ExecutionRoleArn:
69 | Fn::ImportValue:
70 | !Join [':', [!Ref 'StackName', 'ECSTaskExecutionRole']]
71 | TaskRoleArn:
72 | Fn::If:
73 | - 'HasCustomRole'
74 | - !Ref 'Role'
75 | - !Ref "AWS::NoValue"
76 | ContainerDefinitions:
77 | - Name: !Ref 'ServiceName'
78 | Cpu: !Ref 'ContainerCpu'
79 | Memory: !Ref 'ContainerMemory'
80 | Image: !Ref 'ImageUrl'
81 | PortMappings:
82 | - ContainerPort: !Ref 'ContainerPort'
83 |
84 | # The service. The service is a resource which allows you to run multiple
85 | # copies of a type of task, and gather up their logs and metrics, as well
86 | # as monitor the number of running tasks and replace any that have crashed
87 | Service:
88 | Type: AWS::ECS::Service
89 | DependsOn: LoadBalancerRule
90 | Properties:
91 | ServiceName: !Ref 'ServiceName'
92 | Cluster:
93 | Fn::ImportValue:
94 | !Join [':', [!Ref 'StackName', 'ClusterName']]
95 | LaunchType: FARGATE
96 | DeploymentConfiguration:
97 | MaximumPercent: 200
98 | MinimumHealthyPercent: 75
99 | DesiredCount: !Ref 'DesiredCount'
100 | NetworkConfiguration:
101 | AwsvpcConfiguration:
102 | AssignPublicIp: ENABLED
103 | SecurityGroups:
104 | - Fn::ImportValue:
105 | !Join [':', [!Ref 'StackName', 'FargateContainerSecurityGroup']]
106 | Subnets:
107 | - Fn::ImportValue:
108 | !Join [':', [!Ref 'StackName', 'PublicSubnetOne']]
109 | - Fn::ImportValue:
110 | !Join [':', [!Ref 'StackName', 'PublicSubnetTwo']]
111 | TaskDefinition: !Ref 'TaskDefinition'
112 | LoadBalancers:
113 | - ContainerName: !Ref 'ServiceName'
114 | ContainerPort: !Ref 'ContainerPort'
115 | TargetGroupArn: !Ref 'TargetGroup'
116 |
117 | # A target group. This is used for keeping track of all the tasks, and
118 | # what IP addresses / port numbers they have. You can query it yourself,
119 | # to use the addresses yourself, but most often this target group is just
120 | # connected to an application load balancer, or network load balancer, so
121 | # it can automatically distribute traffic across all the targets.
122 | TargetGroup:
123 | Type: AWS::ElasticLoadBalancingV2::TargetGroup
124 | Properties:
125 | HealthCheckIntervalSeconds: 6
126 | HealthCheckPath: /
127 | HealthCheckProtocol: HTTP
128 | HealthCheckTimeoutSeconds: 5
129 | HealthyThresholdCount: 2
130 | TargetType: ip
131 | Name: !Ref 'ServiceName'
132 | Port: !Ref 'ContainerPort'
133 | Protocol: HTTP
134 | UnhealthyThresholdCount: 2
135 | VpcId:
136 | Fn::ImportValue:
137 | !Join [':', [!Ref 'StackName', 'VPCId']]
138 |
139 | # Create a rule on the load balancer for routing traffic to the target group
140 | LoadBalancerRule:
141 | Type: AWS::ElasticLoadBalancingV2::ListenerRule
142 | Properties:
143 | Actions:
144 | - TargetGroupArn: !Ref 'TargetGroup'
145 | Type: 'forward'
146 | Conditions:
147 | - Field: path-pattern
148 | Values: [!Ref 'Path']
149 | ListenerArn:
150 | Fn::ImportValue:
151 | !Join [':', [!Ref 'StackName', 'PublicListener']]
152 | Priority: !Ref 'Priority'
153 |
--------------------------------------------------------------------------------