19

I'm using sbt-native-packager 1.0.0-M5 to create my docker image. I need to add a file that's not a source file or in the resource folder. My docker commands are as follows:

dockerCommands := Seq(
  Cmd("FROM", "myrepo/myImage:1.0.0"),
  Cmd("COPY", "test.txt keys/"), // <-- The failing part
  Cmd("WORKDIR", "/opt/docker"),
  Cmd("RUN", "[\"chown\", \"-R\", \"daemon\", \".\"]"),
  Cmd("USER", "daemon"),
  ExecCmd("CMD", "echo", "Hello, World from Docker")
)

It fails with: msg="test.txt: no such file or directory"

So after digging around a bit it seems I need to have test.txt in target/docker/stage. Then it works. But how do I get it there automatically? The file is actually in the root folder of the project.

2rs2ts
  • 10,662
  • 10
  • 51
  • 95
Andreas Du Rietz
  • 1,151
  • 11
  • 16
  • 1
    I've been wondering this too. I can tell you that adding it as a mapping (`mappings in Docker` or `dockerPackageMappings in Docker`) does not work, despite it [seeming that should work](https://github.com/sbt/sbt-native-packager/blob/master/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala#L94). – 2rs2ts Mar 13 '15 at 18:00

5 Answers5

22

I managed to get it to work by adding the file to mappings in Universal. So for you, you would need something like this:

mappings in Universal += file("test.txt") -> "keys/test.txt"

You won't need the COPY command if you do this, by the way.

Now, I'm not sure if this is going to add this mapping to other sbt-native-packager plugins. I hope a commenter can tell me whether or not this is true, but my intuition is that it will do so, which might be a dealbreaker for you. But any workaround is better than none, right? If you use Build.scala you could maybe use a VM argument to tell sbt whether or not to add this mapping...

2rs2ts
  • 10,662
  • 10
  • 51
  • 95
  • I'm able to place files within the Docker working directory in this way, but unfortunately in the root. i.e. mapping to "/test.txt" seems to have the preceding slash ignored. – akauppi Nov 25 '15 at 15:30
  • You could run another command to move the file where you want to: dockerCommands += ExecCmd("RUN", "mv", s"${(defaultLinuxInstallLocation in Docker).value}/keys/test.txt", "/wherever/you/want/test.txt") – radek1st Mar 16 '16 at 09:58
  • What is the base directory for these mappings? Like, relative to `build.sbt` in the root of the project, where would native packager look for `test.txt`? – kag0 Apr 04 '18 at 21:38
  • @kag0 it's been 3 years since I wrote this answer (and 2.5 since I last worked on an sbt project) and I don't have access to the code anymore. So unfortunately I don't remember. – 2rs2ts Apr 04 '18 at 21:48
  • 1
    @2rs2ts I've figured it out through a bit of experimentation. The base directory is the project root (so same directory `build.sbt` is in). But do note that if you're in a sub-project, the base directory is still the same directory of the ROOT project `build.sbt`, not the subproject `build.sbt`. – kag0 Apr 04 '18 at 22:22
12

You may place all additional files (which must be included in container image) into folder src/universal. Content of that folder will be automatically copied in /opt/app folder within your container image. You don't need any additional configuration. See "Getting started with Universal Packaging" for additional info.

The files located in /src/universal will be available in the runtime directory for the Scala app in the Docker container. This means that if your app has /src/universal/example.txt, then it can be accessed with scala.io.Source.fromFile("./example.txt")

Brian
  • 444
  • 1
  • 4
  • 16
4

For sbt-docker plugin, not sbt-native-packager

I was able to add files this way:

For example, to add a file located in src/main/resources/docker/some-file.ext

dockerfile in docker := {
  val targetPath = "/usr/app"

  // map of (relativeName -> File) of all files in resources/docker dir, for convenience
  val dockerFiles = {
    val resources = (unmanagedResources in Runtime).value
    val dockerFilesDir = resources.find(_.getPath.endsWith("/docker")).get
    resources.filter(_.getPath.contains("/docker/")).map(r => dockerFilesDir.toURI.relativize(r.toURI).getPath -> r).toMap
  }

  new Dockerfile {
    from(s"$namespace/$baseImageName:$baseImageTag")
    ...
    add(dockerFiles("some-file.ext"), s"$targetPath/some-file.ext")
    ...
  }
}
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
AlonL
  • 6,100
  • 3
  • 33
  • 32
4

I was able to get this working using dockerPackageMappings:

dockerPackageMappings in Docker += (baseDirectory.value / "docker" / "ssh_config") -> "ssh_config"

dockerCommands := (dockerCommands.value match {
  case Seq(from@Cmd("FROM", _), rest@_*) =>
    Seq(
     from,
     Cmd("Add", "ssh_config", "/sbin/.ssh/config")
  ) ++ rest
})
jdprc06
  • 360
  • 3
  • 7
0

You can add an entire directory to a Docker image's file system by first making it available using dockerPackageMappings, and then COPYing it as an additional Docker command.

import NativePackagerHelper._
dockerPackageMappings in Docker ++= directory(baseDirectory.value / ".." / "frontend" )

dockerCommands ++= Seq(
  Cmd("COPY", "frontend /opt/frontend"),
)
Ruurtjan Pul
  • 1,197
  • 1
  • 10
  • 21