How to reduce docker image size for Java application - java

i have the following dockerfile code but the image with over 500mb is way to large. I tried to use multi stage build in order so reduce the size but after that the kubernetes deployment wont work.
FROM openjdk:8
ADD target/name_id.jar name_id.jar
EXPOSE 8080
ENTRYPOINT [ "java","-jar","name_id.jar" ]
With this file it works. Can someone help me?
For the project itself maven and springboot are used. I also have to clean install the jar everytime if i change something in the code.

Can you use openjdk:8-alpine, size of the base image will be 144.9MB.
Use below image for less size
• openjdk:8-jre-alpine: 84 MB
Or you can also try to install alpine os which is 5 MB and openjdk separately and check sizes

Personally, there are two things that come to mind when I think of minimizing the docker image
Base Images
Multistage Builds
Le me try to answer your question
I would used the small jdk image i.e openjdk:8-alpine
I would used this if I wanted to create the jar file inside the Dockerfile AND execute it. In you case, you just want to use an already existing jar file.
Since you already have and want to use the jar file named name_id.jar,
Then you just need the java runtime environment i.e openjdk:8-jre-alpine rather than openjdk:8-alpine

Related

fabric8io docker-maven-plugin assembly and external artifact

I am trying to create a docker image from within maven which includes artifacts from a different maven project. But the examples I have copied do not appear to be working.
I think the problem here is I do not really understand how assemblies work and so am asking for help on what I want to do here. I have set up a contrived simple example of what I am trying to do here:
https://github.com/sodved/java-docker-demo/tree/0.0.1-0
pom.xml
sod-java/pom.xml
sod-java/src/main/java/sodved/Sod.java
sod-docker/pom-depency.xml
sod-docker/pom.xml
sod-docker/src/main/docker/setup.sh
sod-docker/src/main/docker/Dockerfile
sod-docker/src/main/docker/run.sh
So my project has two modules:
sod-java which builds an executable jar (which just writes a file to /tmp/sod.txt)
sod-docker which creates a java alpine image with Dockerfile
setup.sh is run when building the image. It runs the java to create the /tmp/sod.txt
run.sh is the default command writes the content of the /tmp/sod.txt file
I have tried two approaches to the inline <assembly> so far:
https://github.com/sodved/java-docker-demo/blob/0.0.1-0/sod-docker/pom-depency.xml Was my first attempt. Using dependecySet in the assembly. But I noted that the dependency was not even included in the /target folder (I assume because there is no actual java code to compile in sod-docker, so the dependencies were not copied).
https://github.com/sodved/java-docker-demo/blob/0.0.1-0/sod-docker/pom.xml Was my second attempt. It first explicitly copied the artifact into /target folder (which worked). Then used file in the assembly to try and copy the file.
In both cases I do not see the jar file copied anywhere by the assembly or in the tar file which the docker plugin creates and so I get an error when attempting to reference the jar in a Dockerfile COPY command.
I know the example is a bit contrived. But its simple and fitting with the standard way we do things at work. So I do not have a lot of flexibility in respect to tools, layouts etc.
The real case is used to build database images. Get base image, run java code to manipulate database, save as new image to be used downstream.
TLDR:
How can I specify a groupId, artifactId, version and have the corresponding artifact included in my docker image. The docker source itself contains no java.
OK, have figured it out.
The issue was that the pom.xml specified some external configuration
<external>
<type>properties</type>
<prefix>docker</prefix>
<mode>override</mode>
</external>
But as the doco here (http://dmp.fabric8.io/#property-configuration) says, this means the <build> configuration (including my assembly) in the pom.xml will be ignored. I am not sure why our standard uses the external configuration, will chase up our ops people on that. But removing this <external> section and everything works.

Zookeeper cli not starting

I've installed zookeeper v 3.4.9 on suse using the following package:
http://download.opensuse.org/repositories/home:/nicolasbock:/midokura/openSUSE_Leap_42.2/x86_64/zookeeper-3.4.9-1.1.x86_64.rpm
Starting the server works just fine an the various application that need to connect to it seem to be able to do so just fine, however I'm getting a strange error when I try to start the client:
zkCli.sh -server 127.0.0.1:2181
Error: Could not find or load main class org.apache.zookeeper.ZooKeeperMain
I've tried searching around the internet but the only answer I've come up with is setting the env variable $CLASSPATH. I tried looking what classpath is used internally by the serve starting script and set $CLASSPATH to that but with no results.
I'm running openjvm v 1.8.0_121
I encountered this problem today on Ubuntu 18.04. On zookeper official download page once one follows the given mirror link and chooses stable version, he can see 2 files available. In my case those were:
apache-zookeeper-3.5.5-bin.tar.gz
apache-zookeeper-3.5.5.tar.gz
I chose apache-zookeeper-3.5.5.tar.gz, observed the same problem. Tried to print CLASSPATH as #Jonathan suggested, it was printing different paths however, problem is that the archive file did not contain zookeper jars, probably it is expected that user packages to jar himself as I could find source code in that archive file.
Downloading larger apache-zookeeper-3.5.5-bin.tar.gz archive, extracting and running ./zkCli.sh went smooth as it had everything necessary, so whoever faces the same problem, try that and see if it does the trick for you.
Are you trying on Unix or Windows?
I dont think, you need "-server 127.0.0.1:2181"
Just run zkCli.sh or zkCli.cmd
That is a classpath problem. The zkCli.sh script is attempting to launch a java app where the main class is ZooKeeperMain. However, java cannot find the ZooKeeperMain class file because the classpath being passed to java does not contain a jar file that contains the ZooKeeperMain class.
Typically, the ZooKeeperMain.class file is contained in a jar file at something like $ZOOKEEPER_HOME/zookeeper-3.4.13.jar.
You might trying modifying the zkCli.sh script to print out the classpath just before the script attempts to launch ZooKeeperMain. The classpath should contain the jar that contains the ZooKeeperMain class.
On my Windows 10 machine, my classpath looks like this:
/c/Program Files (x86)/Zookeeper/bin/../build/classes:/c/Program Files (x86)/Zookeeper/bin/../lib/slf4j-log4j12-1.7.25.jar:/c/Program Files (x86)/Zookeeper/bin/../lib/slf4j-api-1.7.25.jar:/c/Program Files (x86)/Zookeeper/bin/../lib/netty-3.10.6.Final.jar:/c/Program Files (x86)/Zookeeper/bin/../lib/log4j-1.2.17.jar:/c/Program Files (x86)/Zookeeper/bin/../lib/jline-0.9.94.jar:/c/Program Files (x86)/Zookeeper/bin/../lib/audience-annotations-0.5.0.jar:/c/Program Files (x86)/Zookeeper/bin/../zookeeper-3.4.12.jar:/c/Program Files (x86)/Zookeeper/bin/../conf:
I encountered a similar errors as yours when launching zkCli.sh from Git Bash for Windows on my Windows 10 machine. My issue was because of the way Git Bash was handling wildcards in the classpath. I initially had some *.jar entries in my classpath that I removed to get zkCli.sh to launch.

Is it possible to create a standalone JAR web app with Play Framework?

I'm trying to create a standalone JAR application, which will be executed from command line like this:
$ java -jar foo.jar --port=8080
I want to use Play Framework. Is it possible to create something like this? I want to use Java and Maven. I want to stay away from that "activators" or downloading of Play. Just plain old simple Maven dependencies. Possible?
To stay away from activator and Play download just on your dev-machine call cmd: ./activator dist (activator.bat dist for Windows) it will create a ZIP file in the target/universal/ directory containing scripts for both: Unixes and Windows within the bin directory.
So you can launch your app like (unix sample, after unzipping)
/your-app-dir/target/universal/your-app-1.0-SNAPSHOT/bin/your-app -Dhttp.port=8080
Of course, nothings prevents you from creating additional shell script/BAT file for simplicity this path
As mentioned here it is possible. Look at the documentation (Default SBT layout).
Quote from the play 2.4.0 documentation:
You also have the option of using the default layout used by SBT and Maven. Please note that this layout is experimental and may have issues. In order to use this layout, use disablePlugins(PlayLayoutPlugin). This will stop Play from overriding the default SBT layout [...]
I haven't tested it, but I think this is a good point to start at :)
P.S.: Let us know if it is possible!

Can't figure out cause for NoClassDefFoundError: aspose/pdf/Paragraph

I can't get any pages of my webapp to load (locally on Tomcat 7.0.2.6), due to this NoClassDefFound error. I'm at my wits end trying to figure out what the cause is, here is what I know:
My coworker has this project successfully running locally (on Tomcat) and on our development server (WebLogic).
I have done a fresh pulldown from svn so my code is exactly the same as his. I've verified that I have a shared library reference to Aspose (and that the required .jars are in there), and that weblogic.xml has an entry for it.
We saw this same error when initially deploying on WebLogic because the Aspose library was named incorrectly, but it ran fine locally on his Tomcat server.
I've tried cleaning and rebuilding the project to no effect.
As best as I can figure, it has to be either a Tomcat issue, or maybe an Eclipse setting.
Has anyone encountered a similar situation? Any ideas on what to try to resolve this?
First thing you need to do is determine if you are colliding with another class with the same name and package. The easiest way to do this is with the cygwin/linux console, save this shell script to a file say, findjar
find "$1" -name "*.jar" -exec sh -c 'jar -tf {}|grep -H --label {} '$2'' \;
put it in your path and navigate to the root of the server instance and run the script like this
findjar . yourclass
Note the period, dont forget it. this will return if you have multiple classes with the same name in your project.
once your sure the project is clean and there is only one copy of the class, i would try actually adding your shared libraries folder to the websphere server instances JVM arguments. to do that:
Go into the admin, click on servers
Open server types, click on websphere application servers
You should see your server listed there, click on it
On the right hand side, you will see a section “server infrastructure” and below that is a subsection “Java and process Management”
Open that section and click on “Process Definition”
On the process definition screen is another right hand column. Click on “Java Virtual Machine”
Yes, finally we are on the correct screen, there is an end in sight here, I promise
On the virtual machine page, there is a large text field labeled “Classpath” What you need to do is enter the full path to the shared libraries folder
its odd and makes no sense to have to do it, but i have had to do that in the past to allow my code to see the properties files in a shared resource.
It is possible that your colleague has java librarys installed within his Tomcat instance itself.
Take a look in the Tomcat directory for some lib folders (I cant remember the exact location and I think it changes based on the version) but something like ${CATALINE_HOME}/common/lib
Verify that he doesnt have differen JAR files in his tomcat installation as yours.
From this question: Does Tomcat load the same library file into memory twice if they are in two web apps?
They are apparently stored here:
Tomcat 6 $CATALINA_HOME/lib
Tomcat 5 $CATALINA_HOME/common/lib

How to refer a jar outside exe in Java desktop application?

I have a Java application installed. The jar is bundled into an .exe file using Launch4J. Now I want to create a patch for this application.
If I create another jar containing only updated files, how can I refer it in the original code?
I have java application installed. ..Now I want to create a patch for this application.
This is one of the strengths of the Java Web Start launch technology that comes with the J2SE. Simply update the Jar on the server, and the next time the app. launches, it will be updated.
The update can be honed for your use-case, configured to be done lazily or eagerly, before or after launch, or even programatically controlled using the JNLP API's DownloadService.
..And the jar is bundlled into an .exe file ..
'Unfortunately', JWS works on Windows, ..and Mac., and *nix - so you may have to expand your horizons.
BTW - I have no idea how to do the same with Launch4J, but then, that is really the wrong question. I aim to provide an answer to the right question, which is "How do I deploy & update a Java rich client?". ;)
I've never worked with Launch4J, however I think you should try to affect the classpath. JRE always loads the classes from the classpath. From this point of view, jars have no added value and just serve as a containers for your *.class files and resources.
Now, if you succeed to configure your tool to do something like:
classpath = C:\Temp\my_patch_path;$your_current_classpath
then its enough to put your changed files into C:\Temp\my_patch_path (of course preserving the package structure). JRE will load your classes first in this case.
Hope, this helps
Mark
It is might not be possible to do this without changing the contents of the exe.

Categories