这就是我在 typescipt 中定义所有 python lambda 函数的方式(屏蔽了所有敏感信息):
import * as cdk from 'aws-cdk-lib';
import { Stack, StackProps } from 'aws-cdk-lib';
import { AuthorizationType, CfnAuthorizer, CfnMethod, LambdaIntegration, Resource, RestApi } from 'aws-cdk-lib/aws-apigateway';
import { Effect, IManagedPolicy, ManagedPolicy, PolicyStatement, Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Duration } from 'aws-cdk-lib/core';
import { Rule, Schedule } from 'aws-cdk-lib/aws-events';
import { Code, DockerImageFunction, Function, ILayerVersion, LayerVersion, Runtime } from 'aws-cdk-lib/aws-lambda';
import * as eventsources from 'aws-cdk-lib/aws-lambda-event-sources';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Secret } from 'aws-cdk-lib/aws-secretsmanager';
import { Queue } from 'aws-cdk-lib/aws-sqs';
import { StringParameter } from 'aws-cdk-lib/aws-ssm';
import { Construct } from 'constructs';
import { AMA, APIPaths, EventBridgeRules, Handlers, Lambdas, Methods, Package, SSM_PARAM } from '../constants';
import { createQueueWithDLQ, createSQSEventSource } from '../sqsUtils';
import { createLambdaFunction, getCommonBucketName } from '../utils';
import { CognitoStack } from './cognitoStack';
import { LambdaStack } from './lambdaStack';
import { RDSStack } from './rdsStack';
import { S3BucketStack } from './s3BucketStack';
import { VPCStack } from './vpcStack';
const EMBEDDING_LOG_POLLING_INTERVAL = Duration.minutes(5);
export const ACTIVE_EMBEDDING_LOG_STACKS = [
{ accountId: '<MASKED_ACCOUNT_ID_1>', stageName: 'alpha' },
{ accountId: '<MASKED_ACCOUNT_ID_2>', stageName: 'ui' },
{ accountId: '<MASKED_ACCOUNT_ID_3>', stageName: 'ui2' },
{ accountId: '<MASKED_ACCOUNT_ID_4>', stageName: 'aryan' },
{ accountId: '<MASKED_ACCOUNT_ID_4>', stageName: 'ama' },
];
export const EMBEDDING_POLLING_LAMBDA_DURATION = Duration.seconds(30);
export class AmaStack extends Stack {
public readonly AmaServiceAPI: RestApi;
public readonly Amaauthorizer: CfnAuthorizer;
// Resources
public readonly ParentFunctionResource: Resource;
public readonly RedirectionEngineResource: Resource;
public readonly aiFormFillupResource: Resource;
// ama
public readonly amaServiceLambda: Function;
public readonly getAmaChats: Function;
public readonly feedbackLambda: Function;
public readonly redirectionEngine: Function;
public readonly embeddingLambda: Function;
public readonly aiFormFillup: Function;
public readonly aiFormUpdate: Function;
public readonly aiFormUpdateQueue: Queue;
public readonly aiFormUpdateDlqQueue: Queue;
// prompt engine
public readonly promptEngine: Function;
// embedding log queue
public readonly embeddingLogQueue: Queue;
public readonly embeddingLogDlqQueue: Queue;
// layer
public readonly layer: ILayerVersion;
embeddingPollingLambda: cdk.aws_lambda.Function;
constructor(scope: Construct, id: string, props: AMAProps) {
super(scope, id, props);
this.AmaServiceAPI = new RestApi(this, `AmaServiceAPI-${props.stage}`);
const baseLayerArn = StringParameter.valueForStringParameter(this, `${SSM_PARAM}-${props.stage}`);
this.layer = LayerVersion.fromLayerVersionArn(this, `AmaLayerFromArn-${props.stage}`, baseLayerArn);
const commonEnvironmentVariables = {
COMPANY_RDS_SECRET: props.rdsStack.DatabaseCluster.secret!.secretValue.unsafeUnwrap(),
};
this.Amaauthorizer = new CfnAuthorizer(this, `APIGatewayAuthorizer-${props.stage}`, {
name: `Ama-authorizer-${props.stage}`,
identitySource: 'method.request.header.Authorization',
providerArns: [props.cognitoStack.cognitoPool.userPoolArn],
restApiId: this.AmaServiceAPI.restApiId,
type: AuthorizationType.COGNITO,
});
this.ParentFunctionResource = this.AmaServiceAPI.root.addResource(APIPaths.AMA);
this.RedirectionEngineResource = this.AmaServiceAPI.root.addResource(APIPaths.REDIRECTION_ENGINE);
const openAISecret = Secret.fromSecretNameV2(this, 'OpenAISecret', 'Open-AI-API-Key');
const openAIKey = openAISecret.secretValueFromJson('OPENAI_API_KEY');
const AMAFeedbackResource = this.ParentFunctionResource.addResource(APIPaths.AMA_FEEDBACK);
const managedPolicies = [
ManagedPolicy.fromAwsManagedPolicyName('AWSLambdaExecute'),
ManagedPolicy.fromAwsManagedPolicyName('AWSLambda_FullAccess'),
ManagedPolicy.fromAwsManagedPolicyName('CloudWatchLambdaInsightsExecutionRolePolicy'),
ManagedPolicy.fromAwsManagedPolicyName('AmazonBedrockFullAccess'),
ManagedPolicy.fromAwsManagedPolicyName('AmazonS3FullAccess'),
];
const embeddingQueueAndDlqQueue = createQueueWithDLQ(this, 'EmbeddingLogQueue', props.stage, {
visibilityTimeout: Duration.seconds(120),
maxReceiveCount: 3,
});
this.embeddingLogQueue = embeddingQueueAndDlqQueue.queue;
this.embeddingLogDlqQueue = embeddingQueueAndDlqQueue.dlqQueue;
this.embeddingPollingLambda = createLambdaFunction(
this,
Lambdas.EMBEDDING_LOG_POLLING,
Package.BACKEND,
Handlers.EMBEDDING_LOG_POLLING,
props.stage,
{
roleName: `${Lambdas.EMBEDDING_LOG_POLLING}-Role`,
managedPolicies: managedPolicies,
resources: [this.embeddingLogQueue.queueArn],
actions: ['sqs:SendMessage'],
},
{
...commonEnvironmentVariables,
EMBEDDING_LOG_QUEUE: this.embeddingLogQueue.queueUrl,
},
EMBEDDING_POLLING_LAMBDA_DURATION,
[this.layer],
props.vpcStack.vpc,
);
const rule = new Rule(this, `EventBridge-${EventBridgeRules.AMA_LOG_POLLING}`, {
description: `Rule to trigger embedding polling lambda every ${EMBEDDING_LOG_POLLING_INTERVAL} minutes`,
schedule: Schedule.rate(EMBEDDING_LOG_POLLING_INTERVAL),
});
if (ACTIVE_EMBEDDING_LOG_STACKS.find((stack) => stack.accountId === props.accountId && stack.stageName === props.stage)) {
rule.addTarget(new cdk.aws_events_targets.LambdaFunction(this.embeddingPollingLambda));
}
const aiFormUpdateQueueAndDldQueue = createQueueWithDLQ(this, 'AiFormUpdateQueue', props.stage, {
visibilityTimeout: cdk.Duration.seconds(120),
maxReceiveCount: 3,
});
this.aiFormUpdateQueue = aiFormUpdateQueueAndDldQueue.queue;
this.aiFormUpdateDlqQueue = aiFormUpdateQueueAndDldQueue.dlqQueue;
this.amaServiceLambda = this.createDockerLambdaFunction(
Lambdas.AMA_LAMBDA,
Handlers.AMA_SERVICE,
props.stage,
{
roleName: `${Lambdas.AMA_LAMBDA}-${props.stage}-Role`,
managedPolicies: managedPolicies,
actions: ['s3:GetObject', 's3:GetObjectTagging', 's3:ListBucket'],
resources: [props.lambdaStack.replicateUserProfile.functionArn],
},
{
BUCKET_PREFIX: AMA.BUCKET_PREFIX,
MODEL: AMA.MODEL,
EMBEDDING: AMA.EMBEDDING,
LANGCHAIN_TRACING_V2: 'true',
LANGCHAIN_ENDPOINT: props.langchainEndpoint,
LANGCHAIN_API_KEY: props.langchainApiKey,
LANGCHAIN_PROJECT: `AMA-${props.stage}`,
STAGE_NAME: props.stage,
BUCKET_PREFIX: getCommonBucketName(props.accountId, props.stage),
LLM_TOP_P: '0.2',
OPENAI_API_KEY: openAIKey.unsafeUnwrap(),
LLM_TEMPERATURE: '0.2',
RETRIEVER_K: '3',
...commonEnvironmentVariables,
},
);
openAISecret.grantRead(this.amaServiceLambda);
this.promptEngine = this.createDockerLambdaFunction(
Lambdas.PROMPT_ENGINE,
Handlers.PROMPT_ENGINE,
props.stage,
{
roleName: `${Lambdas.PROMPT_ENGINE}-${props.stage}-Role`,
managedPolicies: managedPolicies,
actions: ['s3:GetObject', 's3:GetObjectTagging', 's3:ListBucket'],
resources: [props.lambdaStack.replicateUserProfile.functionArn],
},
{
MODEL: AMA.MODEL,
EMBEDDING: AMA.EMBEDDING,
},
);
this.feedbackLambda = this.createDockerLambdaFunction(
Lambdas.FEEDBACK_LAMBDA,
Handlers.AMA_FEEDBACK,
props.stage,
{
roleName: `${Lambdas.FEEDBACK_LAMBDA}-${props.stage}-Role`,
managedPolicies: managedPolicies,
actions: ['s3:GetObject', 's3:GetObjectTagging', 's3:ListBucket'],
resources: [props.lambdaStack.replicateUserProfile.functionArn],
},
{
BUCKET_PREFIX: AMA.BUCKET_PREFIX,
MODEL: AMA.MODEL,
LANGCHAIN_ENDPOINT: '<MASKED_LANGCHAIN_ENDPOINT>',
LANGCHAIN_API_KEY: '<MASKED_LANGCHAIN_API_KEY>',
},
);
this.configureMethodOnResource(AMAFeedbackResource, Methods.POST, new LambdaIntegration(this.feedbackLambda));
this.redirectionEngine = this.createDockerLambdaFunction(
Lambdas.REDIRECTION_ENGINE,
Handlers.REDIRECTION_ENGINE,
props.stage,
{
roleName: `${Lambdas.REDIRECTION_ENGINE}-${props.stage}-Role`,
managedPolicies: managedPolicies,
actions: ['s3:GetObject', 's3:GetObjectTagging', 's3:ListBucket'],
resources: [
props.lambdaStack.replicateUserProfile.functionArn,
this.amaServiceLambda.functionArn,
this.promptEngine.functionArn,
],
},
{
AMA_LAMBDA: this.amaServiceLambda.functionName,
PROMPT_ENGINE: this.promptEngine.functionName,
BUCKET_PREFIX: AMA.BUCKET_PREFIX,
MODEL: AMA.MODEL,
EMBEDDING: AMA.EMBEDDING,
OPENAI_API_KEY: openAIKey.unsafeUnwrap(),
LANGCHAIN_TRACING_V2: 'true',
LANGCHAIN_ENDPOINT: props.langchainEndpoint,
LANGCHAIN_API_KEY: props.langchainApiKey,
LANGCHAIN_PROJECT: `RedirectionEngine-${props.stage}`,
STAGE_NAME: props.stage,
},
);
this.embeddingLambda = this.createDockerLambdaFunction(
Lambdas.EMBEDDING_ENGINE,
Handlers.EMBEDDING_ENGINE,
props.stage,
{
roleName: `${Lambdas.EMBEDDING_ENGINE}-${props.stage}-Role`,
managedPolicies: managedPolicies,
actions: ['s3:GetObject', 's3:GetObjectTagging', 's3:ListBucket'],
resources: [props.lambdaStack.replicateUserProfile.functionArn],
},
{
BUCKET_PREFIX: AMA.BUCKET_PREFIX,
MODEL: AMA.MODEL,
EMBEDDING: AMA.EMBEDDING,
LANGCHAIN_TRACING_V2: 'true',
LANGCHAIN_ENDPOINT: props.langchainEndpoint,
LANGCHAIN_API_KEY: props.langchainApiKey,
LANGCHAIN_PROJECT: `AMA-${props.stage}`,
STAGE_NAME: props.stage,
BUCKET_PREFIX: getCommonBucketName(props.accountId, props.stage),
PINECONE_API_KEY: '<MASKED_PINECONE_API_KEY>',
LLM_TOP_P: '0.3',
OPENAI_API_KEY: openAIKey.unsafeUnwrap(),
LLM_TEMPERATURE: '0.3',
RETRIEVER_K: '3',
...commonEnvironmentVariables,
},
);
// ... [Implementation details for remaining methods]
}
// ... [Rest of the class implementation]
}
export interface AMAProps extends StackProps {
readonly stage: string;
readonly region: string;
readonly accountId: string;
readonly langchainEndpoint: string;
readonly langchainApiKey: string;
readonly lambdaStack: LambdaStack;
readonly cognitoStack: CognitoStack;
readonly rdsStack: RDSStack;
readonly vpcStack: VPCStack;
readonly s3BucketStack: S3BucketStack;
}
export interface IAMRoleProps {
readonly roleName: string;
readonly managedPolicies: IManagedPolicy[];
readonly actions: string[];
readonly resources: string[];
}
我尝试将 lambda 作为服务,但由于冷启动而遇到麻烦,想转向 EKS/ECS。无法将所有内容转移到 Web 服务器,我如何通过 CDK 以最少的代码更改来完成此操作。
我想将基础设施转移到 EKS/ECS ,还建议它所带来的差异,我主要使用 lambda,没有使用 ECS/EKS。
当您为函数启用预置并发时,Lambda 服务将初始化请求数量的执行环境,以便它们可以准备好响应调用。
参考:https://aws.amazon.com/blogs/aws/new-provisioned-concurrency-for-lambda-functions/
首先,您应该配置 Lambda 冷启动问题预配置并发。
这是分配给您的函数的预初始化执行环境的数量。这些执行环境已准备好立即响应传入的功能请求。预配置并发对于减少函数的冷启动延迟很有用。配置预置并发会导致您的 AWS 账户产生额外费用。
如果您想提高 Lambda 函数的性能,那么您需要增加其内存。
想要转向 EKS/ECS。无法将所有内容转移到 Web 服务器,我如何通过 CDK 以最少的代码更改来完成此操作。
是否选择 EKS 还是 ECS 将取决于您的应用程序、您管理它们的专业知识、控制和定价以及可移植性(供应商锁定)。
但是看到你的问题我认为 ECS 会是更好的选择,因为:
如果您不熟悉容器编排和部署,ECS 是一个很好的起点,因为它成本较低,并且几乎不需要或不需要管理 Kubernetes 集群的专业知识。如果您熟悉 AWS 平台,AWS ECS 也是一个不错的选择,因为它提供与 Amazon 服务的紧密集成。 ECS 您无需为控制平面付费,这意味着它可能会更便宜。
如果您选择 EKS,那么:
如果您正在寻找多云功能和容器化工作负载的可移植性,EKS 是首选,因为它不会将您锁定在 Amazon 云中。 EKS 还提供附加功能、更多自定义选项以及对容器化应用程序的细粒度控制。请记住,与 ECS 相比,每个集群需要支付额外费用,因为 AWS 收取控制平面成本。
当然,多年来 EKS 也变得非常简单,最近他们推出了 EKS Auto,它可以自动化集群基础设施。但如果您进入 EKS,那么您需要了解部署、监控、扩展、网络、安全性。
所以我的建议是首先使用 ECS,但请记住供应商锁定点,然后如果您想要更多的定制和控制,请选择 EKS 或 Kubernetes
如何通过 CDK 以最少的代码更改来完成此操作。
这是非常主观的,但一个好的起点是这里(来自aws文档)
还建议它将采取的差异,
也请检查此示例:https://conermurphy.com/blog/aws-lambda-to-ecs-fargate-migration-guide