Skip to content

Commit 5be35bc

Browse files
committed
move lambda to docker due to sagemaker sdk dependency size
1 parent ac2bd7d commit 5be35bc

5 files changed

Lines changed: 84 additions & 51 deletions

File tree

modules/sagemaker/sagemaker-model-monitoring/sagemaker_model_monitoring/baselining_construct.py

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from typing import Any, List
22

3-
from aws_cdk import BundlingOptions, Duration
3+
from aws_cdk import Duration
44
from aws_cdk import aws_events as events
55
from aws_cdk import aws_events_targets as targets
66
from aws_cdk import aws_iam as iam
@@ -34,27 +34,17 @@ def __init__(
3434
) -> None:
3535
super().__init__(scope, construct_id, **kwargs)
3636

37-
# Lambda function
38-
baselining_lambda = lambda_.Function(
37+
# Lambda function using Docker container image
38+
# This approach bypasses the 250MB layer limit by using container images (up to 10GB)
39+
baselining_lambda = lambda_.DockerImageFunction(
3940
self,
4041
"BaseliningLambda",
41-
runtime=lambda_.Runtime.PYTHON_3_13,
42-
handler="baselining_handler.lambda_handler",
43-
code=lambda_.Code.from_asset(
42+
code=lambda_.DockerImageCode.from_image_asset(
4443
"sagemaker_model_monitoring/lambda",
45-
bundling=BundlingOptions(
46-
image=lambda_.Runtime.PYTHON_3_13.bundling_image,
47-
command=[
48-
"bash",
49-
"-c",
50-
"pip install pydantic==2.10.3 -t /asset-output --no-cache-dir && "
51-
"pip install sagemaker==2.232.2 -t /asset-output --no-deps --no-cache-dir && "
52-
"rm -rf /asset-output/{boto*,urllib3*,certifi*,six*,python_dateutil*,jmespath*,s3transfer*} && "
53-
"find /asset-output \\( -name '*.pyc' -o -name '*.so' \\) -delete && "
54-
"find /asset-output -type d \\( -name '__pycache__' -o -name 'test*' \\) -exec rm -rf {} + && "
55-
"cp -au . /asset-output",
56-
],
57-
),
44+
cmd=["baselining_handler.lambda_handler"],
45+
build_args={
46+
"PYTHON_VERSION": "3.13",
47+
},
5848
),
5949
timeout=Duration.minutes(15),
6050
memory_size=2048,
@@ -156,6 +146,16 @@ def __init__(
156146
),
157147
)
158148

149+
# Cron trigger
150+
rule = events.Rule(self, "BaseliningScheduleRule", schedule=events.Schedule.expression(schedule_expression))
151+
152+
for monitor_type in enabled_monitors:
153+
rule.add_target(
154+
targets.SfnStateMachine(
155+
state_machine, input=events.RuleTargetInput.from_object({"monitor_type": monitor_type})
156+
)
157+
)
158+
159159
# Add CDK-nag suppressions
160160
if baselining_lambda.role:
161161
NagSuppressions.add_resource_suppressions(
@@ -183,13 +183,3 @@ def __init__(
183183
],
184184
apply_to_children=True,
185185
)
186-
187-
# Cron trigger
188-
rule = events.Rule(self, "BaseliningScheduleRule", schedule=events.Schedule.expression(schedule_expression))
189-
190-
for monitor_type in enabled_monitors:
191-
rule.add_target(
192-
targets.SfnStateMachine(
193-
state_machine, input=events.RuleTargetInput.from_object({"monitor_type": monitor_type})
194-
)
195-
)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
__pycache__
2+
*.pyc
3+
*.pyo
4+
*.pyd
5+
.Python
6+
*.so
7+
*.egg
8+
*.egg-info
9+
dist
10+
build
11+
.pytest_cache
12+
.coverage
13+
htmlcov
14+
.tox
15+
.git
16+
.gitignore
17+
README.md
18+
*.md
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
ARG PYTHON_VERSION=3.13
2+
FROM public.ecr.aws/lambda/python:${PYTHON_VERSION}
3+
4+
# Install build dependencies for numpy and other packages
5+
RUN dnf install -y gcc gcc-c++ make && \
6+
dnf clean all && \
7+
rm -rf /var/cache/dnf
8+
9+
# Upgrade pip to latest version
10+
RUN pip install --no-cache-dir --upgrade pip
11+
12+
# Copy requirements and install dependencies
13+
COPY requirements.txt ${LAMBDA_TASK_ROOT}/
14+
RUN pip install --no-cache-dir -r requirements.txt
15+
16+
# Copy function code
17+
COPY *.py ${LAMBDA_TASK_ROOT}/
18+
19+
# Set the CMD to your handler
20+
CMD ["baselining_handler.lambda_handler"]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pydantic==2.10.3
2+
pydantic-core
3+
# Use numpy version with pre-built wheels for Python 3.13
4+
numpy>=1.26.0,<2.0
5+
sagemaker==2.232.2

modules/sagemaker/sagemaker-model-monitoring/sagemaker_model_monitoring/stack.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -155,17 +155,6 @@ def __init__(
155155
),
156156
)
157157

158-
# TODO Reduce the use of wildcards by limiting to the provided KMS key ID & needed bucket prefixes.
159-
NagSuppressions.add_resource_suppressions(
160-
model_monitor_policy,
161-
suppressions=[
162-
{
163-
"id": "AwsSolutions-IAM5",
164-
"reason": "The IAM policy needs access to the S3 bucket and associated KMS keys",
165-
},
166-
],
167-
)
168-
169158
model_monitor_role = iam.Role(
170159
self,
171160
"Model Monitor Role",
@@ -176,17 +165,6 @@ def __init__(
176165
],
177166
)
178167

179-
# TODO Avoid AmazonSageMakerFullAccess by limiting to the needed operations.
180-
NagSuppressions.add_resource_suppressions(
181-
model_monitor_role,
182-
suppressions=[
183-
{
184-
"id": "AwsSolutions-IAM4",
185-
"reason": "The IAM policy needs access to many SageMaker and EC2 operations.",
186-
},
187-
],
188-
)
189-
190168
model_bucket_name = model_bucket_arn.split(":")[-1]
191169

192170
if baseline_training_data_s3_uri and baseline_output_data_s3_uri:
@@ -303,3 +281,25 @@ def __init__(
303281
probability_attribute=model_explainability_probability_attribute,
304282
schedule_expression=model_explainability_schedule_expression,
305283
)
284+
285+
# TODO Avoid AmazonSageMakerFullAccess by limiting to the needed operations.
286+
NagSuppressions.add_resource_suppressions(
287+
model_monitor_role,
288+
suppressions=[
289+
{
290+
"id": "AwsSolutions-IAM4",
291+
"reason": "The IAM policy needs access to many SageMaker and EC2 operations.",
292+
},
293+
],
294+
)
295+
296+
# TODO Reduce the use of wildcards by limiting to the provided KMS key ID & needed bucket prefixes.
297+
NagSuppressions.add_resource_suppressions(
298+
model_monitor_policy,
299+
suppressions=[
300+
{
301+
"id": "AwsSolutions-IAM5",
302+
"reason": "The IAM policy needs access to the S3 bucket and associated KMS keys",
303+
},
304+
],
305+
)

0 commit comments

Comments
 (0)