-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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]>
- Loading branch information
1 parent
4d19f89
commit 4833109
Showing
4 changed files
with
303 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# Fargate Service using EFS | ||
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. | ||
|
||
This sample is Is based on this blog post: https://aws.amazon.com/blogs/aws/amazon-ecs-supports-efs/ | ||
|
||
## Sample overview | ||
|
||
The `cdk.json` file tells the CDK Toolkit how to execute your app. | ||
|
||
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. | ||
|
||
To manually create a virtualenv on MacOS and Linux: | ||
|
||
``` | ||
$ python3 -m venv .env | ||
``` | ||
|
||
After the init process completes and the virtualenv is created, you can use the following | ||
step to activate your virtualenv. | ||
|
||
``` | ||
$ source .env/bin/activate | ||
``` | ||
|
||
If you are a Windows platform, you would activate the virtualenv like this: | ||
|
||
``` | ||
% .env\Scripts\activate.bat | ||
``` | ||
|
||
Once the virtualenv is activated, you can install the required dependencies. | ||
|
||
``` | ||
$ pip install -r requirements.txt | ||
``` | ||
|
||
If you have not deployed with CDK into your account before, you will need to bootsrap the account and environment with | ||
|
||
``` | ||
$ cdk bootstrap | ||
``` | ||
|
||
At this point you can now deploy the CloudFormation template for this code. | ||
|
||
``` | ||
$ cdk deploy | ||
``` | ||
|
||
## Testing the app | ||
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>" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
#!/usr/bin/env python3 | ||
from aws_cdk import ( | ||
aws_ec2 as ec2, | ||
aws_ecs as ecs, | ||
aws_efs as efs, | ||
aws_iam as iam, | ||
aws_logs as logs, | ||
aws_ecs_patterns as ecs_patterns, | ||
App, Stack | ||
) | ||
from constructs import Construct | ||
import os | ||
|
||
class FargateServiceWithEfs(Stack): | ||
|
||
def __init__(self, scope: Construct, id: str, **kwargs) -> None: | ||
super().__init__(scope, id, *kwargs) | ||
|
||
PREFIX = 'efs-sample-' | ||
APP_PATH = '/var/www/' | ||
VOLUME_NAME = 'cdk-ecs-sample-efs-volume' | ||
|
||
vpc = ec2.Vpc( | ||
self, PREFIX + 'Vpc', | ||
max_azs=2 | ||
) | ||
|
||
ecs_cluster = ecs.Cluster( | ||
self, PREFIX + 'Cluster', | ||
vpc=vpc, | ||
) | ||
|
||
# Create an Amazon Elastic File System (EFS), with the logical ID CDK-efs-sample-EFS | ||
file_system = efs.FileSystem( | ||
self, PREFIX + 'EFS', | ||
vpc=vpc, | ||
lifecycle_policy=efs.LifecyclePolicy.AFTER_14_DAYS, | ||
performance_mode=efs.PerformanceMode.GENERAL_PURPOSE, | ||
) | ||
|
||
# Create an Access Point for the EFS, with the logical ID CDK-efs-sample-AccessPoint | ||
access_point = efs.AccessPoint( | ||
self, PREFIX + 'AccessPoint', | ||
file_system=file_system, | ||
) | ||
|
||
# Create a new EFS volume configuration for the ECS Task | ||
efs_volume_configuration = ecs.EfsVolumeConfiguration( | ||
file_system_id=file_system.file_system_id, | ||
|
||
# The logical ID of the Access Point to use. | ||
# This is a string, not an ARN. | ||
authorization_config=ecs.AuthorizationConfig( | ||
access_point_id=access_point.access_point_id, | ||
iam='ENABLED', | ||
), | ||
transit_encryption='ENABLED', | ||
) | ||
|
||
# Create a new IAM Role for the ECS Task | ||
task_role = iam.Role ( | ||
self, PREFIX + 'EcsTaskRole', | ||
assumed_by=iam.ServicePrincipal('ecs-tasks.amazonaws.com').with_conditions({ | ||
"StringEquals": { | ||
"aws:SourceAccount": Stack.of(self).account | ||
}, | ||
"ArnLike":{ | ||
"aws:SourceArn":"arn:aws:ecs:" + Stack.of(self).region + ":" + Stack.of(self).account + ":*" | ||
}, | ||
}), | ||
) | ||
|
||
# Attach a managed policy to the IAM Role | ||
task_role.attach_inline_policy( | ||
iam.Policy(self, PREFIX +'Policy', | ||
statements=[ | ||
iam.PolicyStatement( | ||
effect=iam.Effect.ALLOW, | ||
resources=['*'], | ||
actions=[ | ||
"ecr:GetAuthorizationToken", | ||
"ec2:DescribeAvailabilityZones" | ||
] | ||
), | ||
iam.PolicyStatement( | ||
sid='AllowEfsAccess', | ||
effect=iam.Effect.ALLOW, | ||
resources=['*'], | ||
actions=[ | ||
'elasticfilesystem:ClientRootAccess', | ||
'elasticfilesystem:ClientWrite', | ||
'elasticfilesystem:ClientMount', | ||
'elasticfilesystem:DescribeMountTargets' | ||
] | ||
) | ||
] | ||
) | ||
) | ||
|
||
# Create a new Fargate Task Definition | ||
task_definition = ecs.FargateTaskDefinition( | ||
self, PREFIX + 'FargateTaskDef', | ||
task_role=task_role, | ||
) | ||
|
||
# Add a new volume to the Fargate Task Definition | ||
task_definition.add_volume( | ||
name=VOLUME_NAME, | ||
efs_volume_configuration=efs_volume_configuration, | ||
) | ||
|
||
# Add a new container to the Fargate Task Definition | ||
mount_point = ecs.MountPoint( | ||
container_path=APP_PATH+VOLUME_NAME, | ||
source_volume=VOLUME_NAME, | ||
read_only=False, | ||
) | ||
|
||
# Add a new port mapping to the Fargate Task Definition | ||
port_mapping = ecs.PortMapping( | ||
container_port=80, | ||
host_port=80, | ||
protocol=ecs.Protocol.TCP, | ||
) | ||
|
||
# Add a new container to the Fargate Task Definition | ||
container = ecs.ContainerDefinition( | ||
self, 'ecs-cdk-sample-container', | ||
task_definition=task_definition, | ||
image=ecs.ContainerImage.from_registry('amazon/amazon-ecs-sample'), | ||
logging=ecs.LogDrivers.aws_logs( | ||
stream_prefix='cdk-ecs-sample', | ||
log_retention=logs.RetentionDays.ONE_MONTH, | ||
) | ||
) | ||
|
||
# Add a new volume to the Fargate Task Definition | ||
container.add_mount_points(mount_point), | ||
|
||
# Add a new port mapping to the Fargate Task Definition | ||
container.add_port_mappings(port_mapping), | ||
|
||
# Create a new Fargate Service with ALB | ||
fargate_service = ecs_patterns.ApplicationLoadBalancedFargateService( | ||
self, PREFIX + 'Service', | ||
cluster=ecs_cluster, | ||
desired_count=1, | ||
task_definition=task_definition, | ||
task_subnets=ec2.SubnetSelection( | ||
subnet_type=ec2.SubnetType.PRIVATE_WITH_EGRESS, | ||
), | ||
platform_version=ecs.FargatePlatformVersion.LATEST, | ||
public_load_balancer=True, | ||
enable_execute_command=True, | ||
enable_ecs_managed_tags=True, | ||
|
||
) | ||
|
||
# Allow the ECS Service to connect to the EFS | ||
fargate_service.service.connections.allow_from(file_system, ec2.Port.tcp(2049)), | ||
|
||
# Allow the EFS to connect to the ECS Service | ||
fargate_service.service.connections.allow_to(file_system, ec2.Port.tcp(2049)), | ||
|
||
# Create a new Auto Scaling Policy for the ECS Service | ||
scalable_target = fargate_service.service.auto_scale_task_count( | ||
min_capacity=1, | ||
max_capacity=20, | ||
) | ||
|
||
# Create a new Auto Scaling Policy for the ECS Service | ||
scalable_target.scale_on_cpu_utilization("CpuScaling", | ||
target_utilization_percent=50, | ||
) | ||
|
||
# Create a new Auto Scaling Policy for the ECS Service | ||
scalable_target.scale_on_memory_utilization("MemoryScaling", | ||
target_utilization_percent=50, | ||
) | ||
|
||
# Create the new CDK Application | ||
cdk_application = App() | ||
FargateServiceWithEfs(cdk_application, "aws-fargate-service-with-efs") | ||
cdk_application.synth() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
{ | ||
"app": "python3 app.py", | ||
"watch": { | ||
"include": [ | ||
"**" | ||
], | ||
"exclude": [ | ||
"README.md", | ||
"cdk*.json", | ||
"requirements*.txt", | ||
"source.bat", | ||
"**/__init__.py", | ||
"**/__pycache__", | ||
"tests" | ||
] | ||
}, | ||
"context": { | ||
"@aws-cdk/aws-lambda:recognizeLayerVersion": true, | ||
"@aws-cdk/core:checkSecretUsage": true, | ||
"@aws-cdk/core:target-partitions": [ | ||
"aws", | ||
"aws-cn" | ||
], | ||
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, | ||
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, | ||
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, | ||
"@aws-cdk/aws-iam:minimizePolicies": true, | ||
"@aws-cdk/core:validateSnapshotRemovalPolicy": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, | ||
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, | ||
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, | ||
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true, | ||
"@aws-cdk/core:enablePartitionLiterals": true, | ||
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, | ||
"@aws-cdk/aws-iam:standardizedServicePrincipals": true, | ||
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, | ||
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, | ||
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, | ||
"@aws-cdk/aws-route53-patters:useCertificate": true, | ||
"@aws-cdk/customresources:installLatestAwsSdkDefault": false, | ||
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, | ||
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, | ||
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, | ||
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, | ||
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, | ||
"@aws-cdk/aws-redshift:columnId": true, | ||
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, | ||
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, | ||
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, | ||
"@aws-cdk/aws-kms:aliasNameRef": true, | ||
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, | ||
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true, | ||
"@aws-cdk/aws-efs:denyAnonymousAccess": true, | ||
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, | ||
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, | ||
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, | ||
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, | ||
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, | ||
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, | ||
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, | ||
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, | ||
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, | ||
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, | ||
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, | ||
"@aws-cdk/aws-eks:nodegroupNameAttribute": true | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
aws-cdk-lib==2.144.0 | ||
constructs>=10.0.0,<11.0.0 |