Как развернуть и прикрепить слой к лямбда-функции aws с помощью aws CDK?
Мне нужен простой код cdk, который развертывает и прикрепляет слой к лямбда-функции aws.
Как развернуть и прикрепить слой к лямбда-функции aws с помощью aws CDK?
Мне нужен простой код cdk, который развертывает и прикрепляет слой к лямбда-функции aws.
Следующий код aws CDK Python развертывает слой и прикрепляет его к лямбда-функции aws.
by yl.
--+
+-app.py
+-cdk_layers_deploy.py
+--/functions+
+-testLambda.py
+--/layers+
+-custom_func.py
#!/usr/bin/env python3
import sys
from aws_cdk import (core)
from cdk_layers_deploy import CdkLayersStack
app = core.App()
CdkLayersStack(app, "cdk-layers")
app.synth()
from aws_cdk import (
aws_lambda as _lambda,
core,
aws_iam)
from aws_cdk.aws_iam import PolicyStatement
from aws_cdk.aws_lambda import LayerVersion, AssetCode
class CdkLayersStack(core.Stack):
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
super().__init__(scope, id, **kwargs)
# 1) deploy lambda functions
testLambda : _lambda.Function = CdkLayersStack.cdkResourcesCreate(self)
# 2) attach policy to function
projectPolicy = CdkLayersStack.createPolicy(self, testLambda)
# -----------------------------------------------------------------------------------
@staticmethod
def createPolicy(this, testLambda:_lambda.Function) -> None:
projectPolicy:PolicyStatement = PolicyStatement(
effect=aws_iam.Effect.ALLOW,
# resources=["*"],
resources=[testLambda.function_arn],
actions=[ "dynamodb:Query",
"dynamodb:Scan",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:UpdateItem",
"states:StartExecution",
"states:SendTaskSuccess",
"states:SendTaskFailure",
"cognito-idp:ListUsers",
"ses:SendEmail"
]
)
return projectPolicy;
# -----------------------------------------------------------------------------------
@staticmethod
def cdkResourcesCreate(self) -> None:
lambdaFunction:_lambda.Function = _lambda.Function(self, 'testLambda',
function_name='testLambda',
handler='testLambda.lambda_handler',
runtime=_lambda.Runtime.PYTHON_3_7,
code=_lambda.Code.asset('functions'),
)
ac = AssetCode("layers")
layer = LayerVersion(self, "l1", code=ac, description="test-layer", layer_version_name='Test-layer-version-name')
lambdaFunction.add_layers(layer)
return lambdaFunction
# -----------------------------------------------------------------------------------
# -------------------------------------------------
# testLambda
# -------------------------------------------------
import custom_func as cf # this line is errored in pyCharm -> will be fixed on aws when import the layer
def lambda_handler(event, context):
print(f"EVENT:{event}")
ret = cf.cust_fun()
return {
'statusCode': 200,
'body': ret
}
import datetime
def cust_fun():
print("Hello from the deep layers!!")
date_time = datetime.datetime.now().isoformat()
print("dateTime:[%s]\n" % (date_time))
return 1
Вы можете сделать это, сначала создав и развернув свой слой, а затем импортировав его из aws и передав в качестве аргумента слоя для лямбда в определении стека.
Мы обнаружили, что самым простым решением для этого является создание папки /layer
в корневом проекте cdk и создание файла bash для развертывания слоя (для его запуска необходимо cd
в папку /layer
).
LAYER_NAME="<layer_name>"
echo <your_package>==<package.version.0> >> requirements.txt # See PyPi for the exact version
docker run -v "$PWD":/var/task "lambci/lambda:build-python3.6" /bin/sh -c "pip install -r requirements.txt -t python/lib/python3.6/site-packages/; exit"
zip -r $LAYER_NAME.zip python > /dev/null
aws lambda publish-layer-version \
--layer-name $LAYER_NAME \
--zip-file fileb://$LAYER_NAME.zip \
--compatible-runtimes "python3.6" \
--region <your_region>
rm requirements.txt
rm -rf python
rm $LAYER_NAME.zip
Затем вам нужно найти ARN слоя в вашей консоли AWS (Lambda›Layers) и определить свой слой в вашем _stack.py
следующим образом:
layer = aws_lambda.LayerVersion.from_layer_version_arn(
self,
'<layer_name>',
<layer_ARN> # arn:aws:lambda:<your_region:<your_account_id>:layer:<layer_name>:<layer_version>
)
Затем вы можете передать его в свою лямбду:
lambda = aws_lambda.Function(
scope=self,
id='<lambda_id>',
handler='function.handler',
runtime=aws_lambda.Runtime.PYTHON_3_6,
code=aws_lambda.Code.asset(path='./lambda'),
environment={
},
layers=[
layer
]
)
Это не будет работать. Вместо этого вам нужно поставить custom_func.py
на layers/python/lib/python3.7/site-packages/custom_func.py
, чтобы все заработало (https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-path).
Вы можете использовать его следующим образом,
mysql_lib = lb.LayerVersion(self, 'mysql',
code = lb.AssetCode('lambda/layers/'),
compatible_runtimes = [lb.Runtime.PYTHON_3_6],
)
my_lambda = lb.Function(
self, 'core-lambda-function',
runtime=lb.Runtime.PYTHON_3_6,
code=lb.InlineCode(handler_code),
function_name="lambda_function_name",
handler="index.handler",
layers = [mysql_lib],
timeout=core.Duration.seconds(300),
)
Я настроил это для использования моих пакетов сайтов в моей виртуальной среде, поэтому он включает не только мои зависимости, но и их зависимости. Чтобы сделать это при создании среды, настройте venv следующим образом:
mkdir .venv
python3 -m venv .venv/python
Затем в стеке укажите вашу виртуальную среду как AssetCode(.venv). Потому что это включает в себя версию Python в пути как часть пакетов сайта, которые вы должны ограничить совместимость в зависимости от вашей версии. Самый простой способ поддерживать все версии Python — использовать другую структуру, как определено https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html
Пример:
from aws_cdk import core
from aws_cdk.aws_lambda import AssetCode, LayerVersion, Runtime
class lambda_layer_stack(core.Stack):
def __init__(self, scope: core.Construct, construct_id: str, version: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
ac = AssetCode(path=".venv")
au_layer = LayerVersion(
self,
id=construct_id,
code=ac,
layer_version_name=construct_id,
description=version,
compatible_runtimes=[Runtime.PYTHON_3_8],
)