当前位置: 首页 > 知识库问答 >
问题:

AWS CDK CI/CD Pipeline-部署Lambda返回ClassNotFoundExcure

武博艺
2023-03-14

我试图通过AWS CDK与Lambda建立一个CI/CD管道。我们在这里使用gradle项目。此外,我遵循了示例留档。我们定义了两个堆栈,它们是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构建规范。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

看起来一切正常,管道正在成功创建,源代码-

谢谢你的帮助。

共有1个答案

田镜
2023-03-14

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

 类似资料:
  • 问题内容: 我正在尝试执行新的JDK 8函数式编程领域中似乎是相对基本的事情,但是我无法使其工作。我有这个工作代码: 它接受一个数字列表,并产生可以打印出来的功能列表。但是,显式强制转换为Callable似乎是多余的。在我和IntelliJ中看来。我们都同意这也应该起作用: 但是我得到一个错误: 问题答案: 您遇到了Java 8目标类型的限制,该限制适用于方法调用的 接收者 。尽管目标类型在大多数

  • 我正试图做一件在新JDK似乎是相对基本的事情 它获取一个数字列表并生成一个可以将它们打印出来的函数列表。然而,Callable的显式强制执行似乎是多余的。对我和IntelliJ来说似乎是这样。我们都同意这也应该有效: 但是,我收到一个错误:

  • 我正在编写一个lambda表达式来将给定的纬度和经度转换为地址。表达式应该以坐标为参数,并返回其相应的地址。但是,返回的值为null。以下是我的班级: 以下是logcat的输出: 以下是我的用法: 是类的对象,以下是相关接口: 当我尝试从相关适配器打印坐标时,它们会正确打印。因此,位置正在正确设置,但是当我试图从另一个类访问它时,它会显示字符串的空值。你能建议一个替代方法来从表达式中提取位置吗?

  • 我试图将一些for-each循环更改为lambda-方法,以发现lambda表达式的可能性。以下似乎是可能的: 使用lambda 但下一个就不起作用了: 带lambda 是最后一行的语法有问题还是无法从方法返回?

  • 我有一个Quarkus项目,它公开了一些RESTendpoint。当在开发模式下工作或从本地构建docker容器中运行时,所有工作都很好,那些用@rolesalloved和@permitall注释的endpoint都正常工作。但是当我按照以下步骤部署到AWS服务时: 提交到Gitlab 运行Gitlab cicd 将结果与配置一起发送到AWS S3 bucket 触发AWS CodePipelin

  • 下面尝试包装lambda的(简化的)代码给了我一些Clang版本的警告,但不是所有版本,也不是gcc版本。 这是一个窃听器,还是我遗漏了什么?我在godbolt和版本中收到了的警告,这是一个更大的回购的一部分,但我还无法隔离该版本的故障。 这个相关问题中的例子没有给出警告。 改进(我认为)版本: 这将使Godbolt中的的警告沉默。我想它应该能安全地适用于任何一个functor,任何我遗漏的东西?