Article Written by Oleg Chunikhin, CTO, KublrContainers and Kubernetes can create code that is portable
across on premise VMs, bare metal, and multiple cloud provider environments.
Despite this portability promise, developers may include configuration and
application definitions that constrain or even eliminate application
portability.
Let's look at two Kubernetes clusters, deployed in AWS and
Azure correspondingly, to show how a correctly built application may be
deployed into different environments with just configuration changes. This is
made possible because Kubernetes provides convenient abstractions for
application resource requirements and endpoints, namely persistent volumes,
ingress rules and ingress controllers.
Why Build Portable
Apps?
Portability is one of the core advantages of containers
technology. While some companies may be happy with the environment they are
working in, other companies may profit from applications that can move between
different environments. Here are just some of them:
- Fast response to traffic from any geographical
location by allowing you to spawn containers immediately in another region.
- Easily migrate applications from one cloud or
hosting provider to another, in order to save costs or add an additional point
of presence for your applications, using additional regions not available in
other cloud providers.
- Ability to cloud-burst workloads that are
generally on premise, but may need cloud capacity at some point.
- Split-tier architecture (application tiers may
reside in different environments).
- Disaster recovery strategy may require recovery
in a different region or cloud, or you may host your application on a data
center and recover into a cloud.
Not only does the environment have to be portability
compatible, the application has to be correctly designed too. Your bible for
portable apps best practices is the 12-factor app methodology manifest.
Particularly, verses 2, 3, 4, 6, 7, and 12.
- Explicitly declare and isolate dependencies. The
application should not assume an existing package or component already
available by default in the environment.
- Store configuration in the environment, avoid
keeping configuration in application code. When migrating to another cloud or
region, the configuration can change, but the application should not need
changes.
- Treat backing services as attached resources.
The application should be able to reinitialize detached and reattached resource
(such as Redis cache or MySql database).
- Execute the application as one or
more stateless. Do not store any data in the application container or
environment, all persistent data has to be stored in a database or other type
of storage (ElasticSearch, Cassandra, dedicated file storage, etc.).
Typical problems that
arise when building portable applications
Some of the hardest and most common problems when moving
applications across environments are handling Ingress traffic (specifically
HTTPS/SSL certificates management), routing and load balancing. Complex routing
rules are sometimes required and need to be managed by cluster administrators.
State persistence can also be a challenge, while some apps require databases,
others may need shared file storage or reliable block storage. Messaging is
another area, though we won't focus on this in this article.
Not all environments satisfy the needed requirements. Cloud
providers may supply only part of the required services that your applications
need (like supporting only a particular type of database, so you have no
choice but to deploy your own database manually and maintain it on that cloud
provider. Think of Cassandra. You can't easily find it available in an
as-a-service in most public clouds).
Platforms have different degrees of capabilities. A "rich"
platform satisfies all application needs and dependencies:

It has flexible routing capabilities, load balancing with
SSL termination, databases, and both types of block storage we need.
Then, there are some with fewer capabilities.

These platforms can satisfy only part of deployed
application needs. To get the missing components you may manually deploy custom
open source solutions, like proxies and databases hosted on dedicated
instances. But that is error prone and quite frankly a nightmare to manage.
Other hosting providers might supply even fewer services on
their platforms. Yet, you still need to be able to deploy your applications on
them. That leaves you with no choice but to use the limited functionality of
the hosting provider or datacenter.

This is where you can benefit from Kubernetes. You can wrap
it around the basic provided resources of the hosting provider, and spawn
fail-tolerant services on top of the raw resources, using Helm package manager
for example. This way, your application can leverage Kubernetes services,
instead of relying on the hosting provider. As you can move all its
dependencies with the application, it becomes portable.
Kubernetes is great because it functions almost like a Lego
set where you can connect your component and external services anywhere you
like. Here are some features of Kubernetes and its ecosystem that help make
your applications, its dependencies, and backing services portable:
-
Component definitions and their connectivity and
relation to each other, including routing and access policies, are stored as
all other resources in simple YAML format.
- Templating tools: Helm package manager. You can
define and reuse templates (or "blueprints") made of several services with
variable settings. Each template can contain as many resources as needed, like
pods, volumes, load balancers, security settings, deployments and other
Kubernetes resources.
- Abstraction over ingress traffic processing:
Service, Ingress, and Ingress controller. Those components serve as a robust
framework that satisfies all routing and balancing needs of your application
and its backing services.
- Abstraction over storage provisioning and
management: Volumes and Volume claims. These all were made possible by
sophisticated "behind the scenes" controllers and plugins, that integrate with
all virtualization, storage, and cloud providers, and expose a unified syntax
for provisioning storage to cluster users.
Basic Kubernetes
Concepts
There are a variety of Kubernetes components that make
application portability possible:
- Services: one of the basic Kubernetes concepts
that allow you to provide a single, stable endpoint to access a set of pods or
containers running inside a Kubernetes cluster. This pod/container set is
dynamic, can be started, scaled up or down, die, or restarted. Services track
these dynamic sets and rearrange routing rules so that clients of this service
implemented don't see the change.
- Ingress: is an abstraction of a higher level
than ‘service' with a similar purpose. It's a level 7 routing rule, which tells
Kubernetes how HTTP and HTTPS requests should be routed to services inside the
cluster.
- Ingress controllers: Implements routing rules
for the ingress. Layer 7 reverse proxy that runs inside Kubernetes watches
those ingress rules as they are updated by cluster users and reconfigures
itself to ensure proper processing of HTTP and HTTP requests. There are various
implementations; some are based on Nginx or HAproxy as an example.
- Config maps and secrets: allows storing configuration
or sensitive information like credentials, inside the Kubernetes cluster and
mapping them to pods and containers. This allows for complete portability of
all application components including their per-namespace and per-environment
credentials and settings.
- Volumes and volume claims: This type of complete
abstraction over storage mechanics, contributes to portability by letting
developers and administrators avoid manually configuring low-level
storage-related settings and managing folder mounts.
To summarize, a portable application architecture involves
not only the usage of the right tools, but also correct planning and best
practices, like keeping the app stateless, supporting re-initialization and
reconnection to external resources like databases, and so on.
Ready to roll up your sleeves and deploy portable
applications? You can find a step-by-step guide in the 2nd section
of our portability blog.
For more on application portability,
Kubernetes, and other great cloud native topics, attend KubeCon + CloudNativeCon EU, May 2-4, 2018 in Copenhagen, Denmark.
##
About the Author
Oleg
Chunikhin has been working in the field of software architecture and
development for nearly 20 years. Oleg joined Kublr as the CTO in 2016 to help
define the technology strategy and innovative standards and fulfill the
company's plans for growth. Notably, Oleg has championed the standardization of
DevOps in all the company does and is a firm believer in driving the adoption
of automation and artificial intelligence applications, particularly in
industries where new technologies are fast becoming mainstream (genetics, 3D
printing, robotics, neural interfaces, mesh technologies, etc.). Oleg holds a
Bachelor of Mathematics and a Master of Applied Mathematics and Computer
Science from Novosibirsk State University and is an AWS Certified Software
Architect.