How to deploy a Scala application with filenames larger than 242 characters in CloudFoundry garden container

廉价感情. 提交于 2019-12-12 03:16:45

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!