1

I have an sbt project and i am creating its Jar using the sbt publishLocal command and i want a docker image for that i am doing something like this

FROM hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8

MAINTAINER Sara Waheed <[email protected]>

WORKDIR /myproject

ADD . /myproject

# Define default command.
CMD ["sbt", "publishLocal"]

and i am building it docker build -t myproject:v1 and run it docker run myproject:v1 i have seen in the logs

[info] Main Java API documentation successful.
[info] Packaging /stripe-payment-account/target/myproject-1.0.1-javadoc.jar ...
[info] Done packaging.
[info] :: delivering :: com.test#myproject;1.0.1 :: 1.0.1 :: release :: Tue May 07 10:26:13 UTC 2019
[info]  delivering ivy file to /stripe-payment-account/target/ivy-1.0.1.xml
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/poms/myproject.pom
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/jars/myproject.jar
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/srcs/myproject-sources.jar
[info]  published myproject to /root/.ivy2/local/com.test/myproject/1.0.1/docs/myproject-javadoc.jar
[info]  published ivy to /root/.ivy2/local/com.test/myproject/1.0.1/ivys/ivy.xml
[success] Total time: 77 s, completed May 7, 2019, 10:26:13 AM

and when i try to look the file contents of this container via

docker exec -t -i containerid /bin/bash

and look into

cd ///root/.ivy2 

and ls -a only shows

.  ..  .sbt.ivy.lock  cache

the local folder is missing here but when i run the container it shows that it created the jar in /root/.ivy2/local/com.test/myproject/1.0.1/docs/myproject-javadoc.jar

why its not showing the local folder in .ivy2 folder what i am doing wrong here?

2 Answers 2

1

You are using docker wrongly in this case IMHO and I have a serious doubt that your docker exec command is targeting the correct container because, from what I see (and my very limited knowledge of sbt/scala), it should be dead by the time the jar is published. Let me explain.

sbt publishLocal is not a long living command. It will exit when the jar is published to the local .ivy store on disk. So when you launch a container from your image in foreground with docker run --name mytestcontainer myproject:v1 (I added a name for easier debugging purpose on your side...), I am pretty sure you see all your above logs and that the command exits back to your shell.

At this point, if you issue a docker ps, your mytestcontainer will not show up, unless with docker ps -awhere it will be listed in the exited container. If you try to start it again (docker start mytestcontainer), it will exit as soon as the jar is re-compiled/published. So there is no way to target an exec on this container since it is not running. The only way to have a shell in a running container out of this image is to override the start command in docker run but this will bypass your jar publication.

Now, what you first want is to publish the jar as part of the image, not to compile/publish it everytime you start a container out of the image.

FROM hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8
MAINTAINER Sara Waheed <[email protected]>

WORKDIR /myproject
ADD . /myproject

RUN sbt publishLocal

In this case, the jar will be published during the build

docker build -t myproject:v1

You can then run a container out of your image dropping to jshell as intended by the base image you are using:

docker run -it --rm --name testcontainer myproject:v1
May 12, 2019 8:31:33 AM java.util.prefs.FileSystemPreferences$1 run
INFO: Created user preferences directory.
|  Welcome to JShell -- Version 11.0.2
|  For an introduction type: /help intro

jshell>

Or if you want a more classic bash shell, you can override the start command:

docker run -it --rm --name testcontainer myproject:v1 /bin/bash

To go further, if your intent is to deliver your application in a ready to use image, you should have a look at Docker multistage builds. The idea is to build your jar in an image containing all the needed build tools and to copy the produced artifacts to an other image intended only for run that you will finally distribute. Here is the basic idea from your example. Image/command used are solely for illustration purpose and the process is highly perfectible (e.g. harcoded version....):

FROM hseeberger/scala-sbt:11.0.2_2.12.8_1.2.8 as build
WORKDIR /myproject
ADD . /myproject
RUN sbt publishLocal

FROM openjdk:8-alpine
WORKDIR /myproject
COPY --from=build /root/.ivy2/local/com.test/myproject/1.0.1/jars/myproject.jar .
CMD['java', '-jar', 'myproject.jar']
0

Not knowing anything about the java appication, but just going on what you can do with docker: The workdir for the parent image is /root. You can try to omit the WORKDIR statement. The build script might be working in the current directory, which would not be /root, but /workdir. Or you can add WORKDIR /root again before CMD.

Also don't forget some basic checks, eg.

df -h 

to check if your server has enough free space (granted, it would have given an error message.) Also remove old containers:

docker ps -a 
docker rm containername
docker images
docker rmi imagename

If you add the WORKDIR root at the end, and the jar is created at

 /root/.ivy2/local/default/root_2.12/0.1.0-SNAPSHOT/jars/root_2.12.jar 

instead of, say:

/root/.ivy2/local/com.test/myproject/1.0.1/jars/myproject.jar

You can try to find the scripts that generate that path with grep:

egrep -r '(jars|root|default)' * 

This will recursively list all the files where those terms appear. You can scan them for clues so as to what configuration files or environment variables to use. Also check the configuration section of the documentation for the jar generating application. (It's not software I am familiar with.) If you find that there is an environment variable that informs the location, lets say for example PROJECT, then you can include it in the Dockerfile:

ENV PROJECT myproject.test.com

Or if you want to dynamically pass it to the container when you run it:

docker run -E PROJECT=myproject.test.com myproject:v1

More likely however, is that it is inside some sort of configuration file that you need to copy to the container. Because "docker build" copies all the files in the current directory, you can just create the file in the current directory. Or if you need to manually put it somewhere else:

PUT configfile /some/path

Or

RUN mv configfile /some/path

Or you can create it dynamically inside the container. If it's just one line that needs to be in a file in the container:

RUN bash -c "echo project: myproject.test.com > /some/path/configfile"

As a plan B you can always just create a softlink inside the container, if it will solve your problem:

mkdir -p /root/.ivy2/local/com.test/myproject/1.0.1
ln -s /root/.ivy2/local/default/root_2.12/0.1.0-SNAPSHOT/jars /root/.ivy2/local/com.test/myproject/1.0.1/

You can also add this as a RUN command before the CMD in the Dockerfile:

RUN mkdir -p /root/.ivy2/local/com.test/myproject/1.0.1 && /root/.ivy2/local/default/root_2.12/0.1.0-SNAPSHOT/jars /root/.ivy2/local/com.test/myproject/1.0.1/
2
  • first of all thank you so much for your response i have tried your solution i removed workdir and tested and added workdir /root but it did not helped also the jar renamed to published root_2.12 to /root/.ivy2/local/default/root_2.12/0.1.0-SNAPSHOT/jars/root_2.12.jar instead of /root/.ivy2/local/com.test/myproject/1.0.1/jars/myproject.jar
    – swaheed
    May 11, 2019 at 8:50
  • If you can't find the right place to change the name from default to com.test you can always just go and create a softlink in /root/.ivy2/local, instructions added.
    – Dagelf
    May 13, 2019 at 6:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.