-
Notifications
You must be signed in to change notification settings - Fork 2
/
app.py
161 lines (144 loc) · 6.52 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python3
# %%
# Imports
import os
from dotenv import load_dotenv
from pathlib import Path
from aws_cdk import (
aws_lambda as lambda_,
aws_apigatewayv2_alpha as api_gw2_a,
aws_efs as efs,
aws_ec2 as ec2
)
from aws_cdk import (App, Stack, Duration, RemovalPolicy,
Environment, CfnOutput)
from aws_cdk.aws_apigatewayv2_integrations_alpha import HttpLambdaIntegration
from constructs import Construct
# %%
# Read dotenv for environment variables
load_dotenv()
# Region and account for stack
aws_env = Environment(
account=os.environ['AWS_ACCOUNT_ID'], region=os.environ['AWS_REGION'])
# Stack for this cdk program
class NlpLambdaStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# %%
# EFS needs to be setup in a VPC (but no NAT gateways, please)
# Alternative for no nat gateway
# Source: https://github.com/aws/aws-cdk/issues/1305#issuecomment-547361989
vpc = ec2.Vpc(self, 'FargateVPC',
cidr='10.0.0.0/16',
max_azs=1,
nat_gateways=0,
subnet_configuration=[
{
'cidr_mask': 24,
'name': 'Public',
'subnetType': ec2.SubnetType.PUBLIC
}
]
)
# %%
# Creates a file system in EFS to store cache models
fs = efs.FileSystem(self, 'FileSystem',
vpc=vpc,
removal_policy=RemovalPolicy.DESTROY)
access_point = fs.add_access_point('MLAccessPoint',
create_acl=efs.Acl(
owner_gid='1001', owner_uid='1001', permissions='750'),
path="/export/models",
posix_user=efs.PosixUser(gid="1001", uid="1001"))
# %%
# Create Http Gateway API
# Source (adapted): https://bobbyhadz.com/blog/aws-cdk-api-gateway-example
# Source (api for alpha): https://docs.aws.amazon.com/cdk/api/v2/python/aws_cdk.aws_apigatewayv2_alpha/HttpApi.html
methods = [api_gw2_a.CorsHttpMethod.GET,
api_gw2_a.CorsHttpMethod.POST]
httpApi = api_gw2_a.HttpApi(self, 'AiidNlpHttpApi',
description='HTTP API Gateway for AIID Lambdas',
cors_preflight={
'allow_headers': ['Content-Type',
'X-Amz-Date',
'Authorization',
'X-Api-Key', ],
'allow_methods': methods,
'allow_credentials': True,
'allow_origins': ['http://localhost:3000',
'http://www.apirequest.io/',
'https://www.apirequest.io/'],
}
)
# Create output for the api url
# this outputs the apiUrl to a json file when deploying the stack, so it can be used by programs as needed
CfnOutput(self, 'apiUrl', value=httpApi.url)
# %%
# Iterates through the Python files in the docker directory
docker_folder = os.path.dirname(
os.path.realpath(__file__)) + "/inference"
pathlist = Path(docker_folder).rglob('*.py')
for path in pathlist:
# Parse lambda handler filename name
base = os.path.basename(path)
filename = os.path.splitext(base)[0]
# Lambda Function from docker image
function = lambda_.DockerImageFunction(
self, filename,
allow_public_subnet=True,
code=lambda_.DockerImageCode.from_image_asset(
docker_folder, cmd=[filename+".handler"]),
memory_size=8096,
timeout=Duration.seconds(600),
vpc=vpc,
filesystem=lambda_.FileSystem.from_efs_access_point(
access_point, '/mnt/hf_models_cache'),
environment={
"TRANSFORMERS_CACHE": "/mnt/hf_models_cache",
"MODEL_DIR": "model",
"MODEL_FILENAME": "pytorch_model.bin",
"INCIDENTS_FILENAME": "incident_cls.pt",
"CSV_FILENAME": "incidents.csv",
"HF_MODEL_URI": "allenai/longformer-base-4096"
},
)
# Create lambda integration for use in the Gateway API
lambda_integration = HttpLambdaIntegration('LambdaIntegration', function)
# Add route lambda integration to a route on the api, using the fn name
httpApi.add_routes(
path=f"/{filename}",
methods=[api_gw2_a.HttpMethod.GET, api_gw2_a.HttpMethod.POST],
integration=lambda_integration
)
# %%
# Initialize the aws stack
app = App()
NlpLambdaStack(app, "AiidNlpLambdaStack", env=aws_env)
app.synth()
# %%
# # # # Backup vpc configurations
# # Custom, no nat gateway? (doesnt work yet)
# # Source: https://github.com/aws/aws-cdk/issues/1305
# vpc = ec2.Vpc(self, 'Vpc', max_azs=2, nat_gateways=0)
# exclude_condition = CfnCondition(
# self, 'exclude-default-route-subnet', expression=Fn.condition_equals(True, False))
# for subnet in vpc.private_subnets:
# for child in subnet.node.children:
# if type(child) == ec2.CfnRoute:
# route: ec2.CfnRoute = child
# route.cfn_options.condition = exclude_condition # key point here
# # Alternative for NAT instance rather than NAT gateway
# # Source: https://github.com/aws/aws-cdk/issues/1305#issuecomment-554700587
# vpc = ec2.Vpc(self, 'vpc',
# cidr='10.40.0.0/16',
# max_azs=2,
# nat_gateways=2,
# nat_gateway_provider=ec2.NatProvider.instance(
# instance_type = ec2.InstanceType('t3a.nano'), # 'instanceType': ec2.InstanceType.of(ec2.InstanceClass.T3A, ec2.InstanceSize.NANO),
# ),
# gateway_endpoints= {
# 's3': {'service': ec2.GatewayVpcEndpointAwsService.S3},
# },
# )
# # Default, using NAT gateway
# vpc = ec2.Vpc(self, 'Vpc', max_azs=2)