Reputation: 3463
I'm using sbt-native-packager and sbt-docker to generate Docker images as described in this tutorial. The Docker image won't run (permission denied), and on inspection it turns out that bin/start
is being created as an empty directory.
dan@cobalt:~/projects/confabulous/deva$ ls -l target/universal/stage/bin/
total 24
-rwxrw-r-- 1 dan dan 11591 Aug 5 20:44 deva
-rw-rw-r-- 1 dan dan 6211 Aug 5 20:44 deva.bat
drwxrwxr-x 2 dan dan 4096 Dec 31 1969 start
It also has a null timestamp for some reason. Why is it being created as a directory and not a shell script?
Here's my plugins.sbt:
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.1.4")
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.7.4")
addSbtPlugin("io.spray" % "sbt-revolver" % "0.7.1")
addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "0.5.0")
resolvers += Classpaths.sbtPluginReleases
And here's my build.sbt:
import DockerKeys._
import sbtdocker.{Dockerfile, ImageName}
import com.typesafe.sbt.packager.Keys._
organization := "com.confabulous"
name := "deva"
version := "0.0.1"
scalaVersion := "2.10.3"
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8", "-language:postfixOps")
resolvers ++= Seq(
"sonatype releases" at "https://oss.sonatype.org/content/repositories/releases/",
"sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/",
"typesafe repo" at "http://repo.typesafe.com/typesafe/releases/"
)
libraryDependencies ++= Seq(
"ch.qos.logback" % "logback-classic" % "1.0.9",
"com.typesafe.akka" % "akka-slf4j_2.10" % "2.3.3",
"com.typesafe.akka" %% "akka-actor" % "2.3.3",
"com.typesafe.akka" %% "akka-remote" % "2.3.3",
"com.typesafe.akka" %% "akka-agent" % "2.3.3",
"com.typesafe.slick" %% "slick" % "2.0.1-RC1",
"org.mozilla" % "rhino" % "1.7R4",
"org.postgresql" % "postgresql" % "9.3-1101-jdbc3",
"org.msgpack" %% "msgpack-scala" % "0.6.8",
"com.livestream" %% "scredis" % "1.1.2",
"com.confabulous" %% "messages" % "0.0.1-SNAPSHOT",
"com.confabulous" %% "db" % "0.0.1-SNAPSHOT"
)
packageArchetype.java_server
sbtdocker.Plugin.dockerSettings
mappings in Universal += baseDirectory.value / "docker" / "start" -> "bin/start"
docker <<= docker.dependsOn(com.typesafe.sbt.packager.universal.Keys.stage.in(Compile))
// Define a Dockerfile
dockerfile in docker <<= (name, stagingDirectory in Universal) map {
case (appName, stageDir) =>
val workingDir = s"/opt/${appName}"
new Dockerfile {
// Use a base image that contain Java
from("relateiq/oracle-java7")
maintainer("Dan Ellis <[email protected]>")
expose(1600)
add(stageDir, workingDir)
run("chmod", "+x", s"/opt/${appName}/bin/${appName}")
run("chmod", "+x", s"/opt/${appName}/bin/start")
workDir(workingDir)
entryPointShell(s"bin/start", appName, "$@")
}
}
imageName in docker := {
ImageName(
namespace = Some("confabulous.com"),
repository = name.value
//,tag = Some("v" + version.value))
)
}
Upvotes: 1
Views: 1695
Reputation: 1196
Another option is to make use of the experimental support for Docker in sbt-native-packager.
If you remove the Docker-related lines from build.sbt, and add a maintainer
setting, you can:
sbt docker:stage
generate a Dockerfile and context in target/docker/stage
sbt docker:publishLocal
generate a local image
sbt docker:publish
generate an image and push it remotely
If you want to modify the commands passed to the start script, you can make modifications like this:
bashScriptExtraDefines := Seq(
"CLUSTER_IP=$(/sbin/ifconfig eth0 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')",
"addResidual ${CLUSTER_IP}"
)
addResidual
is a function in the start script generated by sbt-native-packager, that adds an extra parameter to the command line arguments for the program.
addJava
is a function that adds an extra parameter to the Java binary that runs your program.
Your build.sbt
might look like this:
import com.typesafe.sbt.packager.Keys._
organization := "com.confabulous"
name := "deva"
version := "0.0.1"
scalaVersion := "2.10.3"
scalacOptions := Seq("-unchecked", "-deprecation", "-encoding", "utf8", "-language:postfixOps")
resolvers ++= Seq(
"sonatype releases" at "https://oss.sonatype.org/content/repositories/releases/",
"sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/",
"typesafe repo" at "http://repo.typesafe.com/typesafe/releases/"
)
libraryDependencies ++= Seq(
"ch.qos.logback" % "logback-classic" % "1.0.9",
"com.typesafe.akka" % "akka-slf4j_2.10" % "2.3.3",
"com.typesafe.akka" %% "akka-actor" % "2.3.3",
"com.typesafe.akka" %% "akka-remote" % "2.3.3",
"com.typesafe.akka" %% "akka-agent" % "2.3.3",
"com.typesafe.slick" %% "slick" % "2.0.1-RC1",
"org.mozilla" % "rhino" % "1.7R4",
"org.postgresql" % "postgresql" % "9.3-1101-jdbc3",
"org.msgpack" %% "msgpack-scala" % "0.6.8",
"com.livestream" %% "scredis" % "1.1.2",
"com.confabulous" %% "messages" % "0.0.1-SNAPSHOT",
"com.confabulous" %% "db" % "0.0.1-SNAPSHOT"
)
packageArchetype.java_server
maintainer := "Dan Ellis <[email protected]>"
More information should be available from the sbt-native-packager documentation. Comments are also welcome.
Upvotes: 3
Reputation: 1196
The referenced article is part 2 of a series, where the address of the container is passed into the Java program by a script. The script itself is referenced in part 1.
mappings in Universal
takes a sequence of (File, String)
tuples. The File is copied to the path specified by the String in the resulting image.
In this case, if there is no file present at baseDirectory.value / "docker" / "start"
, then nothing is available to copy, and the resulting is the behavior you describe.
You should create an appropriate start script, as discussed in part 1.
Upvotes: 3