Monday, May 6, 2013

Apache Archiva on a Raspberry PI

Apache Archiva
The purpose of this post is to provide  some hints on how to setup an Apache Archiva artifacts repository server on a Raspberry PI.




A Raspberry PI in a plastic case
In a few words, a Raspberry PI is an affordable credit card sized device, which has a very low power consumption, and runs under Raspbian Wheezy, a Linux Debian derivative (among other operating systems). Other characteristics of interest are :

  • ARM V6 Processor
  • 512 MB of RAM
  • 100 Mb/s Ethernet port
  • 2 USB ports
  • HDMI

My initial intent when I bought a Raspberry was to use it as an artifact repository  to deploy and share my Maven build artifacts (jars, war, ...) with different computers of my home network.

Artifacts repositories have a lot of other functionalities, among them:
  • acting as a specialized Maven proxy which saves network bandwidth if two different Maven instances or more need the same dependencies (artifacts),
  • keeping the Maven service "on" when the Internet access is "off".
As I am using Apache Archiva at work, it was a natural choice for me to use it also at home (and a compatibility choice because I use some Archiva dependent URLs in the SCM history of my pom.xml files - see below when it will come to the Archiva context path) .

So my first attempt was to install Archiva 1.3.6 (the latest stable version) on Raspbian Wheezy and execute it using OpenJDK 7.

#fail #1 : Missing wrapper !

Archiva failed to start because  the Tanuki Java Service Wrapper binary which is embedded in its last stable version has no ARM support. So I got the missing part from the Tanuki site ... and it worked (with a scary warning, more on this below) !

#fail #2 : But too slow !

I found Archiva very slow in this context (and unusable) ...

The explanation for that is the following: OpendJDK 7 itself, under Raspbian, is very slow.

Raspbian is a good choice for using the PI at its full performance level under Linux, but it is a bad choice for Java  (Soft Float Debian is know to be better for that).

#fail #3 : Oracle JVM not running under Raspbian !

Oracle JVM being faster than OpenJDK under ARM platforms, I downloaded the last JDK 7 from Oracle ... and it failed to work (see here for another testimony).

#fail #4 : Spring killed me !

I was about to switch to Soft Float Debian Wheezy when I remembered that Oracle produced in late 2012 a preview of JDK 8 for ARM processors ... and this one was able to work under Raspbian Wheezy.

Full of hope, I used it to launch Archiva 1.3.6 ... but it failed :

2013-05-06 16:02:33,079 [WrapperSimpleAppMain] ERROR org.springframework.web.context.ContextLoader  - Context initialization failed
org.springframework.beans.factory.BeanDefinitionStoreException: Unexpected exception parsing XML document from URL [jar:file:/home/archiva13/apache-archiva-1.3.6/apps/archiva/WEB-INF/lib/redback-configuration-1.2.9.jar!/META-INF/spring-context.xml]; nested exception is java.lang.IllegalStateException: Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser] are only available on JDK 1.5 and higher
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:420)
        at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
...
Caused by: java.lang.IllegalStateException: Context namespace element 'annotation-config' and its parser class [org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser] are only available on JDK 1.5 and higher
        at org.springframework.context.config.ContextNamespaceHandler$1.parse(ContextNamespaceHandler.java:65)
        at org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse(NamespaceHandlerSupport.java:69)

JDK 1.8 is higher than JDK 1.5, isn't it ? It should !

#success #1 : Use the next version of Archiva (1.4-M3)

I had no other choice to download the last standalone development version of Archiva (1.4 series), and ... hurrah !

It worked with Oracle JDK 8 ... and most importantly, at an acceptable speed (don't be afraid by the start-up time, and more particularly by the initial start-up time).

NB: I just changed in conf/wrapper.conf the -Xms and -Xmx settings of the Java heap size respectively to 64MB and 256MB, to better fit with the memory available on the PI (512MB).

There was still a warning in the logs related to the Tanuki wrapper  for ARM 32 bits architecture which was not in sync with the Tanuki jar (lib/wrapper.jar) embedded in the Archiva distribution (unsupported combination).

This one was easy to solve (download the sources, build, and put the binaries in place) :

root@raspberry:/tmp# wget -O wrapper.zip http://sourceforge.net/projects/wrapper/files/wrapper_src/Wrapper_3.5.19_20130419/wrapper_3.5.19_src.zip/download
root@raspberry:/tmp# unzip wrapper.zip
Archive:  wrapper.zip
   creating: wrapper_3.5.19_src/
   creating: wrapper_3.5.19_src/build/
   creating: wrapper_3.5.19_src/doc/
   creating: wrapper_3.5.19_src/src/
   ...
root@raspberry:/tmp# cd wrapper_3.5.19_src/
root@raspberry:/tmp/wrapper_3.5.19_src# export ANT_HOME=/usr/share/ant
root@raspberry:/tmp/wrapper_3.5.19_src# export JAVA_HOME=/opt/jdk1.8/
root@raspberry:/tmp/wrapper_3.5.19_src# sh build32.sh
--------------------
Wrapper Build System
using /tmp/wrapper_3.5.19_src/./build.xml
--------------------
Buildfile: /tmp/wrapper_3.5.19_src/build.xml
...
main:

BUILD SUCCESSFUL
Total time: 4 minutes 8 seconds
root@raspberry:/tmp/wrapper_3.5.19_src# ls -l bin/wrapper lib/wrapper.jar lib/libwrapper.so 
-rwxr-xr-x 1 root root 287313 mai    6 16:33 bin/wrapper
-rwxr-xr-x 1 root root  40225 mai    6 16:34 lib/libwrapper.so
-rw-r--r-- 1 root root 119494 mai    6 16:34 lib/wrapper.jar

Instructions to install the new wrapper:

cp bin/wrapper $ARCHIVA_HOME/bin/wrapper-linux-armv6l-32
cp lib/libwrapper.so $ARCHIVA_HOME/lib/libwrapper-linux-arm-32.so
cp lib/wrapper.jar  $ARCHIVA_HOME/lib


#fail #5 : Archiva 1.4-M3 killed me !

The new Archiva UI was OK and responsive, I was an happy man. I created some user acounts and start to make some tests with Maven (after all, it was all for that) and ... they failed.

Nothing was downloadable from my brand new Archiva Raspberrized instance !

#success #2 : Always, always read and read again the release notes !

Starting from Archiva 1.4-M3, the context path for Archiva is "/" and no more "/archiva".

Hopefully, there is a parameter for that (thank you Olivier Lamy !).

I was then able to test my installation using my Maven settings.xml file and all my projects's pom.xml files (after emptying my ~/.m2/repository directory to validate the whole thing, of course ...).

Update for 1.4-M4 release: as Olivier Lamy points it out in his first comment bellow, since the 1.4.M4 release, the property -DAsyncLogger.WaitStrategy=Block must be used when launching Archiva on the Raspberry in order to keep an acceptable level of performance. More details here.

Conclusion

The good news is that it is feasible to use Archiva on a home network using a PI.

After Gitolite and Archiva, the next logical target for me would be to try the Jenkins adventure to make a step forward the forge@home (on another PI; one service = one PI, these machines are too small !)  ...

I will give a try, unless I wait for a PI like device slightly more powerful for Jenkins (something like that or what we can expect to be the next generation of PIs).

In a next post, I will describe a Puppet module for installing or updating an Archiva 1.4.x instance  on the PI (or elsewhere).

I know that Puppetisation of Archiva like for many other softwares has been made a lot of times.

But since I entered the Puppet world, I do think that there is no such thing as a "Puppet Universal and Reusable Module for middleware X or tool Y".

Every company has its own way of doing or organize things, its own understanding and configuration set of parameters for each software, and that is why I think that it is very difficult to reach a universal level for a puppet module.

I prefer to consider Puppet modules as snippets where I always find new ways of doing things (either better or different), and this level of sharing is sufficient enough for me.