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 <dan@halftreelabs.com>")
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))
)
}
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.