Has anyone had success running Play on an alpine-based Docker container? It seems broken per https://github.com/playframework/playframework/issues/8282.
Sounds like a useful thing to get working! I personally haven’t had any experience with that. It sounds like Play or sbt-native-packager might need a patch. ;)
I got it working with the below in
build.sbt, by inspecting the docker commands via
show dockerCommands in
sbt and then duplicating it, with the addition of adding bash.
Now, the point of these minimal Alpine releases is that they don’t have bash :) e.g. when there was the “ShellShock” bash vulnerability, these images were unaffected because they don’t have bash… that’s desirable.
It would be great to support these images out of the box. Is this a Play issue or a sbt-package-manager issue?
Update: Also, the docker image size (with just the base image and a minimal Play app) is something like 859 MB for the standard image and 229 MB for the alpine-based one. Big difference.
import com.typesafe.sbt.packager.docker._ dockerCommands := Seq( Cmd("FROM", "openjdk:8-jre-alpine"), Cmd("RUN", "apk --no-cache add bash"), Cmd("WORKDIR", "/opt/docker"), Cmd("ADD", "--chown=daemon:daemon opt /opt"), Cmd("USER", "daemon"), Cmd("ENTRYPOINT", """["bin/foo-service"]"""), Cmd("CMD", """""") )
If you want this recipe to be easily reusable you write a small sbt plugin that basically just adds these settings to a Play project. Here’s how to write a plugin: https://www.scala-sbt.org/1.0/docs/Plugins.html. Then users who want to use it would just need to add your plugin to their projects!
Actually using alpine based images is not the best idea for JRE stuff.
It’s better to use
sbt-assembly and use
Something like that:
FROM MY_SBT_BUILD_IMAGE ARG JAVA_OPTS ADD . /app WORKDIR /app RUN /usr/local/sbt/bin/sbt server/assembly RUN mkdir -p /out && mv server/target/scala-2.12/server.jar /out FROM gcr.io/distroless/java COPY --from=build-env /out /app WORKDIR /app EXPOSE 9000 CMD ["server.jar"]
I consider what I did a hack - if the underlying docker commands change in sbt-package-manager, the above code (or plugin) would not reflect that.
It would be great to get Play apps running on a stock Alpine-based docker image. This means looking into the runscript generation. I think this means there’s an issue here: https://github.com/sbt/sbt-native-packager/blob/master/src/main/scala/com/typesafe/sbt/packager/archetypes/scripts/AshScriptPlugin.scala
Could you please expand on why (using alpine based images is not good with JRE)? There are official alpine-based ‘openjdk’ docker images… Doing a brief search, I see a number of posts which recommend this route:
Well first of all alpine still comes with tools you don’t need (package manager, etc.)
Second a docker image should be as small as possible. and a sbt-assembly image with distroless can be even smaller.
(Well alpine is fine, ok-ish and at least better than most options, but removing any distro is even better and mostly more secure)
(Also your last link basically does the same I did with distroless, just with jdk9 (which does not work that “good” with play (yet)))
Of course the best image would be some kind of image where you have the following layers:
- base image with jre
- image with play dependencies & your dependencies
- your application jar
of course this won’t work
sbt-assembly but it will make your application even better deployable.
There are upsides and downsides of both approaches.
The first approach adopts for a overall “smallness”, while the second tries to minimize diff size if your deps won’t change.
Can you raise an issue over there on that project?
There is already an issue:
However it’s probably Play related.
Actually one of the “best” ways at the moment is probably to just run play with the following under docker:
FROM gcr.io/distroless/java COPY target/universal/stage/lib/* /app/lib/ COPY target/universal/stage/conf/ /app/conf/ WORKDIR /app EXPOSE 9000 ENTRYPOINT ["java"] CMD ["-Duser.dir=/app", "-cp", "conf/:lib/*", "play.core.server.ProdServerStart"]
sbt stage && docker build -t YOUR_TAG .
(it would probably be even more sane to actually have mutliple layer with your library, so that consider your application jars will be added after dependency jars, this makes your image bigger but it will use less space while upgrading, but I didn’t have time to fine tune that.)