This week I had the privilege of hanging out with the local Vegas Docker community and spoke at the Las Vegas Docker Meetup. It was pretty refreshing to get out of the Bay Area and to spend time with Devs, Ops, and DevOps practitioners in the city of lights. Thanks to the folks at InfoSiftr for fostering such a collaborative and open-minded community (they didn’t even balk when I demoed Kubernetes instead of Docker Swarm!)
The goal of my talk was to discuss some of the challenges that containers and container driven architectures like microservices can place on Continuous Delivery and to demo some cool features in ElectricFlow that address these head on.
Wait a minute… Challenges? Containers? I thought new technologies like containers, Kubernetes, and microservices were a silver bullet!?
Well, as is often said – something’s greatest strength can also be its greatest weakness.
Why Containers are Good for CI/CD
The benefits of containers, especially when speaking to a room full of Docker users, is clear.
Containers provide a faster and more portable means of deploying applications than VMs or traditional apps. They also ensure more consistency across environments, making deployments more reliable and repeatable. Container orchestrators like Kubernetes, Docker Swarm, and Mesos provide additional load-balancing, networking, and service discovery capabilities that further augment containers’ benefits. All this means developers and architects can afford to create more granular, distributed, redundant, and service based applications based on new architectures like microservices.
Obviously, I didn’t have to spend much time touting the benefits of containers to Docker enthusiasts. But the benefits for CI/CD (how we build and release that code) are sometimes less discussed. Some key benefits are:
- Environment consistency enables shifting left and releasing more reliable code.
- More granular applications promote smaller and more autonomous teams, which typically leads to more productivity. One of the attendees made the point that developers prefer to focus on what they’re best at (coding) and what they need to get done (resolving a story in Jira). They don’t like to have to worry about other systems that may distract them from ideating on the code that’s right in front of them. The degree to which they have to “think about the bigger picture of how the code is built, tested and released” can be a time-sink and a distraction.
- More granular applications also promote associating individual release pipelines with each microservice or container, allowing teams to design pipeline tooling to be specific to the individual component being released. This makes each pipeline more effective at ensuring an app component can be successfully deployed into production.
It’s important to note, however, that a migration to containers and microservices is not a silver bullet – for many teams, building and managing a monolithic pile of poop can sometimes be easier than managing hundreds of micro-poops.
Four Challenges and How to Address Them
As I said, my real goal was to talk about some of the challenges and how we’re addressing them. Ironically, many of these challenges rise from the very strengths of containers and microservices. Here are four key challenges and some cool new features in ElectricFlow that address them head on.
Container Challenge #1: App Complexity.
Monolithic applications are complicated, but microservice applications are complex. What’s the difference between complicated and complex? Most notably, complex systems are generally less deterministic, which makes them harder to debug. While it’s true that individual microservices are easier to unit test, a failure in a microservices based application can be challenging to remediate because the source of the failure is hard to identify. There’s a great tweet that’s been going around for a while which likens fixing a failure in a microservices based app to solving a murder mystery.
To address this, ElectricFlow recently added a feature called “Smart Map Topology” that provides a visual representation of your microservices app (Kubernetes cluster, etc.) that is not possible with any management software today. It shows a live view of all your apps clusters, pods, services, containers, and, most uniquely, which specific environments each application is deployed to. It also provides live feedback, including deployment issues. This is hugely helpful with managing complexity, as you can view a single application, see the environments it’s deployed (say QA, Staging, and Prod) and where there may be deployment issues.
In fact, as I was recently developing a demo application, I continued to get errors with the deployment of my web front end container. I couldn’t figure out what was going wrong until I brought up Smart Map, clicked on the container that was failing to deploy, looked in the containers details pane, and there in front of me was an environment variable for service discovery I had forgotten to set in my deploy code. A simple edit, a quick redeploy, and everything was working great. Nothing like using your own product to solve your own problems.
Container Challenge #2: Pipeline Complexity.
If you’re following the best practice of building individual pipelines for each microservice, then the number and complexity of pipeline(s) will grow at the same rate your application does. While unit-tests and other pipeline stages can remain independent, shifting-left and introducing more sophisticated testing and integrations earlier in your pipelines means that you’ll be shifting dependencies left as well. ElectricFlow’s ability to support sophisticated relationships between pipelines helps managing this pipeline complexity.
Furthermore, if you allow your teams to use the tools they already know and love for each microservice, then you’ll need to manage far more tools than you would with a monolithic app. This is where it’s critical to have an extensible/adaptive platform that can integrate existing (and future) tools to empower developers and position your team to keep up with and take advantage of new trends and technologies (eg, adding TwistLock to your pipeline) without disrupting other teams’ efforts, up- or down-stream.
Container Challenge #3: Supporting Traditional Applications.
The third challenge is how to support traditional applications alongside container / microservice based apps. The reality for most enterprises is that the journey to containers and microservices has to happen while supporting traditional, legacy “monolithic” applications. Not only is it challenging to manage the different tooling to build, test, and release these interdependent applications, but managing “the system” they all comprise as a single deliverable entity is even harder. This is why it’s critical to have a CI/CD platform thats allows you to abstract and model hybrid applications with traditional and container/microservices based applications side by side. ElectricFlow’s application model and “pipeline as code” provide a powerful layer of abstraction that makes this possible. Each application component has specific automation for deployment and configuration, but all share a common data model that simplifies dependency mapping, and allows complex deployment flows to be easily managed together.
As an example, the e-commerce web application above has frontend and backend components that are deployed as microservices and a traditional database component, all of which are managed together as a single entity. As you start to look at systems with hundreds, or thousands, of microservices — having the ability to safely “zoom up” to a system-level view and know that “the entire application has been successfully deployed” becomes a useful abstraction. Similarly, having the ability to target deployments and releases to other platforms (eg, moving from GKE to Azure AKS, or AWS ECS) without recoding platform-specific deployment scripts becomes a useful tool to ensure business agility and cost management.
Container Challenge #4: Migrating Traditional to Container.
The last challenge is the question of how to decompose traditional applications into container-based microservices, which is a meaty topic of its own.
However, since containers provide immediate agility and speed advantages, many businesses can benefit from taking a “first step” to modernization by simply moving individual legacy components into containers. ElectricFlow makes this easy with a “lift-and-shift” feature that intelligently builds container images from legacy/traditional components like JAR and WAR files. This allows teams to take advantage of the runtime portability and scaling properties of containerized applications without requiring any code changes or re-architecture work to be done.
To accomplish this, it’s simply a matter of creating a new microservice component and adding a call to our lift-and-shift tool during its deploy stage. Here you just specify the legacy artifact you want to containerize (say myFrontend.war, which can be in an artifact repository), the base Docker image you want to target (say Jetty or Tomcat), and the name/location of the container repo you want to publish the new container image to (eg, DockerHub – myImages/myWebFrontend).
From there, ElectricFlow will do the rest, including creating and building the Dockerfile and pushing the new image up to your container repo! Your new microservice based application can then deploy your legacy component as a newly built container image to your container platform of choice (like Kubernetes, OpenShift, AWS ECS, Google, or Azure).
Many folks at the Meetup resonated with the need to take a piecewise approach to application modernization and moving to containers.
It was great to get out and engage the local Docker community in Vegas, enjoy some cheap pizza, and spend time chatting with folks about where they are in their DevOps journey.