"Cloud native" applications, or simply "cloud" applications, are specifically designed to operate in cloud infrastructures. They are typically built as a set of loosely coupled microservices packaged in containers, which are managed by a cloud platform. Such applications are resilient by default, meaning they reliably work and scale even during severe infrastructure-level failures. The flip side is a set of constraints (contracts) imposed by the cloud platform on containerized applications to allow for automated management.

While fully aware of the necessity and importance of transitioning to cloud applications, many organizations still do not know where to start. In this post, we will explore a number of principles that, when followed in the development of containerized applications, will help realize the potential of cloud platforms and ensure reliable operation and scaling of applications, even in the face of significant IT infrastructure failures. The ultimate goal of these principles is to learn how to create applications that can be automatically managed by cloud platforms such as Kubernetes.
Software Design Principles
In the programming world, principles refer to quite general rules that must be followed in software development. They can be applied when working with any programming language. Each principle has its own goals, which are typically achieved through patterns and practices. There are also several fundamental principles of quality software creation, from which all others derive. Here are examples of fundamental principles:
- (Keep it simple, stupid) – don't complicate things;
- (Don’t repeat yourself) – avoid repetition;
- (You aren't gonna need it) – don't create something you don't immediately need;
- (Separation of concerns) – separate responsibilities.
As can be seen, these principles do not lay down any specific rules; they are rather a set of so-called common sense considerations based on practical experience, which many developers share and regularly reference.
Additionally, there is – a set of the first five principles of object-oriented programming and design formulated by Robert Martin. SOLID includes generalized and interpretable complementary principles that, when applied in conjunction, help create higher quality software systems and better maintain them in the long term.
SOLID principles pertain to the realm of OOP and are formulated in the language of concepts such as classes, interfaces, and inheritance. Similarly, for cloud applications, development principles can be formulated, but the basic element here will not be a class, but a container. By following these principles, it is possible to create containerized applications that better meet the goals and objectives of cloud platforms like Kubernetes.
Cloud-oriented containers: the Red Hat approach
Today, it is relatively easy to package almost any application into containers. However, for applications to be effectively automated and orchestrated within a cloud platform like Kubernetes, additional effort is required.
The foundation for the ideas presented below is the methodology and numerous other works on various aspects of web application creation, from source code management to scaling models. The principles described relate specifically to the development of containerized applications based on microservices intended for cloud platforms such as Kubernetes. The basic element in our discussions is the container image, and the target execution environment for containers refers to the container orchestration platform. The goal of the proposed principles is to create containers for which tasks such as scheduling (the selection of a host for running a container instance), scaling, and monitoring can be automated on most orchestration platforms. The principles are presented in no particular order.
Single Concern Principle (SCP)
This principle is largely similar to the Single Responsibility Principle ( ), which is part of the SOLID principles and states that every object should have a single responsibility, and that responsibility must be completely encapsulated within the class. The essence of SRP is that each responsibility is a reason for change, and a class should have one and only one reason for change.
In SCP, instead of the term 'responsibility', we use 'concern' to indicate a higher level of abstraction and a broader purpose of the container compared to an OOP class. While the goal of SRP is to have only one reason for change, SCP aims to enhance the capabilities of reuse and replacement of containers. By following SRP and creating a container that addresses a single concern and does so in a functionally complete manner, you increase the chances of reusing the model of this container in various application contexts.
The SCP principle states that each container should address a single concern and do so well. Moreover, SCP is achieved more simply in the world of containers than SRP in the world of OOP, as containers typically perform one single process, and for most of the time, that process addresses one single concern.
If a container microservice needs to handle multiple concerns at once, it can be split into single-concern containers and combined within a single pod (the unit of deployment in a container platform) using sidecar and init-container patterns. Additionally, SCP simplifies the replacement of an old container (such as a web server or message broker) with a new one that addresses the same concern but offers enhanced functionality or better scalability.

High Observability Principle (HOP)
When using containers as a unified way to package and run applications, the applications themselves are considered to be a 'black box.' However, if these are cloud containers, they must provide the runtime environment with special APIs to monitor container health and take appropriate actions when necessary. Without this, it would be impossible to unify the automation of container updates and manage their lifecycle, which, in turn, would deteriorate the resilience and usability of the software system.
In practice, a container application should at least have an API for various types of health checks: liveness tests and readiness tests. If the application claims to do more, it should also provide other means to monitor its state. For example, logging important events through STDERR and STDOUT for log aggregation using tools like Fluentd, Logstash, and similar. Furthermore, it should integrate with tracing and metric collection libraries such as OpenTracing, Prometheus, etc.
Overall, the application can still be viewed as a 'black box,' but it needs to be equipped with all the APIs necessary for the platform to monitor and manage it effectively.
Lifecycle Conformance Principle (LCP)
LCP is the antithesis of HOP. While HOP states that a container must provide the platform with APIs for reading, LCP requires the application to be able to perceive information from the platform. Moreover, the container must not only receive events but also adapt, in other words, respond to them. Hence the name of the principle, which can be seen as a requirement to provide the platform with APIs for writing.

Platforms have different types of events that help manage the lifecycle of a container. However, it is the application itself that should decide which events to perceive and how to respond.
It is clear that some events are more important than others. For example, if an application handles unexpected terminations poorly, it must accept the signal: terminate (SIGTERM) messages and quickly initiate its shutdown procedure to get ahead of the signal: kill (SIGKILL), which follows SIGTERM.
Additionally, events such as PostStart and PreStop can be important for an application’s lifecycle. For instance, after startup, an application may require some time to 'warm up' before it can respond to requests. Or, the application may need to release resources in a special way upon termination.
Image Immutability Principle (IIP)
It is commonly accepted that container applications should remain unchanged after being built, even when run in different environments. This necessitates externalizing data storage at runtime (in other words, using external means for this), as well as relying on external configurations tailored for a specific runtime environment, rather than modifying or creating unique containers for each environment. Any changes to the application require rebuilding the container image and deploying it across all utilized environments. Incidentally, a similar principle is used in IT systems management, known as the immutability principle of servers and infrastructure.
The goal of IIP is to prevent the creation of separate container images for different execution environments and to use the same image everywhere along with the appropriate configuration for the specific environment. Adhering to this principle enables the implementation of important practices for cloud system automation, such as rollbacks and roll-forwards of application updates.

Process Disposability Principle (PDP)
One of the key characteristics of a container is its ephemeral nature: a container instance is easy to create and easy to destroy, which means it can be readily replaced with another instance at any time. There can be many reasons for such replacement: a failure in a health check, application scaling, migration to another host, depletion of platform resources, or other situations.
As a consequence, container applications must maintain their state using external resources or utilize internal distributed schemes with redundancy. Additionally, the application should start up quickly and shut down rapidly, and be prepared for sudden catastrophic hardware failures.
One practice that helps implement this principle is creating small containers. Cloud environments can automatically select a host for running a container instance, so the smaller the container, the faster it starts—it's simply copied over the network to the target host more quickly.
Self-containment Principle (S-CP)
According to this principle, all necessary components are included in the container during the build phase. The container should be built with the assumption that only a clean Linux kernel is present in the system, so all required additional libraries must be placed inside the container. It should also include items like a runtime environment for the relevant programming language, application platforms (if needed), and other dependencies that the container application will require during operation.

Exceptions are made only for configurations that vary from environment to environment and should be provided at runtime, for example, through Kubernetes ConfigMap.
An application may include several containerized components, such as a separate database container within a containerized web application. According to the S-CP principle, these containers should not be merged into one; instead, the database container should contain everything necessary for the database to function, while the web application container should hold everything required for the web application to operate, including the web server. As a result, during execution, the web application container will depend on the database container and will communicate with it as needed.
Runtime Confinement Principle (RCP)
The S-CP principle defines how a container should be built and what the binary image file should contain. However, a container is not just a 'black box' with only one characteristic — file size. During execution, the container gains other dimensions: memory usage, processor time, and other system resources.

Here, the RCP principle comes into play, which states that a container must decouple its resource requirements and convey them to the platform. With resource profiles for each container (how much CPU, memory, network, and disk resources it needs), the platform can optimally handle scheduling and auto-scaling, manage IT capabilities, and maintain SLA levels for the containers.
In addition to meeting a container's resource requirements, it's also important for the application not to exceed its own defined boundaries. Otherwise, in the event of resource shortages, the platform is more likely to include it in the list of applications to suspend or migrate.
When we speak of cloud orientation, we primarily mean a way of working.
Above, we have outlined a number of general principles that establish a methodological foundation for building quality container applications for cloud environments.
It is important to note that, in addition to these general principles, you will also need additional advanced methods and techniques for working with containers. Furthermore, we have several brief recommendations that are more specific and should be applied (or not applied) depending on the situation:
- Try to minimize image sizes: delete temporary files and avoid installing unnecessary packages — the smaller the container, the faster it is built and copied to the target host over the network.
- Focus on arbitrary User-IDs: do not use the sudo command or any special user IDs to run your containers.
- Label important ports: port numbers can be specified at runtime, but it's best to indicate them using the EXPOSE command — this makes it easier for others and programs to use your images.
- Store persistent data on volumes: data that needs to remain after the container is destroyed should be written to volumes.
- Document image metadata: tags, labels, and annotations make using images easier – other developers will thank you.
- Synchronize the host and images: some container applications require the container to synchronize with the host based on certain attributes, such as time or machine ID.
- In conclusion, we share templates and best practices to help implement the principles outlined above more effectively:
June 11 at 11:00 AM
What you will learn:
- Immutable Red Hat Enterprise Linux CoreOS
- OpenShift service mesh
- Operator framework
- Knative framework
Source: habr.com
