cloudfoundry / java-buildpack

Cloud Foundry buildpack for running Java applications
Apache License 2.0
439 stars 2.58k forks source link

Spring Boot Ratpack Application Support #256

Closed bobatronx closed 9 years ago

bobatronx commented 9 years ago

I created a Spring Boot application with an embedded ratpack server, and cf push is showing the following error:

[Buildpack] ERROR Compile failed with exception #<RuntimeError: Application can be 
run by more than one container: Ratpack, Spring Boot>
Application can be run by more than one container: Ratpack, Spring Boot

Which makes sense because I am using both. However, this is a common use case. Is there anyway to tweak the container detection to force the container to be used or if I fork the repository is there an easy way to specify precedence? Would this actually require a new container type?

It is meant to be run as a standard spring boot application with the embedded ratpack server.

bobatronx commented 9 years ago

I got around this by changing the supports method in the ratpack container code:

def supports?
  start_script(root) && start_script(root).exist? && !@spring_boot_utils.is?(@application) && @ratpack_utils.is?(@application)
end

I'm not sure if this is the best way to handle this though.

nebhale commented 9 years ago

@bobatronx It seems like your application contains a ratpack-style start script. Is that correct?

bobatronx commented 9 years ago

I'm new to all this, so I'm not sure I get the question 100%. I just have a normal Spring Boot application that uses @EnableRatpack to embed the ratpack server. I build the application with Gradle, so Gradle will generate the distributions directory with a zip and a tar file. I point the path in the Cloud Foundry manifest at that zip file. Gradle creates a bin folder in that zip with the shell and bat files generated for me that run the application. Hope that helps.

nebhale commented 9 years ago

Right so that creation of a dist and zip file is what I'm getting at. I'd have expected a Spring Boot application to be an executable JAR. What instructions are you following to get this artifact? Just so I can reproduce the build.

bobatronx commented 9 years ago

It should just be an executable jar. I'm not really following any set of instructions, it's just something I was trying out as an example of putting together a Spring Boot / Ratpack application. Here's a link to my project if you want to clone and build it:

https://github.com/bobatronx/user-cloud

nebhale commented 9 years ago

Based on the instructions found here, I've created a sample application (skeleton generated at https://start.spring.io). I ran the following:

$ ./gradlew build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:findMainClass
:jar
:bootRepackage
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

Total time: 3.098 secs
$ cf push
Using manifest file .../ratpack-spring-boot-demo/manifest.yml

Using stack cflinuxfs2...
OK
Creating app ratpack-spring-boot-demo in org bhale / space development as bhale@pivotal.io...
OK

Creating route ben-ratpack-spring-boot-demo.cfapps.io...
OK

Binding ben-ratpack-spring-boot-demo.cfapps.io to ratpack-spring-boot-demo...
OK

Uploading ratpack-spring-boot-demo...
Uploading app files from: .../ratpack-spring-boot-demo/build/libs/ratpack-spring-boot-demo-0.0.1-SNAPSHOT.jar
Uploading 409.9K, 85 files
Done uploading               
OK

Starting app ratpack-spring-boot-demo in org bhale / space development as bhale@pivotal.io...
Creating container
Successfully created container
Downloading app package...
Downloaded app package (12.6M)
Downloading buildpacks (https://github.com/cloudfoundry/java-buildpack.git)...
Downloaded buildpacks
Staging...
-----> Java Buildpack Version: e3eb196 | https://github.com/cloudfoundry/java-buildpack.git#e3eb196
-----> Downloading Open Jdk JRE 1.8.0_65 from https://download.run.pivotal.io/openjdk/trusty/x86_64/openjdk-1.8.0_65.tar.gz (1.2s)
       Expanding Open Jdk JRE to .java-buildpack/open_jdk_jre (1.0s)
-----> Downloading Open JDK Like Memory Calculator 2.0.1_RELEASE from https://download.run.pivotal.io/memory-calculator/trusty/x86_64/memory-calculator-2.0.1_RELEASE.tar.gz (0.1s)
       Memory Settings: -Xss995K -Xmx382293K -Xms382293K -XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M
-----> Downloading Spring Auto Reconfiguration 1.10.0_RELEASE from https://download.run.pivotal.io/auto-reconfiguration/auto-reconfiguration-1.10.0_RELEASE.jar (0.1s)
Exit status 0
Staging complete
Uploading droplet, build artifacts cache...
Uploading droplet...
Uploading build artifacts cache...
Uploaded build artifacts cache (44.7M)
Uploaded droplet (57.6M)
Uploading complete

0 of 1 instances running, 1 starting
1 of 1 instances running

App started

OK

App ratpack-spring-boot-demo was started using this command `CALCULATED_MEMORY=$($PWD/.java-buildpack/open_jdk_jre/bin/java-buildpack-memory-calculator-2.0.1_RELEASE -memorySizes=metaspace:64m.. -memoryWeights=heap:75,metaspace:10,native:10,stack:5 -memoryInitials=heap:100%,metaspace:100% -totMemory=$MEMORY_LIMIT) && JAVA_OPTS="-Djava.io.tmpdir=$TMPDIR -XX:OnOutOfMemoryError=$PWD/.java-buildpack/open_jdk_jre/bin/killjava.sh $CALCULATED_MEMORY" && SERVER_PORT=$PORT $PWD/.java-buildpack/open_jdk_jre/bin/java $JAVA_OPTS -cp $PWD/.:$PWD/.java-buildpack/spring_auto_reconfiguration/spring_auto_reconfiguration-1.10.0_RELEASE.jar org.springframework.boot.loader.JarLauncher`

Showing health and status for app ratpack-spring-boot-demo in org bhale / space development as bhale@pivotal.io...
OK

requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: ben-ratpack-spring-boot-demo.cfapps.io
last uploaded: Fri Nov 20 20:43:20 UTC 2015
stack: cflinuxfs2
buildpack: https://github.com/cloudfoundry/java-buildpack.git

     state     since                    cpu    memory           disk           details   
#0   running   2015-11-20 12:43:59 PM   0.0%   251.1M of 512M   163.8M of 1G      

Seems to work as expected. Why don't you give a try to refactoring to match the documentation and see if that solves things.

bobatronx commented 9 years ago

Appreciate you looking into this. Based on what I've seen of the application you created, I'm not really sure what's fundamentally different between the two. Let me do a little experimenting and see what I can find. Thanks!

nebhale commented 9 years ago

If I had to guess it's the use of the io.ratpack.ratpack-java plugin instead of the spring-boot plugin. I believe that the Ratpack plugin creates a "DistZip" style artifact where as the Spring Boot plugin creates an executable JAR style artifact.

bobatronx commented 9 years ago

Just a follow up for anyone that might come across this. I was doing two things wrong. First, I needed to point the path of the manifest.yml to the actual executable jar file.

e.g. Instead of [gradle_build_dir]/distributions/[app].zip -> [gradle_build_dir]/libs/[app].jar

Also, I needed to add the Spring Boot plugin

apply plugin: "spring-boot"

Also, I was able to keep the ratpack-java plugin:

apply plugin: "io.ratpack.ratpack-java"

which is nice because it allows for syntax like the following:

compile ratpack.dependency('spring-boot')
compile ratpack.dependency('rx')
compile ratpack.dependency('groovy')
compile ratpack.dependency('hystrix')

Thanks for all your help @nebhale. I'm pretty sure this is solved now. I pushed my latest to GitHub. If you have the time to clone and confirm that it's working correctly, that would be great. Otherwise, consider the issue closed.

Thanks again!