Search code examples
scalaplayframeworkdockersbtspray

How to run a sbt project in docker by using sbt-docker or writing a docker file manually?


I have been trying to learn to run a sbt project in docker. I also want to use spray. I am following the example provided by sbt-docker in github: https://github.com/marcuslonnberg/sbt-docker/tree/master/examples/package-spray When i pull the project, it works fine and i could run the docker container as well.

There is a file inside project > project > PackageSprayBuild.scala I dont know how this file is being used. Also, the the given example doesnt have a plugins.sbt file.

Then i tried to create my separate project.

my plugins.sbt looks like this:

logLevel := Level.Warn

addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.2.0")

my build.sbt looks almost identical to that of the example i mentioned above.

name := "demo-docker-sbt"

version := "1.0"

scalaVersion := "2.11.7"

resolvers += "spray repo" at "http://repo.spray.io/"

libraryDependencies ++= Seq(
  "io.spray" % "spray-can" % "1.2.0",
  "io.spray" % "spray-routing" % "1.2.0",
  "com.typesafe.akka" %% "akka-actor" % "2.2.3")

enablePlugins(DockerPlugin)

// Make docker depend on the package task, which generates a jar file of the application code
docker <<= docker.dependsOn(Keys.`package`.in(Compile, packageBin))

// Define a Dockerfile
dockerfile in docker := {
  val jarFile = artifactPath.in(Compile, packageBin).value
  val classpath = (managedClasspath in Compile).value
  val mainclass = mainClass.in(Compile, packageBin).value.get
  val libs = "/app/libs"
  val jarTarget = "/app/" + jarFile.name

  new Dockerfile {
    // Use a base image that contain Java
    from("java")
    // Expose port 8080
    expose(8080)

    // Copy all dependencies to 'libs' in the staging directory
    classpath.files.foreach { depFile =>
      val target = file(libs) / depFile.name
      stageFile(depFile, target)
    }
    // Add the libs dir from the
    addRaw(libs, libs)

    // Add the generated jar file
    add(jarFile, jarTarget)
    // The classpath is the 'libs' dir and the produced jar file
    val classpathString = s"$libs/*:$jarTarget"
    // Set the entry point to start the application using the main class
    cmd("java", "-cp", classpathString, mainclass)
  }
}

Then i went into the terminal, inside the project and used command, "sbt docker" and then it gave me the following error:

[info] Resolving com.typesafe.akka#akka-actor_2.11;2.2.3 ...
[warn]  module not found: com.typesafe.akka#akka-actor_2.11;2.2.3
[warn] ==== local: tried
[warn]   /home/admin/.ivy2/local/com.typesafe.akka/akka-actor_2.11/2.2.3/ivys/ivy.xml
[warn] ==== jcenter: tried
[warn]   https://jcenter.bintray.com/com/typesafe/akka/akka-actor_2.11/2.2.3/akka-actor_2.11-2.2.3.pom
[warn] ==== public: tried
[warn]   https://repo1.maven.org/maven2/com/typesafe/akka/akka-actor_2.11/2.2.3/akka-actor_2.11-2.2.3.pom
[warn] ==== spray repo: tried
[warn]   http://repo.spray.io/com/typesafe/akka/akka-actor_2.11/2.2.3/akka-actor_2.11-2.2.3.pom
[info] Resolving jline#jline;2.12.1 ...
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  ::          UNRESOLVED DEPENDENCIES         ::
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn]  :: com.typesafe.akka#akka-actor_2.11;2.2.3: not found
[warn]  ::::::::::::::::::::::::::::::::::::::::::::::
[warn] 
[warn]  Note: Unresolved dependencies path:
[warn]      com.typesafe.akka:akka-actor_2.11:2.2.3 (/home/admin/IdeaProjects/demo-docker-sbt/build.sbt#L11-15)
[warn]        +- default:demo-docker-sbt_2.11:1.0
sbt.ResolveException: unresolved dependency: com.typesafe.akka#akka-actor_2.11;2.2.3: not found
    at sbt.IvyActions$.sbt$IvyActions$$resolve(IvyActions.scala:291)
    at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:188)
    at sbt.IvyActions$$anonfun$updateEither$1.apply(IvyActions.scala:165)
    at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:155)
    at sbt.IvySbt$Module$$anonfun$withModule$1.apply(Ivy.scala:155)
    at sbt.IvySbt$$anonfun$withIvy$1.apply(Ivy.scala:132)
    at sbt.IvySbt.sbt$IvySbt$$action$1(Ivy.scala:57)
    at sbt.IvySbt$$anon$4.call(Ivy.scala:65)
    at xsbt.boot.Locks$GlobalLock.withChannel$1(Locks.scala:93)
    at xsbt.boot.Locks$GlobalLock.xsbt$boot$Locks$GlobalLock$$withChannelRetries$1(Locks.scala:78)
    at xsbt.boot.Locks$GlobalLock$$anonfun$withFileLock$1.apply(Locks.scala:97)
    at xsbt.boot.Using$.withResource(Using.scala:10)
    at xsbt.boot.Using$.apply(Using.scala:9)
    at xsbt.boot.Locks$GlobalLock.ignoringDeadlockAvoided(Locks.scala:58)
    at xsbt.boot.Locks$GlobalLock.withLock(Locks.scala:48)
    at xsbt.boot.Locks$.apply0(Locks.scala:31)
    at xsbt.boot.Locks$.apply(Locks.scala:28)
    at sbt.IvySbt.withDefaultLogger(Ivy.scala:65)
    at sbt.IvySbt.withIvy(Ivy.scala:127)
    at sbt.IvySbt.withIvy(Ivy.scala:124)
    at sbt.IvySbt$Module.withModule(Ivy.scala:155)
    at sbt.IvyActions$.updateEither(IvyActions.scala:165)
    at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1369)
    at sbt.Classpaths$$anonfun$sbt$Classpaths$$work$1$1.apply(Defaults.scala:1365)
    at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$87.apply(Defaults.scala:1399)
    at sbt.Classpaths$$anonfun$doWork$1$1$$anonfun$87.apply(Defaults.scala:1397)
    at sbt.Tracked$$anonfun$lastOutput$1.apply(Tracked.scala:37)
    at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1402)
    at sbt.Classpaths$$anonfun$doWork$1$1.apply(Defaults.scala:1396)
    at sbt.Tracked$$anonfun$inputChanged$1.apply(Tracked.scala:60)
    at sbt.Classpaths$.cachedUpdate(Defaults.scala:1419)
    at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1348)
    at sbt.Classpaths$$anonfun$updateTask$1.apply(Defaults.scala:1310)
    at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
    at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
    at sbt.std.Transform$$anon$4.work(System.scala:63)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
    at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:226)
    at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
    at sbt.Execute.work(Execute.scala:235)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
    at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:226)
    at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
    at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
[error] (*:update) sbt.ResolveException: unresolved dependency: com.typesafe.akka#akka-actor_2.11;2.2.3: not found

Questions:

1). What version of akka should in use here and what are the things i am missing for properly runnning a sbt project inside a docker container ? Is there something i need to change in my build.sbt docker configuration ?

my sbt is 0.13.8, scala 2.11.7

2) What is the use of that PackageSprayBuild.scala file in the example project, and why is there no plugins.sbt file used ?

3). Is it necessary that i must also define a main class inside the sbt project before the image is build inside the docker for the project ? Or can i simply build an image by providing build.sbt and plugins.sbt configurations ?

4). what would be the sample docker file, if i want to manually build a docker image for my sbt-project without using the sbt-native-packager or sbt-docker or sbt-assembly ? I have read the dockerfile reference, but cant precisely get an idea of how to define a docker file particulary for a sbt project. An example would be extremely helpful showing commands up to building the image as well as the contents of that docker file.

5). There seems to be multiple ways of running the sbt project inside the docker container. Which would be the best approach to achieve it and why ? I want to use sbt with spray/play framework and run it in many containers.

I am using Lubuntu OS.


Solution

  • Take a look at DockerPlugin from SBT Native Packager Plugin