Professional Documents
Culture Documents
Building Microservices in OSGi With The Apache
Building Microservices in OSGi With The Apache
A tutorial.
The microservice paradigm has been a topic of heavy discussion and interest in
recent years. To make the matter even more involved developers and architects have
different understandings of the core principles of microservices and the need to
adopt a microservice-based architecture.
Since the Spring and JavaEE frameworks provide mechanisms for adopting a
microservice-based architecture, the very fundamental building blocks of creating
one with OSGi are already well established by the core and compendium
specifications.
We are bundled with the task of architect a complex system. So complex that it is
even required that the separate microservices be split into separate self-container
modules internally, enabling each one to evolve over time without having to bring
down the entire microservice. Such a system would be represented at a very high
level schematically by the following diagram:
Examples of such complex systems that might be implemented in that manner are:
An IoT system (where each device integration is an OSGi microservice split into
modules that implement the different functions of the device).
A complex supply chain (i.e. flight cargo supply chain system).
A complex factory process (i.e. for an automotive or airplane factory).
In this article, we will demonstrate how we can get the best of both worlds and
build a microservice-based system on top of the Apache Karaf framework (using
default Apache Felix OSGi runtime through Karaf) that addresses this latter
scenario.
OSGi 101
OSGi (Open Services Gateway initiative) provides a set of specifications for
building module systems in Java. There are several notorious frameworks
implementing the OSGi framework such as Eclipse Equinox and Apache Felix. It is
introduced as JSR 8 and JSR 291 to the Java platform.
An OSGi framework/runtime makes use of the Java class loading mechanism in order to
implement a container for modular units (bundles). Many application servers are
implemented using OSGi as a basis.
An OSGi bundle is just a JAR file that contains source code, bundle metadata, and
resources. A bundle may provide various services and components to the OSGi
runtime. An OSGi runtime allows for bundles to be installed, started, stopped,
updated and uninstalled without requiring a reboot.
bundle lifecycle
The OSGi Core spec defines a layered architecture that determines what is supported
by the runtime. Each layer defines a particular functionality supported by the
runtime and the bundles.
osgi layers
Bundles may export packages for use by other bundles, or import packages exported
by other bundles. This dependency mechanism is referred to as wire protocol and is
provided by the module layer of OSGi.
Bundles may publish services to the runtime and use already published services from
the runtime. This dependency mechanism is provided by the service layer of OSGi.
services layer
The MANIFEST.MF file of the bundle�s JAR file describes the metadata of the bundle.
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Sample
Bundle-SymbolicName: com.exoscale.sample
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: com.exoscale.sample.Activator
Bundle-Vendor: Exoscale
Require-Bundle: com.exoscale.otherbundle
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Service-Component: OSGI-INF/service.xml
Import-Package: com.exoscale.services.example;version="3.0.0�
Export-Package: com.sample.utils
If we span outside the premises of the OSGi environment, we get into additional
challenges related to all of the above and including additional considerations such
as load balancing, auto-scaling, self-healing, distributed tracing, resilience,
fault tolerance, and back-pressure to name a few.
All of these can be enabled by means of the Remote Service and Remote Service Admin
specification defined by the OSGi compendium specification.
To be more precise the Remote Service Admin spec defines a pluggable management
agent called Topology Manager that can fulfill the different concepts mentioned
that characterize the interaction between remote OSGi services (effectively the
communication channel between the different OSGi runtimes that form the set of
microservices).
For the purpose of simplicity, we will limit the system to the production of the
main parts. The system consists of three microservices which are distinct OSGi
runtimes with different modules related to the particular microservice:
Body � includes separate modules for the production of the different body parts
such as hood, bumper, pillars, and spoilers.
Doors � includes separate modules for the production of door components such as
handles, locks and hinges.
Windows � includes separate modules for the production of window components such as
glasses and glass regulators.
The system works in a supply-chain manner, whereby we first build the body of the
car, then the doors and finally the windows, before they are finally assembled.
Moreover, since each particular phase of the supply chain is modular, we can
upgrade or replace entire modules that build certain parts (such as the hood)
without really interacting with the full supply-chain and bringing the system out
of operations.
Two of the most notorious frameworks that provide an implementation of the remote
service and remote service admin specifications are Apache CXF and the one provided
by ECF (Eclipse Communication Framework).
We will be using the Apache CXF distributed OSGi subproject that implements a REST
provider for the Aries Remote Service Admin. We will be deploying our application
in a Karaf environment using Felix OSGi runtime (Karaf also provides support for
running an Equinox OSGi runtime).
Note that Karaf provides an alternative mechanism for creating a distributed OSGi
runtime by means of the Karaf Cellar runtime.
First, download the latest Karaf version from the Karaf website.
Instead of downloading the CXF DOSGi distribution Karaf comes with a feature that
installs it directly in Karaf.
Since we will need two separate Karaf runtimes for the deployment of the services
we will simulate the scenario by running the runtimes locally on different HTTP
ports (9991 and 9992).
org.osgi.service.http.port=9991
org.osgi.service.http.port=9992
bin/karaf.bat
After the runtimes are started install the CXF DOSGi feature (with the CXF JAX-RS
provider) and Jackson JSON provider on both of them as follows:
feature:repo-add cxf-dosgi
feature:install cxf-dosgi-provider-rs
feature:repo-add mvn:org.code-house.jackson/features/2.8.11/xml/features
feature:install jackson-jaxrs-json-provider
feature:install jackson-module-jaxb-annotations
Note: If you want to observe bundle information from the containers in the browser
rather than the Karaf console you can install the web console feature.
Now let�s implement and deploy the services one by one and run an example scenario
that demonstrates that our services interact as expected.
The Maven configuration that provides the build information for the module is
available here.
We use the Maven bundle plugin to generate the module metadata (in the MANIFST.MF
file of the module). In order to represent a configuration entry, we are going to
use a simple POJO provided by the com.exoscale.carassembly.config.api.model.Config
class:
@Path("config")
public interface ConfigService {
@GET
@Consumes({ "application/json", "application/xml" })
@Produces({ "application/json", "application/xml" })
public Config get(@QueryParam("key") String key);
@DELETE
@Consumes({ "application/json", "application/xml" })
@Produces({ "application/json", "application/xml" })
public Config remove(@QueryParam("key") String key);
@POST
@Consumes({ "application/json", "application/xml" })
@Produces({ "application/json", "application/xml" })
public Config add(Config config);
}
mvn package
And then install it and start it as follows in the two Karaf runtimes (through the
Karaf consoles):
install file:///D:/config.api/target/config.api-1.0.0-SNAPSHOT.jar
start com.exoscale.carassembly.config.api
Alternatively, Karaf gives you a bundle ID you can use to start the bundle with the
start command.
You can verify the bundle is started by investigating runtime modules with the list
command.
The Maven configuration that provides the build information for the module is
available here.
The annotation is an easier way to define OSGi service metadata than writing
service XML files. In fact, it generates the files for use. In this particular case
that is OSGI-INF/com.exoscale.carassembly.config.GeneralConfigService.xml. It also
provides additional attributes used by the OSGi Remote Service feature (in our case
CXF DOSGi):
@Path("assembly")
public interface BodyAssemblyEndpoint {
@POST
public void assemble();
}
Build and deploy the body assembly service on the second Karaf instance running on
port 9992.
log:display
We are going to first create an entry in the distributed configuration service that
is going to specify the color of the car body, then trigger the body assembly
service that writes status back to the configuration service, and finally review
the status from the configuration service:
You should see the following result from the car body assembly:
{"key":"assemblyFinised","value":"true"}
It will be way better to just inject the configuration service as a regular OSGi
service and let Karaf take care of the service discovery out of the box.
In addition, we need to install the following zookeeper CXF features in the Karaf
runtimes:
Then simply restart the Karaf instances and you are all set for distributed service
discovery through Zookeeper.
Summary
We have implemented a complex style of architecture that is suitable for large
scale systems using the OSGi framework in conjunction with the microservice
paradigm.
While our example is simple, it models an architecture that can span hundreds of
microservices with multiple modules on each.
OSGi remote services provided out of the box distributed service discovery.
Implementing concepts such as load balancing, fault tolerance and any of the others
already mentioned can be done similarly to how we�ve introduced a centralized
configuration service in the architecture.