Monolith to Kubernetes Microservices While Keeping Your Humanity
Cloud Native is billed as some incredibly sleek, sexy technology. Dashboards with transactional tracing that paints a technicolor rainbow of perfect orchestration of the entire business, replete with a surgically perfect doll of a human being in a suit in their premier-class hyperloop seat on their way to their flight to Mars.
The truth is much darker, gritter, seedier, and involves a lot more command line. Yes, the future of Cloud Native is much, much more cyberpunk than the shiny plastic veneer of the dashboard. And for too many organizations, the final product looks a lot less like a transcendently integrated AI and lot more like those Cyberpunk 2077 memes that have been floating around.
This blog series is going to talk about migrating a monolith to a microservices-based architecture.
Part One: Just because you can, doesn’t mean you should
The first part of the series is going to talk about an important lesson we’ve learned about containers: just because you can put it in a container, doesn’t mean you should.
We’re all eager to embrace the Cloud Native mindset, described by OpenLogic director of product management, Arturo Suarez, in a past blog post. I recommend you give that article a read if you’re unfamiliar with Cloud Native as a practice!
A customer’s monolithic application
I recently visited a customer in Europe for a three-day summit with their architecture team to tackle a common thread that we’ve been seeing across our OpenLogic team.
The customer had a monolithic application and the team determined that they couldn’t practice DevOps with a monolith. Practicing DevOps, however, was going to make everyone’s lives better.
Their executive team was investing in the development of their product, and there was a strong alignment on DevOps being the future. The architectural team had already made some excellent choices: Kubernetes for orchestration, Jenkins for CI/CD, and an emphasis on Enterprise Integration Patterns.
Related Post: Introduction to Enterprise Integration Patterns and Apache Camel by chief architect Justin Reock
This team is a prime example of the team that wants it all. They want the tracing, they want the dashboarding, they want the cool robot laser arm, and they’re lined up for the upgrade at the cyber clinic yesterday, credit chit in hand.
However, nobody’s ready for the uncomfortable questions about how the cool robot laser arm affects your love life, though. In other words, cultural and business buy-in are extremely important, especially on exactly how that monolith gets transformed into a microservice.
With the extremely fast pace of a Cloud Native frame of mind, the old Perl adage of “there's more than one way to do it” (TIMTOWTDI) now applies to every layer of a transaction, from virtual networking to exactly which “Kubernetes” you’re using.
The one question to ask
Before your team gets too far down the rabbit hole, let’s ask one question of the service that’s going to be created:
Does this belong in a container?
Some operators are going to scoop the brains out of every workload they have and place them directly into a container. Not pausing to think whether or not they should, only emboldened by the power that they could.
Some workloads just aren’t ready to be brains in a jar, ghosts in a shell, connected to the higher consciousness of orchestrated containerization in Kubernetes.
Hard and fast: production RDBMS doesn’t belong in a container, and integration doesn’t mean ops, it means dev. Do not believe your 128GB, 64-thread Oracle workload is going to don its Thompson EyePhones and Johnny Mnemonic its way into production readiness. If your workload cannot handle disappearing without a trace, it is not a Kubernetes workload. Let’s take a look at a screenshot of the Kubernetes dashboard, and look at a workload that’s been running for a while.
Figure 1: The Kubernetes Dashboard, highlighting status, uptime, and restarts metrics
Yes, “restarts” is a real metric, and yes, it will tick up, and no, it’s not always graceful.
Ask your Oracle ops team the current uptime on your pet database. Observe the grand, venerable status of the months of uptime this represents. Ask them to pull the power out of the back to reboot it, just for kicks, not as a Disaster Recovery exercise. This might illustrate why that, just because you can, doesn’t mean you should.
The pets versus cattle problem
This is what’s known as the pets versus cattle problem in cloud computing. Let’s pull out some slides that I’ve specially annotated for this cyberpunk special edition. Let’s illustrate that just because you can, doesn’t mean you should.
The pets versus cattle problem is summed up as “only put survivable workloads in containers.”
While an engineer’s first thoughts might be that only “throwaway” workloads such as batch workers can make their way into Kubernetes, what I’m referring to here is multi-master, highly-available workloads that can negotiate the joining and leaving of a cluster.
Cassandra, ElasticSearch, and Kafka are examples of applications with these properties. They are all high performance, IO-intensive workloads that work great in production Kubernetes because they can survive reboots, and gracefully handle joining and rejoining. They understand concepts of idempotence and high availability, and work with products like Zookeeper or their own cluster management to ensure that everything keeps moving along gracefully as nodes come and go.
This doesn’t mean your workload needs necessarily to be elastic, but it does need to be survivable, ephemeral, transaction-aware, idempotent, and most importantly, well understood on your team. This is why integration will not mean ops, it will mean re-architecting your entire suite of applications.
An example of an application that doesn’t belong in a container? Strangely, while there exists a Wildfly Docker image, the Java application your team has written for Wildfly may not be ready. If your team hasn’t done its homework on slimming down your image for speedy restarts, and really understands how things like session information is being replicated across your nodes, you might be able to use operations techniques like configuration to move your app into the Docker container.
However, if your application anything like the majority of the Wildfly applications we’ve supported in the past, it's very stateful, highly monolithic, and is more active/passive than ready to be load-balanced (active/active). We’ll cover more on untangling applications like this in the next part of the blog series.
Next post in this blog series
In part two of this blog series, we’ll take a look at a real example of how we can use technologies like Camel, Kafka, Spark, Cassandra, and Kubernetes to build an application ecosystem where the remnants of the monoliths we tear down are first class citizens that can continue to serve the business in a cost-effective manner while uplifting developers into DevOps enlightenment.
Looking for support to migrating a monolith to a microservices-based architecture?