CDK部署Lambda遇ECR镜像不存在问题求助
问题描述
我用CDK编写的代码能正常构建Docker镜像并推送到ECR,但首次部署Lambda时会失败,报错提示镜像不存在。第二次执行cdk deploy则一切正常,可修改Docker镜像触发重新构建推送后,问题会再次出现。
错误信息
AppStack | 8:39:53 PM | CREATE_FAILED | AWS::Lambda::Function | xxx_lambda (xxxlambda9C8872F5) Resource handler returned message: "Source image xxxxxxxxxxxxx.dkr.ecr.eu-west-1.amazonaws.com/xxx-uber-docker-img-repo:5e0b247c90c24e68403f249749b74ca94828ccf405300d7984438fd10f1ea7ca does not exist. Provide a valid source image. (Service: Lambda, Status Code: 400, Request ID: xxxxxxxxxx)" (RequestToken: xxxxxxxxx, HandlerErrorCode: InvalidRequest)
我的CDK代码
import * as cdk from 'aws-cdk-lib'; import { aws_s3 as s3, aws_lambda as lambda, aws_apigateway as apigateway, aws_ecr_assets as ecr_assets, aws_ecr as ecr, aws_ec2 as ec2, aws_efs as efs, aws_iam as iam, aws_elasticbeanstalk as ebs, aws_codecommit as cc, aws_codebuild as cb, aws_codestarconnections as csc, aws_codepipeline as cpl, aws_codepipeline_actions as cpla, aws_s3_assets as s3assets, aws_dynamodb as db } from 'aws-cdk-lib'; import * as ecrdeploy from 'cdk-ecr-deployment'; function docker_img_asset(scope: Construct, id: string, props: ecr_assets.DockerImageAssetProps):ecr_assets.DockerImageAsset{ const img_dir = 'docker_images/' + id + '/'; const p:ecr_assets.DockerImageAssetProps = { ...props, exclude:excludes_for(id).concat((props.exclude??[]).map(x=>img_dir+x)), file: img_dir + (props.file ?? 'Dockerfile'), }; return new ecr_assets.DockerImageAsset(scope, id+'_img', p); } const xxx_uber_ecr_repo = new ecr.Repository(this, 'xxx-uber-docker-img-repo', { repositoryName: 'xxx-uber-docker-img-repo', removalPolicy: cdk.RemovalPolicy.DESTROY, lifecycleRules: [{ description: "Keeps a maximum number of images to minimize storage", maxImageCount: 1 }], }); const xxx_ecr_img = docker_img_asset(this, 'xxx', { directory: ROOT_DIR, exclude:[], invalidation: { buildArgs: false, buildSecrets: false }, }); const xxx_uber_ecr_deployment = new ecrdeploy.ECRDeployment(this, 'xxxUberEcrDeployment', { src: new ecrdeploy.DockerImageName(xxx_ecr_img.imageUri), dest: new ecrdeploy.DockerImageName(`${xxx_uber_ecr_repo.repositoryUri}:${xxx_ecr_img.assetHash}`), }); const xxx_lambda = new lambda.DockerImageFunction(this, "xxx_lambda", { code: lambda.DockerImageCode.fromEcr(xxx_uber_ecr_repo, { tagOrDigest: xxx_ecr_img.imageTag }), environment: { // 'BUCKET': packaged_blender_files.bucketName }, memorySize: 2048, // ephemeralStorageSize: cdk.Size.mebibytes(10240), timeout: cdk.Duration.minutes(15) });
问题原因
核心问题是资源依赖顺序缺失:CDK默认会根据资源引用自动推断依赖关系,但这里Lambda仅关联了ECR仓库和镜像标签,CDK无法识别它需要等待xxx_uber_ecr_deployment完成镜像推送后再创建。首次部署时,Lambda与ECRDeployment并行启动,此时目标ECR仓库中还没有推送完成的镜像,因此报错;第二次部署时镜像已存在,所以能成功;修改镜像后新镜像未完成推送,问题再次出现。
解决方案
给Lambda添加显式依赖,确保它在ECR镜像推送完成后再创建。同时统一镜像标签的引用,避免不一致:
// ... 保留原有代码不变 ... const xxx_uber_ecr_deployment = new ecrdeploy.ECRDeployment(this, 'xxxUberEcrDeployment', { src: new ecrdeploy.DockerImageName(xxx_ecr_img.imageUri), dest: new ecrdeploy.DockerImageName(`${xxx_uber_ecr_repo.repositoryUri}:${xxx_ecr_img.assetHash}`), }); const xxx_lambda = new lambda.DockerImageFunction(this, "xxx_lambda", { code: lambda.DockerImageCode.fromEcr(xxx_uber_ecr_repo, { tagOrDigest: xxx_ecr_img.assetHash // 与推送时的标签保持一致 }), environment: { // 'BUCKET': packaged_blender_files.bucketName }, memorySize: 2048, timeout: cdk.Duration.minutes(15) }); // 添加显式依赖,强制Lambda等待镜像推送完成 xxx_lambda.node.addDependency(xxx_uber_ecr_deployment);
这样修改后,CDK会严格按照「构建镜像 → 推送到ECR → 创建Lambda」的顺序执行部署,彻底解决首次部署失败的问题。
内容的提问来源于stack exchange,提问作者alagris

