Karaf on Docker creates an OSGi environment which you can easily bootstrap and is also highly scalable. This post explains how to setup a Docker environment for a custom Karaf Distribution.
The power of Apache Karaf lays in the easy deployment of your ActiveMQ Broker, your CXF webservices, or your own Apache Camel routes. For this post we are going to set up our own simple camel-route using a Karaf Custom Distribution, which we will dockerize!
Docker is a great way to setup easy maintainable and highly scalable environments, if you want to learn more about Docker read these awesome blog posts, also by The Guild!
1. Create a Karaf Custom Distribution
To quickly create a Custom Karaf Distribution we can use the following Maven archetype.
1 2 3 4 5 6 7 8 mvn archetype:generate \ -DarchetypeGroupId=org.apache.karaf.archetypes \ -DarchetypeArtifactId=karaf-assembly-archetype \ -DarchetypeVersion=4.0.7 \ -DgroupId=nl.theguild \ -DartifactId=karaf-distro \ -Dversion=1.0-SNAPSHOT \ -Dpackage=nl.theguild.karaf-docker
This will give you a new folder
karaf-distro where your new pom.xml is located. When we go to that folder we can compile our distribution with
mvn clean install.
When we execute
bin/karaf in our newly generated
target/assembly directory we see our very own Karaf custom distribution.
1 2 3 4 5 6 7 8 9 10 11 12 13 __ __ ____ / //_/____ __________ _/ __/ / ,< / __ `/ ___/ __ `/ /_ / /| |/ /_/ / / / /_/ / __/ /_/ |_|\__,_/_/ \__,_/_/ Apache Karaf (4.0.7) Hit '<tab>' for a list of available commands and '[cmd] --help' for help on a specific command. Hit '<ctrl-d>' or type 'system:shutdown' or 'logout' to shutdown Karaf. karaf@root()>
1.1 Add the resources
Our custom distribution is quite clean, it has nothing much just the standard package that Karaf provides you. As we look in the
pom.xml the archetype generated for us we see some resource paths defined.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <resources> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> <includes> <include>**/*</include> </includes> </resource> <resource> <directory>src/main/filtered-resources</directory> <filtering>true</filtering> <includes> <include>**/*</include> </includes> </resource> </resources>
We want to add the
Camel features to our Karaf distribution on startup so we have to define it as a resource. All resource files that have Maven property values that have to be filtered/replaced, should go in
src/main/filtered-resources/etc. So our
org.apache.karaf.features.cfg file that contains our startup features, goes in this folder.
The file will look something like this:
1 2 3 4 5 featuresRepositories=mvn:org.apache.camel.karaf/apache-camel/2.17.4/xml/features, \ mvn:org.apache.karaf.features/enterprise/4.0.7/xml/features, \ mvn:org.apache.karaf.features/spring/4.0.7/xml/features featuresBoot=management, shell-compat, camel
1.2 Add an Apache Camel route
Now that we have installed all the necessary dependencies we can actually start building our camel route!
For our example we are going to use a simple file-to-file route. The Camel route will look -something like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?xml version="1.0" encoding="UTF-8"?> <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd"> <camelContext id="context-1" xmlns="http://camel.apache.org/schema/blueprint"> <route id="route-1"> <from uri="file:/tmp/in?autoCreate=true&charset=utf-8"/> <to uri="file:/tmp/out?autoCreate=true&charset=utf-8&fileExist=Override"/> </route> </camelContext> </blueprint>
You can test the camel-route by placing the xml in the
target/assembly/deploy folder and placing a file in
/tmp/in on your machine, to watch it get transferred to
Another possibility is to create the
src/main/resources/deploy folder in your project and place the camel-route there. The contents of this folder will get transferred to the deploy folder of Karaf at startup.
2. Create a Dockerfile
Now that we have our very own custom Karaf distribution we want to run it inside a Docker container. All we have to do in order to make this happen, is create a
Dockerfile which builds our distribution.
Let’s break this down bit by bit, since Karaf runs on Java we want our image to be built from the Java 8 SDK base image.
1 FROM java:8-jdk
We then want to install Maven, and when done we want to clean up our apt-get. We could run this all in a separate
RUN layer which Docker would translate in building three layers. The first layer would update our apt-get, the second layer would install Maven, and the third layer would clean things up. But since the previous two layers are already build by Docker this “clean” won’t actually clean the previous build layers. That’s why we want to update, install and clean up our apt-get all in the same layer, so in the end the image is as small as possible.
1 2 3 RUN apt-get update \ && apt-get -y install maven\ && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
Now we want to determine in which directory on the Docker container we want our Karaf distribution to live. Let’s take
/opt/karaf for that, but we also need to create a temporary directory to store our source in, that will be used to build the distribution.
We set our working directory to the temporary directory and copy our source in.
1 2 3 4 5 6 RUN mkdir /opt/karaf; RUN mkdir /tmp/src; WORKDIR /tmp/src/ ADD . .
Now that we have setup our folder structure we can build our distribution. When built, we unpack our generated distribution to the destination folder
/opt/karaf and remove our temporary folder where we stored our source code. All in the same layer again.
1 2 3 RUN mvn clean install; \ tar --strip-components=1 -C /opt/karaf -xzf target/karaf-distro-1.0-SNAPSHOT.tar.gz; \ rm -rf /tmp/*
Docker allows us to view the logging of containers using the
docker logs command however, to make this work we have to make Karaf log to stdout.
1 2 RUN chmod 755 /opt; \ sed -i "21s/out/stdout/" /opt/karaf/etc/org.ops4j.pax.logging.cfg;
Next we want to volume our deploy folder so we can mount it on our host and keep the data when we stop or remove our container and restart it.
1 VOLUME ["/opt/karaf/deploy"]
Now lets expose the ports that Karaf uses by default, and define our main process of the Docker container. The main process decides when the container should stop or restart, when the main process stops, the container stops.
1 2 3 EXPOSE 1099 8101 44444 CMD ["/opt/karaf/bin/karaf"]
Thats it! When we add up all of the above the Dockerfile will look like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 FROM java:8-jdk MAINTAINER Joery Vreijsen ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64 RUN apt-get update \ && apt-get -y install maven\ && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* RUN mkdir /opt/karaf; RUN mkdir /tmp/src; WORKDIR /tmp/src/ ADD . . RUN mvn clean install; \ tar --strip-components=1 -C /opt/karaf -xzf target/karaf-distro-1.0-SNAPSHOT.tar.gz; \ rm -rf /tmp/* RUN chmod 755 /opt; \ sed -i "21s/out/stdout/" /opt/karaf/etc/org.ops4j.pax.logging.cfg; VOLUME ["/opt/karaf/deploy"] EXPOSE 1099 8101 44444 CMD ["/opt/karaf/bin/karaf"]
We can now build our custom distribution with
docker build -t . from within our distribution directory.
Note! When building the image, make sure you run
mvn clean first so we don’t sent any unnecessary data to our image.
3. Deploy your Apache Karaf container!
We can now run our custom distribution in two different ways, with
docker run or
docker-compose. For this post i’m going to stick with
docker run but if you like a docker-compose example, make sure to check out my git repo karaf-distro-docker
The basic docker run command is
docker run but we actually want to give some additional parameters to it. We want our ports to be mapped to our host so we can access them from outside of the container, and we want to specify where docker should mount our
This will result in:
1 docker run -v /path/on/host/:/opt/karaf/deploy -p 1099:1099 -p 44444:44444 -p 8101:8101 -d <image_name>
You are good to go! When you now drop your Camel context in the mounted deploy directory on your host machine, your Karaf container will pick it up an run it!
If copying into the mounted deploy directory doesn’t work, try pasting directly into the Docker container using
docker exec -it bash. Docker volumes are known to be slow which might make Karaf not picking it up.
Note! To test the camel-route you have to place a file in the
/tmp/in folder inside the Docker container.
Thanks for reading and if you have any question leave them in the comments below, and make sure to check out my git repo on http://github.com/vreijsen/karaf-distro-docker