1
votes

I built a simple CodePipeline for a SpringBoot Java application with 3 steps:

  • Source: get the source from GitHub
  • Build: a jar file
  • Deploy: to an AWS Elastic Beanstalk instance

1 and 2 steps successfully pass while Deploy step fails. The only error I see in Elastic Beanstalk logs:

01_configure_application.sh] : Activity execution failed, because: Executing: /usr/bin/unzip -o -d /var/app/staging /opt/elasticbeanstalk/deploy/appsource/source_bundle
  FileMagic v0.7.1: compiled magic version [5.21] does not match with shared library magic version [5.37]
  Archive:  /opt/elasticbeanstalk/deploy/appsource/source_bundle
    inflating: /var/app/staging/microservices/my-service/target/my-service.jar  
  Unable to launch application as the source bundle does not contain either a file named application.jar or a Procfile.
  Unable to launch application as the source bundle does not contain either a file named application.jar or a Procfile. (ElasticBeanstalk::ExternalInvocationError)
caused by: Executing: /usr/bin/unzip -o -d /var/app/staging /opt/elasticbeanstalk/deploy/appsource/source_bundle
  FileMagic v0.7.1: compiled magic version [5.21] does not match with shared library magic version [5.37]
  Archive:  /opt/elasticbeanstalk/deploy/appsource/source_bundle
    inflating: /var/app/staging/microservices/my-service/target/my-service.jar  
  Unable to launch application as the source bundle does not contain either a file named application.jar or a Procfile.
  Unable to launch application as the source bundle does not contain either a file named application.jar or a Procfile. (Executor::NonZeroExitStatus)

My Buildspec:

build:
  commands:
      - mvn -P ci --settings settings.xml install -DskipTests
artifacts:
  files:
     - microservices/my-service/target/my-service.jar

If I deploy this jar directly to AWS Elastic Beanstalk using AWS Web Interface, it works perfectly.

Please, help me. I'm ready to share any other config on demand.

2

2 Answers

5
votes

while Denys answer is correct i dont think it clearly explains the issue.

the artifact must be top level or at most one directory in depth when it is output under the artifacts directive.

for example the default for a spring project using gradle is to output to <project root>/build/libs/<artifact name>.jar after executing the bootJar task

intuitively you would define something like this:

version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto8
  build:
    commands:
      # bootJar task outputs to build/libs/<name>.jar
      - ./gradlew bootJar
artifacts:
  files:
      - build/libs/<name>.jar

this build will succeed and upload a zipped artifact to S3. when that is unzipped you will get:

build/libs/<name>.jar. you can confirm this by downloading the artifact from s3 and unzipping it yourself (just as elastic beanstalk does within the vm).

so when elastic beanstalk tries to deploy this it fails because it looks either for a top level <name>.jar or at most somedir/<name>.jar and you get that rather cryptic error message

Unable to launch application as the source bundle does not contain either a file named application.jar or a Procfile.

its cryptic because it implies that the artifact must either be named application.jar or a Procfile must be added. neither of these are true

so the solution revolves around making that jar file top level. you can:

define your output artifact from your build tool as placing it top level (not ideal)

add a second command to the build phase that moves that jar file out to the top level such as:

version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto8
  build:
    commands:
      # bootJar task outputs to build/libs/<name>.jar
      - ./gradlew bootJar
      # move the jar (by wildcard, agnostic to its name) to top level app.jar
      - mv build/libs/*.jar app.jar
artifacts:
  files:
      # publish the now top level app.jar as the artifact
      - app.jar

the most appropriate solution is to make use of the post_build directive which is designed for cleanup / reorganizing steps like this:

version: 0.2

phases:
  install:
    runtime-versions:
      java: corretto8
  build:
    commands:
      # bootJar task outputs to build/libs/<name>.jar
      - ./gradlew bootJar
  post_build:
    commands:
      # move the jar (by wildcard, agnostic to its name) to top level app.jar
      - mv build/libs/*.jar app.jar
artifacts:
  files:
      # publish the now top level app.jar as the artifact
      - app.jar

as a result when unzipped you will get app.jar top level and elastic beanstalk is happy! note that app.jar and build/libs are arbitrary, set them however makes sense to you and your project. all that matters is that the artifacts.files is a top level jar file. elastic beanstalk will take care of the rest

if you are new to CP or have a simple project there is no need to override with a config.yml or add a Procfile as suggested in other similar questions.

hope this helps someone else.

0
votes

The problem was in artifact's sub-folders, it's impossible to use an artifact location as in my Buildspec:

artifacts:
  files:
     - microservices/my-service/target/my-service.jar

the only correct way is folder/myapp.jar, for example:

artifacts:
  files:
     - target/my-service.jar

so you should specify outputDirectory in your maven config if it is different