Deployment of SOA infrastructure
After designing and realizing of the SOA infrastructure, we typically meet the challenge of its deploying. Choosing of the deployment approaches depends on various criteria, including the system architecture, the deployment frequency, the level of automation, and so on.
In this article, I would like to discuss the main approaches for deployment of the SOA infrastructure. To illustrate the practical aspects, I will use Apache ServiceMix as the platform and Docker as the virtualization tool.
NB! You can get the example source code from the GitHub project: https://github.com/hrytsenko-sigma/smx-github.
The purpose of this article is to describe the practical approaches for deployment of the complex systems in different execution environments.
Development and integration of the enterprise systems implies working with the following main deployment artifacts (Figure 1):
- Component – a modular part of the enterprise system.
- Environment – a set of containers required to run the components.
Figure 1. Artifacts
The deployment cost of these artifacts affects the overall cost of the system. However, this impact varies depending on the execution environment and the system architecture.
For example, the impact of the environment deployment cost depends on the deployment frequency and on the level of automation. Therefore, this impact will significantly increase between the development environment and the production environment for the distributed system.
The modern Java ecosystem encompasses various approaches for the deployment of those artifacts. In this section, I will describe the most known of them. In the following section, I will show how these approaches complement each other.
A bundle is the small artifact that contains only the component itself and does not contain its dependencies. Therefore, the execution environment is responsible for providing all the required dependencies.
A good example is a web application for a Java EE application server. When such web application requires some dependency, like the RESTful web services framework, it declares this dependency, but does not include it. Then, the application server provides the required dependency (Figure 2).
Another example is the bundle for the OSGi container. Again, when the bundle requires some dependency, it only declares this dependency. Then, the OSGi container provides the required dependency.
In both cases, the dependency should be present in the execution environment to start the bundle.
Figure 2. Bundle
With this approach, we shift the main deployment cost to the environment deployment.
I recommend this approach for the development, because it provides an easy way to deploy the system by parts. However, I do not recommend this approach for the production, because it is nonresponsive to the growth of the system in terms of complexity (number of components) and scaling (number of nodes).
A package is a medium artifact that contains one or more components and their dependencies. Therefore, the execution environment may not contain any dependencies prior to the package deployment.
A good example of a package is Spring Boot or Dropwizard application. When such application requires some dependency, like the RESTful web services framework, it includes this dependency. Then, the execution environment obtains the required dependency from the packaged application (Figure 3). Note that Spring Boot or Dropwizard application can be a relatively large artifact, depending on the number of dependencies.
Another example is a feature for the Apache Karaf. Such feature may include a set of bundles and a set of dependency features. Then, the execution environment is responsible for installation of all resources of the feature, including dependencies. Note that the Apache Karaf feature is a relatively small artifact, because it defines dependency features, but does not include them.
In both cases, the execution environment can fetch dependencies from the package during deployment.
Certain packages (for example, Spring Boot or Dropwizard application) may also include a container (web server). However, the execution environment is still responsible for providing a top-level container (Java virtual machine). Therefore, the package deployment still requires the preliminary environment deployment.
Figure 3. Package
With this approach, we reduce the deployment cost of the environment deployment and increase its usability.
I recommend using this approach for the production with a limited number of nodes. It is because this approach is still nonresponsive to horizontal scaling. In addition, I recommend creating separate packages for different execution environments to reduce the deployment cost (a single package per environment).
An image is a large artifact that includes components and an appropriate execution environment.
A good example is a Docker image. For example, such image may include the OSGi bundle, the OSGi container, and the Java virtual machine (Figure 4).
Figure 4. Image
With this approach, we shift the main deployment cost to the system deployment, because the execution environment would only support Docker.
I recommend using this approach for the production with an unlimited number of nodes and a high level of automation. However, this approach implies additional overhead for the development.
Assume that we have a SOA infrastructure that consists of several services. The execution environment includes the ESB (Apache ServiceMix), the OSGi container for the services (Apache Karaf), the integration framework (Apache Camel), and the RESTful web services framework (Restlet). As the build automation tool, we use the Apache Maven.
The Apache ServiceMix includes the Apache Karaf and the Apache Camel, while the Restlet framework is the dependency of services.
Our goal is to create deployment artifacts for the development and for the production.
At the first step, we create a separate OSGi bundle for each service. The minimal bundle includes:
- The build script.
- The Blueprint configuration that contains the definition of the service.
In addition, a bundle may have an external configuration. Such configuration is the dependency. Therefore, we deploy the configuration file as any other dependency.
To create the OSGi bundle for the Apache Karaf, we can use the Apache Felix Maven Bundle Plugin.
The bundle deployment includes the following steps (if the execution environment is available):
- Install the dependencies for the bundle (the Restlet framework).
- Deploy the bundle configuration into the container.
- Build the bundle.
- Deploy the bundle into the container.
If we have several bundles, then we should repeat these steps for each of them.
During the development, we frequently execute the bundle build and deployment, but rarely execute other activities. In addition, during the development we typically work with only one bundle at each point of time.
Therefore, after the first step, we create suitable deployment artifacts for the development.
When we move to the production, we typically have several environments. For each environment, we have:
- A predefined set of bundles of the predefined versions.
- A predefined set of configuration files.
Using of bundles in this case is too expensive and risky, because we should track many deployment artifacts and their dependencies.
Therefore, at the second step, we create a package (i.e., the Karaf feature) for each environment. The minimal package includes:
- The build script.
- The feature configuration.
- The configuration files (can be preliminary installed into the Maven repository).
- The bundles (can be preliminary installed into the Maven repository).
The feature configuration defines the set of bundles and configuration files, their versions and dependencies.
To create the Karaf feature, we use the Karaf Maven plugin. Depending on the complexity of the build script, we also use the Apache Maven Resource Plugin (to interpolate properties in the feature configuration and in the configuration files) and the Apache Maven Install Plugin (to manage the configuration files and the bundles in the Maven repository).
The package deployment includes the following steps (if the execution environment is available):
- Build the packaged bundles.
- Build the package.
- Deploy the package into the container.
The package deployment requires more resources in comparison to the bundle deployment. Firstly, it requires building of all bundles, then it requires fetching of all dependencies during the deployment, then it requires deploying of all bundles.
Therefore, after the second step, we create suitable deployment artifacts for the production. However, these artifacts are less suitable for the development.
If the number of environments in production is continuously grows (for example, because of the horizontal scaling), then we may face a significant increase of the deployment cost. This is because the bundle deployment and the package deployment require the preliminary environment deployment.
Therefore, as the third step, we create an image of the SOA infrastructure that includes both the containers and the components. Typically, we create several images to decrease the cost of the image build.
For example, the base image includes an instance of the Apache ServiceMix, while the derived image additionally includes the package and other run-time resources (for example, security certificates). In this case, we decrease the image build cost for different environments.
To define and build images, we can use Docker. The minimal image configuration consists of a single Dockerfile that contains all the commands to create an image.
The image deployment includes the following steps:
- Build the package.
- Build the derived image that includes the package.
- Start the container from using the derived image.
The image deployment requires a high level of automation, and it is suitable for the production of the distributed systems. In addition, I recommend using images for the acceptance testing, because they significantly decrease the chance of misconfiguration.
Therefore, after the third step, we have the deployment artifacts to cover most of deployment cases.
Holly Cummins, Timothy Ward. 2013. Enterprise OSGi In Action. Manning publications.
Jeff Nickoloff. 2016. Docker in Action. Manning publications.
Johan Edstrom, Jamie Goodyear, Heath Kesler. 2013. Learning Apache Karaf. Packt Publishing.