Java, you may have been told, is not cloud-native. The reason why, you may have also heard, was simple: Java is bound to middleware which assumes an n-tier architecture that cloud-native architecture doesn’t have. Depending upon whom you’re listening to at the time, cloud-native architecture may either eschew the very essence of middleware or be the next generation of middleware.
The dichotomy has to do with dependency. One of the goals of the 12-factor refactoring method for scalable, cloud-native applications is to eliminate implicit dependencies in order to enable unimpeded scalability of services. Typical middleware such as Red Hat’s JBoss and IBM’s WebSphere is designed to be an implicit dependency — what their vendors used to call “reliability.”
For version 3.5 of OpenShift, which premiered Thursday, Red Hat is introducing what it calls cloud-native Java — specifically, as a container image in addition to the existing VM engine. Rather than a language that looks kind of like it might have been inspired by someone who saw Java before at a conference, this is a genuine effort to make veteran developers feel somewhat at home in the strange realm of microservices.
“There’s a lot of push to rename or rebrand things as ‘cloud-native,’” remarked Brian Gracely, Red Hat’s Director of Product Strategy, speaking with The New Stack. “That’s all well and good, and it plays great at meetups and things like that. But customers are saying, ‘Look, here’s the realities of my world: I have valuable Java developers who have evolved over the last five, ten, maybe fifteen years, and we don’t have any interest in getting rid of those folks. They do a great job, whether they’re supporting current applications or building applications. We want platforms that are going to help us go forward.’ We don’t see a lot of folks saying, ‘We’re a huge Java shop, and we’re just abandoning Java altogether.’”
The Refactoring Factor
Thursday’s introduction of cloud-native Java to OpenShift, which is Red Hat’s container orchestration package, is the latest step in the company’s ongoing effort which began in November 2015 to refactor the Java ecosystem, in stages, for containerized PaaS.
Java is not new to OpenShift, of course, having been part of the platform since its beginnings. But the structure of Java applications has historically relied upon implicit dependencies, which is why essentially the same syntax applied to stateless applications has been called a different language (Scala). Countless new languages have arrived on the scene to tackle the problem of refactoring standard, dependency-laden Java applications for modular and distributed systems, but they all appear better suited to distributed systems than standard Java (or, in fairness, any native .NET language).
Mike Barrett, Red Hat’s principal product manager for OpenShift, told us that developers’ impressions of “cloud-native” with respect to Java may fall into one of two buckets. One involves the creation of a fat jar — a Java package that includes all of its dependencies. Usually, that’s fine if the developer’s okay with limiting her deployment options, Barrett said — for instance, if it’s going to Spring Cloud or straight Kubernetes, but no place else.
The second bucket, by contrast, holds veteran Java developers’ expectations for incorporating the familiar tools they expect, like the Maven project manager, with these CI/CD pipeline managers they’ve been reading so much about, like Jenkins.
Neither method is wrong, or more right than the other, said Barrett. They are two valid methods for Java developers to build working applications, only up to now, both methods have limited their deployment options. He asserted that so-called “cloud-enabled” platforms typically force developers to run their critical services — for instance, persistent databases — outside themselves, probably because those services require different protocols, or use specific IP addresses or ports, or perhaps impose persistence requirements. His assertion implied that the “cloud-enabled” moniker may be just a cover-up for only being capable of addressing one or the other bucket halfway.
“We have never taken that approach in OpenShift,” said Barrett. “We have always tried to design deployment patterns that pretty much take anything that you can run in a container.” To that end, he said, Red Hat’s entire JBoss portfolio is now being made available for container images, for selective binding to containerized Java.
The Stack for Stacks
I asked Barrett and Gracely to name three things that such a developer will still need to learn upon immigrating to OpenShift, even with all the effort Red Hat has undertaken to make them feel at home.
“People need to realize that their applications will be very elastic,” responded Barrett. “Meaning, the platform itself will scale that application up and down. So as you’re driving towards your primitives in your code, you need to keep in mind that the instance counts, and where the information is coming from is going to be a lot more volatile than in the past.”
Scope is a very important concept in Java. Java’s idea of a stack is very different from the kind on our masthead. It’s memory that is allocated to a specific Java thread. By contrast, a heap consists of memory that’s shared by all threads, and from which array variables and class instance variables are allocated. It’s a very stable structure for a contiguous, self-contained virtual machine… but not for highly distributed systems.
When an instance of a Java application is replicated across data centers, availability zones, or geographies — an event that can no longer be considered occasional or accidental — any connection that application has to a data source, feed, or stream, Barrett pointed out, may need to be continually vetted for consistency.
The Discovery of Discovery
Brian Gracely added one underappreciated fact of this new realm of programming: that the orchestrator (in OpenShift’s case, Kubernetes) provides key system services automatically that no longer have to be coded manually. Principal among these is service discovery.
“Now that these capabilities are potentially exposed to Java developers,” said Gracely, “they’re beginning to ask themselves, ‘Do I want to continue to only use the native services that are within my Java framework, whether it’s an older or newer one?’ Or, they’re starting to explore, ‘Should I take advantage of something like Kubernetes service discovery, or one of the other development patterns that come out of Kubernetes? Do I want to write code that’s entirely bound by the capabilities of this Java framework, or might it help me in some way to leverage what’s native to the platform?’”
For developers who’ve grown accustomed to relying upon Java frameworks from JBoss and Spring to extend the capability of their languages, now there’s a platform supporting them, performing functions that don’t require such extensions. It’s a co-existence that Java developers may not be accustomed to yet.
Another of these services from which new development patterns may sprout forth (I’m consciously avoiding the word “spring” in this context) is StatefulSets, Kubernetes’ ongoing experiment, beginning with version 1.5, for declaring pods whose containers need persistent storage and a more measured approach to scaling. While OpenShift has supported stateful instantiation in the past, for version 3.5, the platform is beginning its support for Kubernetes’ suggested standard — which, folks will admit, is a moving target for now.
Prior to StatefulSets, explained Barrett, it was still possible for a Java application to share storage across multiple instances, or a database that needs to be sharded while allowing each instance to have its own block storage. But to convey these configurations to Kubernetes, and then expect the orchestrator to account for CPU or memory utilization, or to automatically add instances when necessary, was not possible.
“Now with StatefulSets, we have the ability to connect those two worlds,” he told The New Stack. “We can teach Kubernetes about more complexity than just adding instances — ‘Stop and do X, Y, Z first, then add the instance.’”
This type of situation crops up, Barrett continued, when the developer of a cloud service is building deployment features for use by tenant customers. It’s easy enough to hard-code the precise details of an application’s deployment within a data center — and indeed, veteran Java developers are accustomed to hard-wired configurations. But converting that hard-wiring into a template whose details are variables to be filled in by customers was impossible without some type of interface between the staging environment and the IT operator.
So Red Hat is opening up Kubernetes’ StatefulSets to Java developers. In so doing, it’s letting them continue to do what they’ve done before.
“That’s that PaaS concept. At the same time, we don’t to lose the container platform concept,” said Mike Barrett. “We offer that dual relationship in OpenShift, leveraging Kubernetes, where some other providers of Kubernetes mainly do one of them… We have an ability to ask for the code if you have code. If you don’t want to learn anything about containers or Kubernetes, that’s perfect. You just fill out our wizard that’s very oriented to you as a Java developer, and maybe you don’t even look at our user interface. Maybe you’re in your Eclipse IDE. We have those integrations, and you can still take advantage of those very complex things in Kubernetes.”
When two architectures are so radically different from one another, the most we can expect from a platform on one side is to meet the other halfway.
Red Hat is a sponsor of The New Stack.
Title image of the Manhattan Bridge under construction in 1909, in the public domain.