In this post I’ll explain how you can use docker to facilitate your developments and deployments when working with apache Karaf.
To help you run the examples in this article, I’ve created this github repository. It consists of a Maven multimodule project :
- karaf-sandbox : parent module. Also contains docker definitions
- karaf-sandbox-distribution : karaf custom distribution packaging
- karaf-sandbox-rest : a custom rest service that exposes /api/message http endpoint to post and get messages.
This post walks through the following sections :
- Karaf provisioning
- How to create your custom karaf distribution
- How to run your karaf distribution with docker
- References
Karaf provisioning
By karaf provisioning, we means : how to deploy and run your custom code in karaf ?
Karaf is a powerful osgi runtime environment which you can use to run your java apps : web applications, api, integration services… There are several ways to deploy your code in karaf. It is described here in the official documentation.
To sum up, the recommanded way to provision a karaf server is to package your application code as osgi features, then to install these features using karaf shell commands.
So the workflow for provisioning a karaf server from scratch would be something like this :
- Download karaf server archive from Download karaf server
- Unpack the karaf server and starts it by lauching
karaf/bin/start
command - Connect to the karaf shell by launching
karaf/bin/client
- Install the features repositories needed (ie. where to find the features)
- Install the features you need
For instance, if I want to install camel-core
in my karaf server, I will first connect to my karaf shell console, then use these two commands :
➜ karaf ./bin/client
Logging in as karaf
__ __ ____
/ //_/____ __________ _/ __/
/ ,< / __ `/ ___/ __ `/ /_
/ /| |/ /_/ / / / /_/ / __/
/_/ |_|\__,_/_/ \__,_/_/
Apache Karaf (4.1.4)
Hit '<tab>' for a list of available commands
and '[cmd] --help' for help on a specific command.
Hit 'system:shutdown' to shutdown Karaf.
Hit '<ctrl-d>' or type 'logout' to disconnect shell from current session.
karaf@root()> feature:repo-add mvn:org.apache.camel.karaf/apache-camel/2.19.4/xml/features
karaf@root()> feature:install camel-core
According to me this method has a huge drawback in a container world. Let’s say you have a container to manage your karaf server, each time you will have to install a feature in it, you will modify your container by applying configuration in it, breaking the rule of idempotence a container should follow.
To respect idempotence, it would be better to package your karaf server with all features you need, then build it and run it as container.
Fortunatly, karaf offers a way to package your own karaf server distribution
How to create your custom karaf distribution
Prerequisites :
- You need to have a valid maven installation to run following examples
- Current version of karaf at the time of writing this article is
4.1.4
.
You can generate your own karaf distribution by using the maven archetype : karaf-assembly-archetype
.
For the purpose of this article, we will init a karaf-sandbox-distribution
project.
The karaf-sandbox-ditsribution
project will consists of a karaf standard installation packaged with hawtio web console.
Init your custom distribution
Launch the following command from this directory to init the karaf distribution (Change groupId, package, … according to your needs).
mvn archetype:generate \
-DarchetypeGroupId=org.apache.karaf.archetypes \
-DarchetypeArtifactId=karaf-assembly-archetype \
-DarchetypeVersion=4.1.4 \
-DgroupId=marem.karaf.sandbox \
-DartifactId=karaf-sandbox-distribution \
-Dversion=1.0.0 \
-Dpackage=marem.karaf.sandbox
This command will generate a directory karaf-sandbox-distribution
with a well formatted pom.xml
in it.
In the generated pom.xml
you’ll find the following insteresting parts :
- packaging :
karaf-assembly
- dependencies : all the dependencies listed here will be included in the generated package.
- karaf-maven-plugin : you can configure the features you want to install
<project xmlns="http://maven.apache.org/POM/4.0.0" ...>
...
<packaging>karaf-assembly</packaging>
...
<dependencies>
<dependency>
<groupId>org.apache.karaf.features</groupId>
<artifactId>framework</artifactId>
<version>4.1.4</version>
<type>kar</type>
</dependency>
<dependency>
<groupId>org.apache.karaf.features</groupId>
<artifactId>standard</artifactId>
<version>4.1.4</version>
<classifier>features</classifier>
<type>xml</type>
</dependency>
...
</dependencies>
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>karaf-maven-plugin</artifactId>
<configuration>
<installedFeatures>
<feature>wrapper</feature>
</installedFeatures>
<!-- <startupFeatures/> -->
<bootFeatures>
<!-- standard distribution -->
<feature>standard</feature>
<!-- minimal distribution -->
<!--<feature>minimal</feature>-->
</bootFeatures>
<javase>1.8</javase>
</configuration>
</plugin>
</plugins>
</build>
</project>
Then, if you launch a maven install for this project, this will package a karaf server in your target
directory. You’ll find here :
assembly
directory : your karaf servertar.gz
: your karaf server packaged as tarzip
: your karaf server packaged as zip
You will be able to start your karaf server by launching bin/karaf
command directly from the target/assembly
directory (provided that you have a valid installation whith JAVA_HOME
env variable parametred).
> mvn clean install
...
> ll target
total 144M
drwxrwxr-x 9 assembly
-rw-rw-r-- 1 karaf-sandbox-distribution-1.0.0.tar.gz
-rw-rw-r-- 1 karaf-sandbox-distribution-1.0.0.zip
>./target/assembly/bin/karaf
Add your custom features
To add hawtio
feature to your karaf distribution, you will need to add the hawtio
xml features dependency in the maven dependencies, then add the feature hawtio
(or hawtio-offline
, the one I use in this article) to the boot features, so that I will be installed during karaf boot.
I also removed the wrapper
feature from installedFeatures
section, because I installs a lot of default features I don’t need.
<dependencies>
...
<dependency>
<groupId>io.hawt</groupId>
<artifactId>hawtio-karaf</artifactId>
<version>${hawtio.version}</version>
<classifier>features</classifier>
<scope>runtime</scope>
<type>xml</type>
</dependency>
</dependencies>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>karaf-maven-plugin</artifactId>
<configuration>
<installedFeatures/>
<!-- <startupFeatures/> -->
<bootFeatures>
<!-- standard distribution -->
<feature>standard</feature>
<feature>hawtio-offline</feature>
</bootFeatures>
<javase>1.8</javase>
</configuration>
</plugin>
</plugins>
</build>
Now if you re-install your project with maven, and start it, hawtio will be installed and you will be able to connect to hawtio web interface : http://localhost:8181/hawtio.
Same could be done with your custom application code. Just package your application code as osgi features, then add the repository xml feature in dependencies section, and finally add your custom features to bootFeatures list.
How to run your karaf distribution with docker
Now that we know how to package a custom karaf distribution, we can focus on how to run it with docker.
What we want :
- Docker should launch maven build (so that I don’t need to have maven installed on host)
- Docker should builds an image from karaf generated tar archive
- Docker should expose karaf used ports :
- 1099
- 8101 : Karaf ssh default port.
- 44444
- 8181 : Karaf http default port.
Docker image
Here is the Dockerfile
I use to build my image :
FROM maven:3.5-jdk-8 as KARAF-BUILD
RUN mkdir /src;
WORKDIR /src/
ADD . .
RUN mvn clean install
FROM openjdk:8-jdk
MAINTAINER Matthieu Rémy
VOLUME "/root/.m2"
ENV JAVA_HOME /usr/lib/jvm/java-8-openjdk-amd64
RUN apt-get update \
&& apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN mkdir /opt/karaf;
COPY --from=KARAF-BUILD /src/karaf-sandbox-distribution/target/karaf-sandbox-distribution-1.0.0.tar.gz /opt/karaf-sandbox-distribution-1.0.0.tar.gz
RUN tar --strip-components=1 -C /opt/karaf -xzf /opt/karaf-sandbox-distribution-1.0.0.tar.gz; \
rm /opt/karaf-sandbox-distribution-1.0.0.tar.gz
RUN mkdir -p /opt/karaf/data/log && touch /opt/karaf/data/log/karaf.log
EXPOSE 1099 8101 44444 8181
COPY karaf-sandbox-distribution/entrypoint.sh /usr/local/bin/docker-entrypoint
RUN chmod +x /usr/local/bin/docker-entrypoint
ENTRYPOINT ["docker-entrypoint"]
This Dockerfile
use a docker multi-stage build, to provide a minimal image :
first part of the dockerfile is just used build the Karaf distribution with maven.
Build image and run container with compose
To build and run this karaf sandbox container you can use docker-compose
with the following docker-compose.yml
file :
version: '3.2'
services:
karaf:
build: .
volumes:
- type: volume
source: m2repo
target: /root/.m2
ports:
- 1099:1099
- 8101:8101
- 4444:4444
- 8181:8181
networks:
- sandbox
networks:
sandbox:
volumes:
m2repo:
Build your docker image with this command :
➜ docker-compose build
Run a docker container with this command :
➜ docker-compose up -d
WARNING: The Docker Engine you're using is running in swarm mode.
Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.
To deploy your application across the swarm, use `docker stack deploy`.
Creating network "karafsandbox_sandbox" with the default driver
Creating volume "karafsandbox_m2repo" with default driver
Creating karafsandbox_karaf_1 ...
Creating karafsandbox_karaf_1 ... done
Check that your container is running :
➜ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d8e07197cba9 karafsandbox_karaf "docker-entrypoint" 5 seconds ago Up 4 seconds 0.0.0.0:1099->1099/tcp, 0.0.0.0:4444->4444/tcp, 0.0.0.0:8101->8101/tcp, 0.0.0.0:8181->8181/tcp, 44444/tcp karafsandbox_karaf_1
To read karaf logs :
➜ docker-compose logs -f
Then you can access your container hawtio with this url : http://localhost:8181/hawtio/login
Here we are, you have a custom karaf distribution running in docker container ! To go further, I will explain you how to scale this docker service in a future article.
References
This article has been inspired in part by the following projects or articles :