【问题标题】:AWS CDK CI/CD Pipeline - Deployed Lambda returns ClassNotFoundExceptionAWS CDK CI/CD 管道 - 部署的 Lambda 返回 ClassNotFoundException
【发布时间】:2020-07-23 21:39:44
【问题描述】:

我正在尝试使用 AWS CDK 的 Lambda 构建 CI/CD 管道。我们在这里使用一个 gradle 项目。此外,我遵循了示例documentation。我们定义了两个堆栈,分别是 APIStack 和 ApiStackPipeline,其中 APIStack 由 Lambda_Build 处理,ApiStackPipeline 由 CDK_BUILD 处理。

我们正在像 ApiStack 中初始化 Lambda 函数;

final Function contactFunction = Function.Builder.create(this, "contactFunction").role(roleLambda)
    .runtime(Runtime.JAVA_8)
    .code(lambdaCode)
    .handler("com.buraktas.contact.main.ContactLambda::handleRequest")
    .memorySize(512)
    .timeout(Duration.minutes(1))
    .environment(environment)
    .description(Instant.now().toString()).build();

在这种情况下,我们将lambdaCode 参数设置为this.lambdaCode = new CfnParametersCode();,与文档中显示的相同(尽管我不确定它是如何得到的)。

现在我们将这个 lambdaCode 传递给 ApiStackPipeline,看起来像这样;

IRepository repository = Repository.fromRepositoryName(this, repoName, repoName);
IBucket bucket = Bucket.fromBucketName(this, "codepipeline-api", "codepipeline-api");

PipelineProject lambdaBuild = PipelineProject.Builder.create(this, "ApiBuild")
    .buildSpec(BuildSpec.fromSourceFilename("lambda-buildspec.yml"))
    .environment(BuildEnvironment.builder().buildImage(LinuxBuildImage.STANDARD_4_0).build())
    .build();

PipelineProject cdkBuild = PipelineProject.Builder.create(this, "ApiCDKBuild")
    .buildSpec(BuildSpec.fromSourceFilename("cdk-buildspec.yml"))
    .environment(BuildEnvironment.builder().buildImage(LinuxBuildImage.STANDARD_4_0).build())
    .build();

Artifact sourceOutput = new Artifact();
Artifact cdkBuildOutput = new Artifact("CdkBuildOutput");
Artifact lambdaBuildOutput = new Artifact("LambdaBuildOutput");

Pipeline.Builder.create(this, "ApiPipeline")
    .stages(Arrays.asList(
        StageProps.builder()
            .stageName("Source")
            .actions(Arrays.asList(
                CodeCommitSourceAction.Builder.create()
                    .actionName("Source")
                    .repository(repository)
                    .output(sourceOutput)
                    .build()))
            .build(),
        StageProps.builder()
            .stageName("Build")
            .actions(Arrays.asList(
                CodeBuildAction.Builder.create()
                    .actionName("Lambda_Build")
                    .project(lambdaBuild)
                    .input(sourceOutput)
                    .outputs(Arrays.asList(lambdaBuildOutput)).build(),
                CodeBuildAction.Builder.create()
                    .actionName("CDK_Build")
                    .project(cdkBuild)
                    .input(sourceOutput)
                    .outputs(Arrays.asList(cdkBuildOutput))
                    .build()))
            .build(),
        StageProps.builder()
            .stageName("Deploy")
            .actions(Arrays.asList(
                CloudFormationCreateUpdateStackAction.Builder.create()
                    .actionName("Lambda_CFN_Deploy")
                    .templatePath(cdkBuildOutput.atPath("ApiStackAlfa.template.json"))
                    .adminPermissions(true)
                    .parameterOverrides(lambdaCode.assign(lambdaBuildOutput.getS3Location()))
                    .extraInputs(Arrays.asList(lambdaBuildOutput))
                    .stackName("ApiStackAlfaDeployment")
                    .build()))
            .build()))
    .artifactBucket(bucket)
    .restartExecutionOnUpdate(true)
    .build();

这里我也分享了 *-buildspec.yml 文件;

lambda-buildspec.yml

version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto8
  build:
    commands:
      - echo current directory `pwd`
      - echo building gradle project on `date`
      - ./gradlew clean build
artifacts:
  files:
    - build/distributions/src.zip
  discard-paths: yes

cdk-buildspec.yml

version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 10
      java: corretto8
    commands:
      - echo installing aws-cdk on `date`
      - npm install aws-cdk
  build:
    commands:
      - echo current directory `pwd`
      - ls -l
      - echo building cdk project on `date`
      - ./gradlew clean build
      - npx cdk synth -o dist
  post_build:
    commands:
      - echo listing files after build under dist
      - ls -l dist
artifacts:
  files:
    - ApiStackAlfa.template.json
  base-directory: dist

这是我得到的异常堆栈跟踪

Class not found: com.buraktas.api.main.Lambda: java.lang.ClassNotFoundException
java.lang.ClassNotFoundException: com.buraktas.api.main.Lambda
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)

最后在这里我分享了一个项目结构的简化版本,如果有帮助的话

├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── buraktas
│   │   │           └── api
│   │   │               ├── main
│   │   │               │   ├── ApiMain.java
│   │   │               │   ├── ApiPipelineStack.java
│   │   │               │   ├── ApiStack.java
│   │   │               │   └── Lambda.java
│   │   │               └── repository
│   │   │                   └── Repository.java
│   │   └── resources
│   │       └── log4j.properties
│   └── test
│       ├── java
│       │   ├── DocumentTest.java
│       │   └── JsonWriterSettingsTest.java
│       └── resources
│           └── request.http

看起来一切正常,管道已成功创建,并且 Source -> Build -> Deploy 步骤运行顺利。但是,当我触发我的 lambda 函数时,我得到了 ClassNotFoundException。我尝试使用 .zip 或 .jar(胖 jar)工件,但没有任何改变。

感谢您的帮助。

【问题讨论】:

  • 找不到什么类?您能否列出您看到的确切异常消息?
  • 嗨@Shawn 我从我的 CloudWatch 日志中为我的 lambda 堆栈共享了 ClassNotFoundException,此外还有一个简化版本我在 src 目录下的项目结构。如果您需要其他任何东西,请告诉我。谢谢!

标签: amazon-web-services aws-code-deploy aws-codepipeline aws-cdk


【解决方案1】:

我发现问题正在发生,因为 CodeBuild 从给定的工件创建了一个 zip。这意味着将有一个包含 src.zip 本身的 zip 文件,其中包含正确的项目构建文件。由于这个主 zip 文件正在上传到 Lambda,它无法找到处理程序定义,因此它会抛出 ClassNotFoundException。但是,示例文档和构建规范的 AWS CodeBuild 参考文档中均未提及此额外的 zip 过程。我们需要手动解压缩 zip 文件的内容并将其作为工件输出。这是我们的 buildspec.yml 的最终版本。此外,如果您不想处理解压缩内容,则需要配置构建工具(我们在这里使用 gradle)在运行构建命令后不将内容压缩到 zip 文件中。

version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto8
  build:
    commands:
      - echo current directory `pwd`
      - echo building gradle project on `date`
      - ./gradlew clean build
  post_build:
    commands:
      - mkdir build/distributions/api
      - unzip build/distributions/api.zip -d build/distributions/api
artifacts:
  files:
    - '**/*'
  base-directory: build/distributions/api

【讨论】:

    猜你喜欢
    • 2019-12-12
    • 2020-04-11
    • 2023-02-16
    • 2020-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    相关资源
    最近更新 更多