我正在尝试使用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(胖罐)工件,但没有任何变化。
感谢您的帮助。
答案 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