Learn more >
by Carsten Bornert, Kim Clark | Updated June 28, 2019 - Published August 31, 2017
API ManagementContainersMicroservicesCloudHybrid Cloud
Archived date: 2019-08-30
In a time when servers took weeks to provision and minutes to start, it was fashionable to boast about how long you could keep your servers running without failure. Hardware was expensive, and the more applications you could pack onto a server, the lower your running costs were. High availability (HA) was handled by using pairs of servers, and scaling was vertical by adding more cores to a machine. Each server was unique, precious, and treated, well, like a pet.
Times have changed. Hardware is virtualized. Also, with container technologies, such as Docker, you can reduce the surrounding operating system to a minimum so that you can start an isolated process in seconds at most. In this new, typically cloud-based infrastructure, scaling can be horizontal, adding and removing servers or containers at will, and paying for only what you use. With that freedom, you can now deploy thin slithers of application logic in minimalist runtimes into lightweight independent containers. Running significantly more than just a pair of containers is common and limits the effects of one container going down. By using container orchestration frameworks, such as Kubernetes, you can introduce or dispose of containers rapidly to scale workloads up and down. These containers are treated more like a herd of cattle.
The analogy of “cattle not pets” is now well established in the application space, especially in relation to the microservice application architecture. However, as explained the “Lightweight integration: Using microservices principles in integration” blog post, it makes just as much sense to also consider this approach in the integration space.
This article focuses on the best practices for deploying IBM® App Connect Enterprise (previously known as IBM® Integration Bus) by using a “cattle” approach in containers. But first, you need to better understand the potential challenges that deployment as a “pet” poses.
Let’s examine what pets currently look like and whether anything looks familiar from a traditional integration viewpoint. In the analogy, if you view a server (or a pair of servers that attempt to appear as a single unit) as indispensable, it is a pet. In the context of integration, this concept is similar to the centralized integration topologies that the traditional approach has used to solve enterprise application integration (EAI) and service-oriented architecture (SOA) use cases. The analogy lists additional characteristics that also map directly to centralized integration topologies as shown in Table 1.
While this article focuses on moving to a more cattle-like approach, the more traditional pet-like approach also has benefits that might be more challenging to achieve with cattle. For a quick comparison, see Figure 1, which shows some of the characteristics that vary between cattle and pets.
Integration scenarios vary in the characteristics that they need. With modern approaches to more lightweight runtimes and containers, you have the opportunity to stand up each integration in the way that is most suited to it. You do not need to assume that, just because a cattle approach suits many integrations, it will suit all of them. You can use both approaches and even add hybrid options as required.
A strong desire exists to move away from centralized deployment of integration hub or enterprise services bus (ESB) patterns where all integrations are deployed to a heavily nurtured (HA) pair of integration servers. The aim is to move toward more modern and lightweight topologies and draw on the benefits of a microservices architecture:
Simplistically, as shown in Figure 2, this shift means breaking up the more centralized ESB runtime into multiple separate and highly decoupled run times.
However, you need to recognize that the change involves more than just breaking out the integrations into containers. A more cattle-like approach must exhibit many, if not all, of the characteristics in Table 2.
The “12-factor integration” blog post in the IBM Integration Developer Center explains how you can use IBM App Connect Enterprise to implement integration requirements by following the principles of 12-factor applications. It also explains how you can achieve many of the characteristics in Table 2.
To gain the benefits of this more fine-grained approach, you must consider how best to enable integration runtimes to be more lightweight and independently packaged. Thanks to the progressive enhancements in IBM App Connect Enterprise to remove dependencies and simplify installation, IBM App Connect Enterprise is now well suited to deployment in a containerized manner. It support such technologies as Docker, which has become an industry standard, and a container orchestration tool, such as Kubernetes.
The question then remains: how granular should the decomposition of the integration flows be? Although you can separate each integration into a separate container, do not assume that you can take such a purist approach. The goal is to ensure that unrelated integrations are not housed together. That is, a middle ground with containers that group related integrations together (as shown in Figure 3) can be sufficient to gain many of the benefits that were described previously. You target the integrations that need the most independence and break them out on their own. Alternatively, keep together flows that, for example, share a common data model for cross-compatibility. Changes to one integration can result in changes to all integrations, and any change to the shared data model might require regression testing across the complete set.
However, you must also make the other changes that are listed in Table 2 for the characteristics of cattle. Just breaking up a large pet into smaller pets does not in introduce any benefit. You must also ensure, for example, that you make them disposable and treat the infrastructure as code.
A Docker container is what you see at run time. Something running in a container acts as though it is running in its own operating system, but it is much more lightweight. In reality, many containers can run side by side on one operating system, each in their own namespace. Consider the smallest amount of software that you can have in a container to run an integration.
Figure 4 shows a summary of a 12-factor integration that is running a Docker container with IBM App Connect Enterprise. The container is based on the core Ubuntu operating system and contains the IBM App Connect Enterprise binary files. The code realizes the integration functions.
On the surface, this container might not look different from what you might expect to see within a traditional server. However, it has one fundamental difference: the container houses few integrations, perhaps only one. In IBM App Connect Enterprise terms, you might have only a single message flow or a suite of message flows that all work together to perform one integration. For example, they might implement a single API or handle the processing of a certain type of message. This integration is isolated and therefore, has its own dedicated set of IBM App Connect Enterprise binary files and an operating system for significant flexibility. For example, you can choose to use the latest version of IBM App Connect Enterprise just for one integration to take advantage of new features. You don’t need to regression test other integrations that are running on older versions as you might have to if they all ran on the same centralized server.
The illustration in Figure 4 also shows configuration for each of the previously mentioned components. Let’s look at some examples to better understand this type of configuration:
Although you can apply various settings at different levels, this configuration is necessary only for the specific integration use case that the container addresses. Keep in mind the “Each container should have only one concern” guideline, which is a key differentiator between integration pets and cattle. In contrast, integration pets are taught various tricks (integrations) over time with the accumulated interwoven and complex configuration to match. Containers that represent cattle are much lighter and more specialized.
Now that you know what is inside the container, let’s focus on how to build containers. Docker containers are created based on images. Images are created at build time by using the Docker build command and instructions in the form of a Dockerfile. Each instruction in the Dockerfile results in changes to a filesystem layer, and all layers together make up the image. You can then deploy and run an image as a container.
After you build an image, everything inside the container is ready and available when the container starts. The running container has read access to all the files that result from the image layers. It also has an extra read-write layer that is added when the container is created and therefore, is not part of the image. The article “Visualizing Docker Containers and Images” explains this scenario well.
When you map this image to the building blocks of the 12-factor integration container, you will see a few obvious candidates to include in the image. All images must begin with a base operating system layer. Ubuntu is common and is supported by IBM App Connect Enterprise. You must also add the IBM App Connect Enterprise binary files. You must also perform certain activities, such as creating the non-privileged user. Because these files don’t change, you can easily include them in the instructions in the Dockerfile. In fact, a Dockerfile for IBM App Connect Enterprise exists on the GitHub repository that includes these instructions.
What about the integration code itself and the configuration? Should you include them in the image too? This question is one of the first big departures from a traditional server toward treating servers as cattle. If you include the integration code in the image, you change the meaning of deploying to an environment. Traditionally, you might deploy the integration code to an existing, heavily nurtured, already running integration server. Here, a deployment package can provide the integration code, its own instance of the IBM App Connect Enterprise binary files, the operating system, and all the configuration that goes with it. A truly self-contained component is ready to be started, scaled, or destroyed completely in isolation from any other integrations.
How do you decide between what to include or configure at build time (in the image) versus at run time after the container is created and started? You must first consider the answers to these questions:
Consider the following example of a simple integration use case that exposes data from a database table as an HTTP REST interface. Starting from nothing, you need to perform the activities that are shown in the following figure.
Lightweight IBM App Connect Enterprise: The IBM App Connect Enterprise runtime is evolving to become more lightweight. Some of the activities in the diagram are likely no longer necessary in the newer version of the product.
Each activity that is started at run time rather than at build time adds to the time it takes before the integration is up and running. A fast startup time is important for the disposability aspect of 12-factor applications and is a key benefit of containers over virtual machines (VMs). It is used to scale elastically with the workload, rebalance if infrastructure failures occur, and facilitate continuous delivery. You want to do everything you can to reduce the container startup time by building whatever you can into the image.
However, loading everything into the image is not as simple as it might appear at first. The credentials for the database access or the Transport Layer Security (TLS) certificates from the previous example can differ between the development environment and production environment. This situation can lead you to have to choose between running environment-specific configuration steps at startup with a slower uptime or creating multiple images, one for each of the different environments with a faster startup time.
Clearly, the complexity of having many images to manage has some cost. However, if startup time is critical, it might be necessary. Regardless of the option that you choose, the resulting container is still much more disposable than a traditional pet style server.
Now that you understand the basics of the filesystem layering approach of building Docker images, let’s delve a little deeper into its practical implications. The previous section briefly mentions the use of Dockerfile instructions to build images. It is technically possible to realize the installation and configuration of the components from Figure 4 into a single Dockerfile. The file might start with a line that references the base operating system (FROM ubuntu:14.04) followed by a long list of extra instructions. You basically have a single Docker image that implements the integration functions as shown in Figure 6.
However, a much more realistic approach might spread the instructions across multiple images that each reference each other as illustrated by Figure 7.
This approach can lead to more images overall, but some of them are reusable. For example, you can use “intapp base” as the basis for all applications with similar prerequisites. When it comes to deciding how to break down the full list of instructions and spread them across multiple images, you can apply the following guidelines:
These guidelines help get you closer to building Docker images with IBM App Connect Enterprise in a predictable and reliable process. While the process is always the same, several important characteristics shape the content of each image. Such requirements as whether you need a local MQ queue manager, shared caching, logging, or error handling framework can also impact the image. Addressing all of those requirements in any significant depth is too much to cover in this article. Some topics, such as incorporating IBM MQ, might result in multiple images in different branches of a hierarchy, such as the one shown in Figure 8. You can read more about building such an image in the “IBM App Connect Enterprise and Docker: Tips and Tricks” blog post. Watch for future complementing posts about addressing some of the others.
Now that you have established a process for building cattle-like images, let’s look at the bigger picture. Figure 8 shows an example of a hierarchy of images for five integration applications. You can see that the number of nodes increases, particularly toward the last two levels on the right.
This image shows two important inflection points that drive the overall number of images and therefore, the effort that is required to manage or maintain them:
If you chose to include the integration applications in the image and have separate images for each environment, the total number of images jumps substantially. Imagine that you have 100 integrations to deploy to five environments. You now have 500 images rather than one image to which you deploy different integrations at run time. However, those images can be stopped, started, or scaled almost instantaneously and require no further nurturing at run time. More specific images move you closer to the cattle direction. Fewer more generic images move you back toward the pet direction. Yet, all options are valid. It all depends on your requirements around resiliency and the ability to scale quickly, balanced with the management implications of many images. Also, some implications might exist on storage requirements for many images. However, because of the layering system that is employed by Docker, the implications might not be as large as you might think.
The example of certificates and credentials in this article also raises the question: how do I get potentially sensitive information, such as passwords, into the container? Orchestration tools, such as Kubernetes or Docker Swarm, provide functions to make this process easier. However, you can use specialized tools, such as Hashicorp Vault, to manage secrets and make them available to containers in a secure and controlled manner. This topic is beyond the scope of this article, but is worth considering exploring in more detail in a separate post.
As is often the case, taking a radically new approach to a problem can lead to more questions than answers. Although breaking down a large monolithic integration topology can result in significant benefits in terms of agility, scalability, and resilience, it also raises inevitable questions that are familiar from the world of microservices. Let’s visit each of these concerns briefly.
How will you manage the much larger number of running servers and their associated containers?
Container orchestration refers to managing the number of containers to deploy, when to deploy more containers based on workload, and enabling auto-recovery. The current favorite for this capability is Kubernetes, and an introduction to its use with IBM App Connect Enterprise is in this post. The IBM Container Service was recently enhanced to provide management based on Kubernetes as described in this post.
IBM App Connect Enterprise on Cloud uses Docker in the background. IBM App Connect Enterprise on Cloud is an excellent option if you prefer to let IBM manage how to stand up containers and orchestrate them. It abstracts you from day-to-day infrastructure concerns so that you can focus on your integration design and implementation.
How can I securely pass confidential information, such as user credentials, to servers that are transitory and cloud based?
Again, Kubernetes provides mechanisms to enable safe storage and retrieval of this sensitive data known as secrets. For more information, see also the “Zero to Kubernetes on the IBM Cloud Container Service” blog post.
How do I monitor and diagnose problems in a distributed set of components without interrogating each one individually?
Indeed, how do you even find out which components a request passed through? A common solution is centralized logging, where all containers use a standardized mechanism to push logs to an event stream that represents the audit trail of the activity from all containers. Many common capabilities are possible for interpreting logs. IBM App Connect Enterprise enables logs to be pushed to standard outputs so that they can be picked up by common capabilities available in most container orchestration platforms.
Moving to more a lightweight cattle style integration clearly offers tempting benefits in terms of agility, elastic scalability, and more individual resilience models. This article explored key concepts and provided recommendations around the construction of images. Containerized integration marks a significant turning point in integration topologies, and there’s plenty more to say. Keep an eye out for more posts like this by following the IBM Integration Developer Center blog.
Thank you to the following people for their input and review of the material in this article: David Arnold, Peter Broadhurst, Rob Convery, David Currie, Geza Geleji, David Hardcastle, Peter Jessup, Rob Nicholson, Ben Thompson, and Jörg Wende.
September 2, 2019
March 19, 2019
Back to top