Deploy Scala binaries without dependencies

2020-05-23 16:41发布

问题:

Is there an easy way to copy a Scala Jar (~1MB) to a server and then have SBT pull in the dependencies (~40MB) it needs and run it?

I've seen sbt-onejar and sbt-assembly, but these bundle all dependencies into one jar which becomes ~45MB in my case which takes too long to upload to the server.

At the moment I use Capistrano to checkout my code from GitHub and compile it. I then run it using the xsbt-start-script-plugin - similarly to how Heroku manages this.

The problem is that the compilation takes a long time on the servers (I am using EC2). EC2 Micro with ~600MB ram takes insanely long and sometimes randomly kills the process. I am using an EC2 Small instance (1.7GB ram) which is working at the moment, but as the code base increases and I add more servers, it may become problematic.

The ideal workflow would be to compile the Scala sources locally (or on CI server), copy to server, have SBT pull in additional dependencies added since last build (existing ones would come from local cached ivy repo), then provide me with a simple script to run the service with Upstart on Ubuntu 10.04.

I would also like to hear how other Scala users deploy their code.


(code from "answer" later posted by OP)

FWIW here are my build files.

build.sbt

import com.typesafe.startscript.StartScriptPlugin
name := "XXX"
version := "0.1.0"
scalaVersion := "2.9.1"
resolvers += "XXX" at "http://repo.XXX.XXX"
libraryDependencies += "XXXX" %% "backend" % "0.1.0"
seq(StartScriptPlugin.startScriptForJarSettings: _*)
mainClass in Compile := Some("XXX.app.Main")

project/build.sbt

resolvers += Classpaths.typesafeResolver
addSbtPlugin("com.typesafe.startscript" % "xsbt-start-script-plugin" % "0.5.0")
addSbtPlugin("com.eed3si9n" % "sbt-dirty-money" % "0.0.1")

回答1:

Deploy your .jar to a repository (I use Artifactory, but I think you can publish via scp to a filesystem) that your servers can access. Create an empty sbt project that has a single dependency on your app's .jar file. You servers can pull and sbt update this empty project to download the jars to the server in a way that takes advantage of the local Ivy cache and is very bandwidth friendly. Then it's just a matter of getting the right classpath to launch your app.

One thing you have to watch out for is to make sure that sbt will actually update your dependencies. There's been some conversation about this on SBT's mailing list.

Options for launching the app (in order of increasing cleverness) are:

  • Just run sbt run
  • Use sbt-onejar or sbt-assembly to create a single .jar and run java -jar to run it
  • Write some sbt scripts to build the classpath, and use that to launch the app directly out of the Ivy cache. I seem to recall seeing a script to do that recently on SO, but can't find it at the moment. You can find a script that does this in this SO answer, or (as you suggested below) use the xsbt-start-script-plugin.