问题
I've been trying to deploy a scala application built into a fat-jar with sbt assembly.
There is well known issue with containers and scala compilation generated class names: https://github.com/milessabin/shapeless/wiki/Shapeless-with-SBT-Assembly-inside-Docker, essentially they don't support file names larger than ~242 chars and will fail miserably to start scala application if they do contain those. Problem is several libraries (scalaz, play) contain those.
scalacOptions in assembly ++= Seq("-Xmax-classfile-name", "73")
Also tried replacing the command used to start and right now I'm looking into using alternative buildpacks, but none of these seem to be able to fix the issue, given that I don't even get to the start command.
My current results are:
➜ sample-generator git:(master) ✗ cf push sample-gen -p ./target/sample-generator-assembly-201608111441.jar -b java_buildpack --health-check-type=none -c "sleep(100)"
Creating app sample-gen in org pcfdev-org / space pcfdev-space as user...
OK
Using route sample-gen.local.pcfdev.io
Binding sample-gen.local.pcfdev.io to sample-gen...
OK
Uploading sample-gen...
Uploading app files from: /tmp/unzipped-app826671513
Uploading 120.3M, 38143 files
Done uploading
OK
Starting app sample-gen in org pcfdev-org / space pcfdev-space as user...
Downloading java_buildpack...
Downloaded java_buildpack
Creating container
Successfully created container
Downloading app package...
FAILED
Error restarting application: StagingError
TIP: use 'cf logs sample-gen --recent' for more information
As cf logs doesn't really return me anything, I have to log into PCFDev and get logs by tailing /var/vcap/data/sys/log/garden/garden.stdout.log:
{"timestamp":"1470918381.941401958","source":"garden-linux","message":"garden-linux.garden-server.stream-in.failed","log_level":2,"data":{"destination":"/tmp/app","error":"error streaming in: exit status 2. Output: tar: play/core/routing/GeneratedRouter$$anonfun$call$56$$anonfun$apply$178$$anonfun$$$$$85f6e7f12408688f578bcac985aee12$$$$$186$$anonfun$apply$187$$anonfun$apply$188$$anonfun$apply$189$$anonfun$apply$190$$anonfun$apply$191$$anonfun$apply$192$$anonfun$apply$193.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$59$$anonfun$apply$197$$anonfun$apply$198$$anonfun$apply$199$$anonfun$apply$200$$anonfun$apply$201$$anonfun$apply$202$$anonfun$apply$203$$anonfun$apply$204$$anonfun$apply$205$$anonfun$apply$206$$anonfun$apply$207.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$47$$anonfun$apply$127$$anonfun$apply$128$$anonfun$apply$129$$anonfun$apply$130$$anonfun$apply$131$$anonfun$apply$132$$anonfun$apply$133$$anonfun$apply$134$$anonfun$apply$135$$anonfun$apply$136$$anonfun$apply$137.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$44$$anonfun$apply$112$$anonfun$apply$113$$anonfun$apply$114$$anonfun$apply$115$$anonfun$apply$116$$anonfun$apply$117$$anonfun$apply$118$$anonfun$apply$119$$anonfun$apply$120$$anonfun$apply$121$$anonfun$apply$122.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$56$$anonfun$apply$178$$anonfun$apply$179$$anonfun$apply$180$$anonfun$apply$181$$anonfun$apply$182$$anonfun$apply$183$$anonfun$apply$184$$anonfun$apply$185$$anonfun$apply$186$$anonfun$apply$187$$anonfun$apply$188.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$59$$anonfun$apply$197$$anonfun$$$$$4d23ff5fc3821e643c952318248bfc6$$$$$205$$anonfun$apply$206$$anonfun$apply$207$$anonfun$apply$208$$anonfun$apply$209$$anonfun$apply$210$$anonfun$apply$211$$anonfun$apply$212.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$53$$anonfun$apply$160$$anonfun$apply$161$$anonfun$apply$162$$anonfun$apply$163$$anonfun$apply$164$$anonfun$apply$165$$anonfun$apply$166$$anonfun$apply$167$$anonfun$apply$168$$anonfun$apply$169$$anonfun$apply$170.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$41$$anonfun$apply$98$$anonfun$apply$99$$anonfun$apply$100$$anonfun$apply$101$$anonfun$apply$102$$anonfun$apply$103$$anonfun$apply$104$$anonfun$apply$105$$anonfun$apply$106$$anonfun$apply$107$$anonfun$apply$108.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$47$$anonfun$apply$127$$anonfun$$$$$a8626ce150a144689738daf9754d5e7$$$$$135$$anonfun$apply$136$$anonfun$apply$137$$anonfun$apply$138$$anonfun$apply$139$$anonfun$apply$140$$anonfun$apply$141$$anonfun$apply$142.class: Cannot open: File name too long\ntar: play/core/routing/GeneratedRouter$$anonfun$call$50$$anonfun$apply$143$$anonfun$apply$144$$anonfun$apply$145$$anonfun$apply$146$$anonfun$apply$147$$anonfun$apply$148$$anonfun$apply$149$$anonfun$apply$150$$anonfun$apply$151$$anonfun$apply$152$$anonfun$apply$153.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$70.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$tupled$11.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$67.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$66.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$73.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$68.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$76.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$71.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$74.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$75.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$72.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$77.class: Cannot open: File name too long\ntar: scalaz/syntax/ApplicativeBuilder$ApplicativeBuilder3$ApplicativeBuilder4$ApplicativeBuilder5$ApplicativeBuilder6$ApplicativeBuilder7$ApplicativeBuilder8$ApplicativeBuilder9$ApplicativeBuilder10$ApplicativeBuilder11$ApplicativeBuilder12$$anonfun$apply$69.class: Cannot open: File name too long\ntar: Exiting with failure status due to previous errors\n","handle":"a1ef2606-ead0-4cb1-b0fd-d464d64b8bc6-ff54adf06a8342f59eedfb022a9e9527","session":"11.7615","user":"vcap"}}
回答1:
For Java/Scala users still fighting or struggling with long nested filenames breaking during the app staging, there is a simpler solution, requiring no custom buildpacks.
Use Java classpath manifest to specify the additional classes bundled within other jars and then push the main app, instead of having everything packaged as one big jar file. Final structure should be One top level Jar file containing multiple internal jars all referred by main classpath manifest entry.
1) Create the app bits with the 3rd party libraries or dependencies as separate jars in some additional folder (like lib/..)
Sample structure:
com.mycompany.foo.class
com.mycompany.bar.class
com.mycompany.xyz.class
lib/myDepedencyA.jar
lib/myDepedencyB.jar
lib/myDepedencyC.jar
.....
lib/myDepedencyZ.jar
2) Create a classpath manifest entry that refers to these additional jars inside a custom manifest (lets say mymanifest) .
Manifest-Version: 1.0
Implementation-Vendor: test
Implementation-Title: Test
Implementation-Version: 1.0
Implementation-Vendor-Id: test
Specification-Vendor: test
Specification-Title: TestApp
Specification-Version: 1.0
Main-Class: TestService
Class-Path: lib/akka-actor_2.10-2.1.4.jar
lib/casbah-commons_2.10-2.7.1.jar
lib/casbah-core_2.10-2.7.1.jar
lib/casbah-gridfs_2.10-2.7.0.jar
lib/casbah-query_2.10-2.7.1.jar
lib/config-1.0.0.jar
lib/joda-convert-1.2.jar
lib/joda-time-2.3.jar
lib/json4s-ast_2.10-3.2.9.jar
lib/json4s-core_2.10-3.2.9.jar
lib/myDepedencyA.jar
lib/myDepedencyB.jar
lib/myDepedencyC.jar
.....
lib/myDepedencyZ.jar
3) Create the final jar while specifying the manifest file explicitly.
jar cvfm MyApp.jar mymanifest -C foo/ .
Explanation: Use the manifest and go to directory foo before including classes within it. Also, refer to https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html The jar would then have the appln classes and the 3rd party libs all bundled but without every one of those problematic long class names. Before pushing, check the manifest content to make sure.
4) When the app push happens, only the top level app classes would be opened up without exploding the 3rd party jars also from the lib folder. The java buildpack would automatically add the jars specified in the classpath manifest into the server classpath at runtime.
start_command: $PWD/.java-buildpack/open_jdk_jre/bin/java -cp $PWD/.:$PWD/lib/akka-actor_2.10-2.1.4.jar:$PWD/lib/casbah-commons_2.10-2.7.1.jar:$PWD/lib/casbah-core_2.10-2.7.1.jar:$PWD/lib/casbah-gridfs_2.10-2.7.0.jar:$PWD/lib/casbah-query_2.10-2.7.1.jar:$PWD/lib/config-1.0.0.jar:$PWD/lib/joda-convert-1.2.jar:$PWD/lib/joda-time-2.3.jar:$PWD/lib/json4s-ast_2.10-3.2.9.jar:$PWD/lib/json4s-core_2.10-3.2.9.jar:$PWD/lib/json4s-native_2.10-3.2.9.jar:$PWD/lib/mimepull-1.9.4.jar:$PWD/lib/mongo-java-driver-2.12.1.jar:$PWD/lib/nscala-time_2.10-1.0.0.jar:$PWD/lib/paranamer-2.6.jar:$PWD/lib/parboiled-core-1.1.6.jar:$PWD/lib/parboiled-scala_2.10-1.1.6.jar:$PWD/lib/salat-core_2.10-1.9.8.jar:$PWD/lib/salat-util_2.10-1.9.8.jar:$PWD/lib/sbinary_2.10-0.4.2.jar:$PWD/lib/sbt-0.13.1.jar:$PWD/lib/sbt-assembly-0.11.2.jar:$PWD/lib/sbt-idea-1.6.0.jar:$PWD/lib/scala-compiler-2.10.4.jar:$PWD/lib/scala-library-2.10.4.jar:$PWD/lib/scala-reflect-2.10.4.jar:$PWD/lib/scalap-2.10.4.jar:$PWD/lib/shapeless_2.10-1.2.4.jar:$PWD/lib/slf4j-api-1.7.2.jar:$PWD/lib/spray-can-1.1.1.jar:$PWD/lib/spray-http-1.1.1.jar:$PWD/lib/spray-httpx-1.1.1.jar:$PWD/lib/spray-io-1.1.1.jar:$PWD/lib/spray-json_2.10-1.2.5.jar:$PWD/lib/spray-routing-1.1.1.jar:$PWD/lib/spray-util-1.1.1.jar:$PWD/lib/task-system-0.13.1.jar:$PWD/lib/tasks-0.13.1.jar:$PWD/lib/test-agent-0.13.1.jar:$PWD/lib/test-interface-1.0.jar:$PWD/lib/testing-0.13.1.jar:$PWD/lib/tracking-0.13.1.jar -Djava.io.tmpdir=$TMPDIR -XX:OnOutOfMemoryError=$PWD/.java-buildpack/open_jdk_jre/bin/killjava.sh -Xmx1536M -Xms1536M -XX:MaxPermSize=209715K -XX:PermSize=209715K -Xss1M TestService
回答2:
Just in case this might still help anyone, we've managed to use a solution with sbt-native-packager instead of sbt-assembly.
Using sbt-native-packager and the universal:packageBin command a zip can be produced, containing the same contents produced by sbt stage. The jars are kept separate (not-exploded) and avoid the compilation problem generated by the size of files caused by sbt-assembly. After that the java_buildpack is capable of running the app without issues:
cf push sample-app -p ./target/universal/stage -b java_buildpack --health-check-type=none
or
cf push sample-app -p ./target/universal/sample-app-201608160251.zip -b java_buildpack --health-check-type=none
来源:https://stackoverflow.com/questions/38899894/how-to-deploy-a-scala-application-with-filenames-larger-than-242-characters-in-c