sbt / sbt-native-packager

sbt Native Packager
https://sbt-native-packager.readthedocs.io/en/stable/
BSD 2-Clause "Simplified" License
1.59k stars 439 forks source link

DockerPlugin doesn't work with multiple main classes by default #1491

Closed kubukoz closed 1 year ago

kubukoz commented 2 years ago

Expected behaviour

sbt Docker/publishLocal produces a runnable image or fails at build time in the presence of multiple main classes

Actual behaviour

The image fails startup

Information

Reproduction

  1. Make an sbt project using NP:
val root = project
  .in(file("."))
  .enablePlugins(JavaAppPackaging)
  .enablePlugins(DockerPlugin)
  1. Add multiple main classes
object Foo extends App
object Bar extends App
  1. sbt Docker/publishLocal

  2. Try to run the generated image:

$ docker run --rm -it sha256:46c53661a82306d95dbd9e9db28fa7e98d7f5ae4553d5c0091f0f71dfdbb8c97
docker: Error response from daemon: OCI runtime create failed: container_linux.go:380: starting container process caused: exec: "/opt/docker/bin/root": stat /opt/docker/bin/root: no such file or directory: unknown.

Docker/dockerEntrypoint points to /opt/docker/bin/root, and setting it to a specific binary helps. Clearly the names are set by a heuristic documented in the docs.

However, I don't think the Docker plugin's behavior is intuitive, because if you add a new main class to a working build you'll suddenly be unable to run the images.

Maybe Docker/stage should fail if there are many main classes and none of them is explicitly chosen (by Docker/mainClass or dockerEntrypoint, I'm not sure)?

muuki88 commented 1 year ago

Thanks for your patience. This is hitting more and more users now. Would you like to open a PR to fix this?

The executableScriptName is set here initially

https://github.com/sbt/sbt-native-packager/blob/2268343362812bbca6e49f15e05586821a101bc7/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala#L99

and without any scoping used here

https://github.com/sbt/sbt-native-packager/blob/2268343362812bbca6e49f15e05586821a101bc7/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala#L129

An option would be to keep this a docker thing. And add

Docker / executableScriptName := normalizedName.value
dockerEntrypoint := Seq(s"${(defaultLinuxInstallLocation in Docker).value}/bin/${(Docker / executableScriptName).value}"),

and remove the executableScriptName entry here

https://github.com/sbt/sbt-native-packager/blob/2268343362812bbca6e49f15e05586821a101bc7/src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala#L281

kubukoz commented 1 year ago

I'll see when I have the time to dig into it and properly test the outcome, but if someone wants to pick it up earlier feel free to do so!

muuki88 commented 1 year ago

@kubukoz I was able to work on this :smile: Release is out

kubukoz commented 1 year ago

thanks, I'm not getting a lot of time with SNP these days :)

muuki88 commented 1 year ago

me neither :sweat: