Skip to content

Commit 4833109

Browse files
jfan9Jacky FanBruce McLeodfanq10kaiz-io
authored
Feat(python/fargate): Added a Python example for Fargate Service with EFS (#1045)
* added initial resources * Create cdk.json * Create requirements.txt * added access point and task definition * added volume and mount point to container def * added faraget service and scalable target * fix ecs sample container_path * updated task role iam policy * added env variable in ecs task role condition * added prefix, app path and volume variables * Added ReadMe, updated aws-cdk-lib, cleaned up and commented app,py * Updated Readme * Updated service name to aws-fargate-service-with-efs * rename stack to aws-fargate-service-with-efs * revert stack name to aws-fargate-application-autoscaling --------- Co-authored-by: Jacky Fan <[email protected]> Co-authored-by: Bruce McLeod <[email protected]> Co-authored-by: Jacky Fan <[email protected]> Co-authored-by: Michael Kaiser <[email protected]>
1 parent 4d19f89 commit 4833109

File tree

4 files changed

+303
-0
lines changed

4 files changed

+303
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Fargate Service using EFS
2+
This is a CDK sample that creates a public facing load balanced Fargate service with an EFS Filesystem mount. The intention of this sample is to demonstrate how shared storage can be deployed and utilised that is seperate from your compute, which, in this case is AWS Fargate.
3+
4+
This sample is Is based on this blog post: https://aws.amazon.com/blogs/aws/amazon-ecs-supports-efs/
5+
6+
## Sample overview
7+
8+
The `cdk.json` file tells the CDK Toolkit how to execute your app.
9+
10+
This project is set up like a standard Python project. The initialization process also creates a virtualenv within this project, stored under the `.env` directory. To create the virtualenv it assumes that there is a `python3` (or `python` for Windows) executable in your path with access to the `venv` package. If for any reason the automatic creation of the virtualenv fails, you can create the virtualenv manually.
11+
12+
To manually create a virtualenv on MacOS and Linux:
13+
14+
```
15+
$ python3 -m venv .env
16+
```
17+
18+
After the init process completes and the virtualenv is created, you can use the following
19+
step to activate your virtualenv.
20+
21+
```
22+
$ source .env/bin/activate
23+
```
24+
25+
If you are a Windows platform, you would activate the virtualenv like this:
26+
27+
```
28+
% .env\Scripts\activate.bat
29+
```
30+
31+
Once the virtualenv is activated, you can install the required dependencies.
32+
33+
```
34+
$ pip install -r requirements.txt
35+
```
36+
37+
If you have not deployed with CDK into your account before, you will need to bootsrap the account and environment with
38+
39+
```
40+
$ cdk bootstrap
41+
```
42+
43+
At this point you can now deploy the CloudFormation template for this code.
44+
45+
```
46+
$ cdk deploy
47+
```
48+
49+
## Testing the app
50+
Upon successful deployment, you should see a new Amazon Elastic Container Service cluster deployed with the name "AWS-CDK-Fargate-efssampleCluster<Unique ID>". Similarly you should see an Amazon EFS Volume deployed with the name "AWS-CDK-Fargate-/efs-sample-EFS(<Unique ID>)", and an Application Load Balancer "AWS-CD-efssa--<Unique ID>"
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#!/usr/bin/env python3
2+
from aws_cdk import (
3+
aws_ec2 as ec2,
4+
aws_ecs as ecs,
5+
aws_efs as efs,
6+
aws_iam as iam,
7+
aws_logs as logs,
8+
aws_ecs_patterns as ecs_patterns,
9+
App, Stack
10+
)
11+
from constructs import Construct
12+
import os
13+
14+
class FargateServiceWithEfs(Stack):
15+
16+
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
17+
super().__init__(scope, id, *kwargs)
18+
19+
PREFIX = 'efs-sample-'
20+
APP_PATH = '/var/www/'
21+
VOLUME_NAME = 'cdk-ecs-sample-efs-volume'
22+
23+
vpc = ec2.Vpc(
24+
self, PREFIX + 'Vpc',
25+
max_azs=2
26+
)
27+
28+
ecs_cluster = ecs.Cluster(
29+
self, PREFIX + 'Cluster',
30+
vpc=vpc,
31+
)
32+
33+
# Create an Amazon Elastic File System (EFS), with the logical ID CDK-efs-sample-EFS
34+
file_system = efs.FileSystem(
35+
self, PREFIX + 'EFS',
36+
vpc=vpc,
37+
lifecycle_policy=efs.LifecyclePolicy.AFTER_14_DAYS,
38+
performance_mode=efs.PerformanceMode.GENERAL_PURPOSE,
39+
)
40+
41+
# Create an Access Point for the EFS, with the logical ID CDK-efs-sample-AccessPoint
42+
access_point = efs.AccessPoint(
43+
self, PREFIX + 'AccessPoint',
44+
file_system=file_system,
45+
)
46+
47+
# Create a new EFS volume configuration for the ECS Task
48+
efs_volume_configuration = ecs.EfsVolumeConfiguration(
49+
file_system_id=file_system.file_system_id,
50+
51+
# The logical ID of the Access Point to use.
52+
# This is a string, not an ARN.
53+
authorization_config=ecs.AuthorizationConfig(
54+
access_point_id=access_point.access_point_id,
55+
iam='ENABLED',
56+
),
57+
transit_encryption='ENABLED',
58+
)
59+
60+
# Create a new IAM Role for the ECS Task
61+
task_role = iam.Role (
62+
self, PREFIX + 'EcsTaskRole',
63+
assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com').with_conditions({
64+
"StringEquals": {
65+
"aws:SourceAccount": Stack.of(self).account
66+
},
67+
"ArnLike":{
68+
"aws:SourceArn":"arn:aws:ecs:" + Stack.of(self).region + ":" + Stack.of(self).account + ":*"
69+
},
70+
}),
71+
)
72+
73+
# Attach a managed policy to the IAM Role
74+
task_role.attach_inline_policy(
75+
iam.Policy(self, PREFIX +'Policy',
76+
statements=[
77+
iam.PolicyStatement(
78+
effect=iam.Effect.ALLOW,
79+
resources=['*'],
80+
actions=[
81+
"ecr:GetAuthorizationToken",
82+
"ec2:DescribeAvailabilityZones"
83+
]
84+
),
85+
iam.PolicyStatement(
86+
sid='AllowEfsAccess',
87+
effect=iam.Effect.ALLOW,
88+
resources=['*'],
89+
actions=[
90+
'elasticfilesystem:ClientRootAccess',
91+
'elasticfilesystem:ClientWrite',
92+
'elasticfilesystem:ClientMount',
93+
'elasticfilesystem:DescribeMountTargets'
94+
]
95+
)
96+
]
97+
)
98+
)
99+
100+
# Create a new Fargate Task Definition
101+
task_definition = ecs.FargateTaskDefinition(
102+
self, PREFIX + 'FargateTaskDef',
103+
task_role=task_role,
104+
)
105+
106+
# Add a new volume to the Fargate Task Definition
107+
task_definition.add_volume(
108+
name=VOLUME_NAME,
109+
efs_volume_configuration=efs_volume_configuration,
110+
)
111+
112+
# Add a new container to the Fargate Task Definition
113+
mount_point = ecs.MountPoint(
114+
container_path=APP_PATH+VOLUME_NAME,
115+
source_volume=VOLUME_NAME,
116+
read_only=False,
117+
)
118+
119+
# Add a new port mapping to the Fargate Task Definition
120+
port_mapping = ecs.PortMapping(
121+
container_port=80,
122+
host_port=80,
123+
protocol=ecs.Protocol.TCP,
124+
)
125+
126+
# Add a new container to the Fargate Task Definition
127+
container = ecs.ContainerDefinition(
128+
self, 'ecs-cdk-sample-container',
129+
task_definition=task_definition,
130+
image=ecs.ContainerImage.from_registry('amazon/amazon-ecs-sample'),
131+
logging=ecs.LogDrivers.aws_logs(
132+
stream_prefix='cdk-ecs-sample',
133+
log_retention=logs.RetentionDays.ONE_MONTH,
134+
)
135+
)
136+
137+
# Add a new volume to the Fargate Task Definition
138+
container.add_mount_points(mount_point),
139+
140+
# Add a new port mapping to the Fargate Task Definition
141+
container.add_port_mappings(port_mapping),
142+
143+
# Create a new Fargate Service with ALB
144+
fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService(
145+
self, PREFIX + 'Service',
146+
cluster=ecs_cluster,
147+
desired_count=1,
148+
task_definition=task_definition,
149+
task_subnets=ec2.SubnetSelection(
150+
subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS,
151+
),
152+
platform_version=ecs.FargatePlatformVersion.LATEST,
153+
public_load_balancer=True,
154+
enable_execute_command=True,
155+
enable_ecs_managed_tags=True,
156+
157+
)
158+
159+
# Allow the ECS Service to connect to the EFS
160+
fargate_service.service.connections.allow_from(file_system, ec2.Port.tcp(2049)),
161+
162+
# Allow the EFS to connect to the ECS Service
163+
fargate_service.service.connections.allow_to(file_system, ec2.Port.tcp(2049)),
164+
165+
# Create a new Auto Scaling Policy for the ECS Service
166+
scalable_target = fargate_service.service.auto_scale_task_count(
167+
min_capacity=1,
168+
max_capacity=20,
169+
)
170+
171+
# Create a new Auto Scaling Policy for the ECS Service
172+
scalable_target.scale_on_cpu_utilization("CpuScaling",
173+
target_utilization_percent=50,
174+
)
175+
176+
# Create a new Auto Scaling Policy for the ECS Service
177+
scalable_target.scale_on_memory_utilization("MemoryScaling",
178+
target_utilization_percent=50,
179+
)
180+
181+
# Create the new CDK Application
182+
cdk_application = App()
183+
FargateServiceWithEfs(cdk_application, "aws-fargate-service-with-efs")
184+
cdk_application.synth()
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"app": "python3 app.py",
3+
"watch": {
4+
"include": [
5+
"**"
6+
],
7+
"exclude": [
8+
"README.md",
9+
"cdk*.json",
10+
"requirements*.txt",
11+
"source.bat",
12+
"**/__init__.py",
13+
"**/__pycache__",
14+
"tests"
15+
]
16+
},
17+
"context": {
18+
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
19+
"@aws-cdk/core:checkSecretUsage": true,
20+
"@aws-cdk/core:target-partitions": [
21+
"aws",
22+
"aws-cn"
23+
],
24+
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
25+
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
26+
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
27+
"@aws-cdk/aws-iam:minimizePolicies": true,
28+
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
29+
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
30+
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
31+
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
32+
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
33+
"@aws-cdk/core:enablePartitionLiterals": true,
34+
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
35+
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
36+
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
37+
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
38+
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
39+
"@aws-cdk/aws-route53-patters:useCertificate": true,
40+
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
41+
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
42+
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
43+
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
44+
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
45+
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
46+
"@aws-cdk/aws-redshift:columnId": true,
47+
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
48+
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
49+
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
50+
"@aws-cdk/aws-kms:aliasNameRef": true,
51+
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
52+
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
53+
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
54+
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
55+
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
56+
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
57+
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
58+
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
59+
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
60+
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
61+
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
62+
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
63+
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
64+
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
65+
"@aws-cdk/aws-eks:nodegroupNameAttribute": true
66+
}
67+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
aws-cdk-lib==2.144.0
2+
constructs>=10.0.0,<11.0.0

0 commit comments

Comments
 (0)