AWS CDK CI / CD管道-部署的Lambda返回ClassNotFoundException

时间:2020-07-22 13:57:14

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

我正在尝试使用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

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

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

我发现问题正在发生,因为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