By Liu Chen (Lorraine)
In this article, I will discuss the basic knowledge on Kubernetes from the perspective of application development, with the hopes of helping developers master Kubernetes and apply it in their daily work.
The world has witnessed a major technical shift from monolithic applications to distributed microservices architecture applications. Serving for various software development design patterns, the distributed microservices architecture uses the domain design model to guide the abstraction and encapsulation of business demands. The entity extraction and boundary division of business will be based on the microservices architecture, so as to form a microservices cluster and operate on cloud-native orchestration platform.
Structure of Cloud Native Applications from Kubernetes-Patterns
With concise and explicit design and relatively simple business logic, cloud native applications are implemented with independent codes from other domain objects. Basic programming skills and high-coverage automated testing capabilities are the main factors that ensure service quality at this stage.
Domain design-driven mode has become the mainstream design pattern in the recent years of the microservices boom. The main problem now is to disassemble the requirements of a complex business scenario to multiple microservices units. Domain design-driven mode is a design pattern of the microservices architecture. A microservice can correspond to either a domain object or a domain service.
Cloud native applications implemented in the distributed microservices architecture are characterized by high availability, automated scaling, failure tolerance, and health self-check. It has gradually shifted the focus on the complexity of programming to that of resource integration, operation, and management, in terms of dealing with the growing business requirements.
Microservices refer to simple applications running in single process. Container technology can exactly support isolated encapsulation for microservices. Therefore, a simple microservice is standardized through a Dockfile template, and can operate on any resource node in a distributed cluster without differentiation.
Kubernetes has become the most popular cloud-native architecture. It provides a set of automated systematic solutions for several issues, including the interaction of a group of microservices, storage of persistent data, operations of microservices with multiple dependencies, and capacity planning.
The object-oriented programming (OOP) must be familiar to application developers. OOP designs a set of lifecycle management solutions for a logical object. The following part introduces some Kubernetes core resource objects and application methods in detail.
OOP vs Kubernetes from Kubernetes-Patterns
Image is similar to the class of OOP, a container image defines all the properties and functions of a module, and provides the only exposed API call method and parameter set. The image corresponds to an independent and complete release cycle. It is like the container design blueprint. The statistic definition can define and initialize a container to ensure consistent operations at any time in any environment. A container image corresponds to a microservice, and is the product of the development team.
Container is similar to an OOP object, and is the operating state of a container image. A container serves as the operating process of a container image. A container image can create any number of containers at any time in any environment.
All Java application developers know that, only one Jar package is required when deploying a Java application based on the Springboot-MVC framework. The internal source code of the Jar package cannot be changed after compilation. Pod is the smallest unit for resource scheduling and deployment on the cloud-native orchestration platform. Pod to container is like Jar package to object in Java. Container images delivered by application developers are deployed and scheduled on Kubernetes clusters via Pod. Containers, however, are the internal resource objects in Pod, which cannot be perceived or intervened by Kubernetes.
Why is Pod the smallest unit? It is because that, Pod allows a set of containers to share Pod resources in the storage space, network space, and process space. It is similar to running multiple processes on a virtual machine at the same time. Inter-container communication is similar to single-node inter-process communication. Pod is designed to allow containers to share as many Linux Namespace as possible, with only the necessary isolation and restriction capabilities reserved.
Pod is similar to an OOP Module. In OOP, objects with strong logic relationship usually belong to one independent module. An example of the Pod definition is as follows:
apiVersion: v1 kind: Pod metadata: name: index-helm-57677c549-lgww5 namespace: bss-dev spec: containers: - command: - java - '-jar' - /home/demo/app.jar env: - name: aliyun_logs_release_tags value: revision=3f44253.20201030-1039 image: 'registry-vpc.cn-shanghai-finance-1.aliyuncs.com/XXX/XXX.XXX:latest' imagePullPolicy: Always
Pod->spec contains one or more container template definitions. PodYAML provides many attributes. For more information, see https://github.com/kubernetes/kubernetes/blob/master/staging/src/Kubernetes.io/api/core/v1/types.go
Pod->spec contains a special container template definition, with the keyword initContainer, namely the container to be initialized. Application container can only start when container initialization has been successfully completed.
Pod->spec defines Volume mounting methods of stored resources shared among containers. It also defines the node selector labels, affinity, and tolerance that affect Pod resources scheduling.
NameSpace is a group concept that enables cluster resources to be logically divided. It is similar to OOP Package. As the project scale grows, it's common that classes or objects share the same name. To distinguish them, the corresponding objects are usually defined and referenced with packge as the path prefix. It is the same for Kubernetes clusters, where hundreds of application services are in operating. NameSpace can be used to isolate a group of resource objects and manage permissions on Kubernetes.
NameSpace is commonly used to separate development and test environments in a Kubernetes cluster. NameSpace can also provide multi-tenant running environments, or a separate NameSpace for an application deployment to isolate application operation.
Although NameSpace enables logic division of resources, it does not really isolate the communication between Pods in a cluster. In other words, Pods in multiple NameSpace of the same cluster can still communicate with each other. For absolute isolation in NameSpace, NetworkPolicy works.
The upgrade of application services running in Kubernetes is to create a new version of Pod and destroy the earlier one, which is defined by Deployment resource objects. There are hundreds of applications in the microservices architecture. Manual deployment may bring human errors and turn deployment operation a bottleneck in the system. Kubernetes defines all operations of Pod deployment as Deployment resource object, thus making the platform automatically deploy Pod.
Deployment resource object defines not only the type of Pod deployment, but also the expected deployment status, such as the expected number of Pods, or the node on which to be deployed.
There are two methods to deploy a new-version Pod. The system can generate a new version of Pod, and then destroy the earlier one after the new Pod is confirmed to able to provide services externally. Besides, the system can also destroy the earlier Pod first, and then generate a new one. The former method, Rolling Update, ensures no downtime during deployment, but cannot avoid simultaneous operation of Pods of multiple versions. The service states would be inconsistent. Advantages and disadvantages of the latter method, Recreate, are the opposite of Rolling Update. Kubernetes defaults Rolling Update as the deployment strategy.
Deployment creates and manages Pods through the ReplicaSet controller. This ensures successful operation as expected and meets the deployment definition, such as the number of opened replicas and requirements of deployment strategies. ReplicaSet decouples the deployment from Pod running. A Running Pod does not mean that the application is successfully deployed. Deployment sets the number of Pod replicas and Health Probe of the application container to ensure successful startup and operation.
Successful deployment can only be achieved under the following conditions. Pod of newly created ReplicaSet runs smoothly. Besides, the number of replicas reaches that set by Replicaset, and Pod managed by the earlier ReplicaSet no longer undertakes any load or is destroyed.
In OOP, initialization, such as Java class definition, is a constructor that encapsulates necessary initialization operations before the object is used. InitContainer, the initialization in Pod, is a special type of container template definition of Pod->spec. It isolates the container process and initialization operations in the main application. Thus, it ensures that the initialization can be completed before the application container starts.
Initialization can also be realized at the container level by using Dockerfile->ENTERPOINT of the container image template. Container-level initialization has an impact on the interior of the container image definition, while Pod-level initialization, InitContainer, defines all the container groups within Pod. Generally, container-level initialization focuses more on Devops and has little to do with application developers. InitContainer can isolate initial container template definitions from the R&D cycle.
The advantages of InitContainer are as follows. The permissions for shared Volume access can be set in a unified manner. Dependency components and data are prepared before applications are started. The dependency of application services can be checked. Before starting the main application container process, it's expected to prepare all the prerequisites to ensure successful operation of application services.
In terms of security like access control, it's not recommended to open access permission of Pod shared resources in the application container image definition. The management and operations of Pod shared resources should be set and controlled by the orchestration platform, and be isolated from the application services. This ensures that the application service itself is free from platform dependency. Therefore, InitContainer improves the security of microservices application development.
Users can define multiple InitContainers and application containers for a Pod template. Kubernetes ensures that initialization operations are sequentially performed by the InitContainer before the application container is started. The application container is started in parallel.
InitContainer is basically the same as normal application containers. However, InitContainer is generally set as Completed and there is no Failure state. The InitContainer failure leads to Pod restarting and re-execution of InitContainer.
As mentioned before, container image and container are similar to OPP class and object, since container image defines an application microservice with single responsibility. What if some bypass operations need to be extended or added when the corresponding service is running? Similar to OOP's composite pattern, another container image definition can be directly integrated into the same Pod. This pattern is called Sidecar.
Sidecar ensures the single responsibility of the application container. Independent and reusable bypass operations, such as update data, configuration files, static resources, and log data collection, can also be added to Pod. Sidecar can combine multiple containers with single responsibility to provide a fully functional application microservice that is qualified to publish. At the same time, the development team only needs to consider the business application functions.
Sidecar and InitContainer are two different container definitions. InitContainer defines a set of Pod-level initialization operations with a strict execution order, which must be completed before all application containers are started. The execution sequence of the Sidecar and application containers is not strictly set. Both of them generally simultaneously run in the same Pod, share Pod resources, and jointly provide the serving capabilities exposed by Pod.
One of the 12 principles of application development is to store configuration in the environment. The isolation of configuration information from applications can be achieved by storing application configuration information through environment variables. Environment variables are global and can be loaded during application runtime. However, it's not feasible for large amount of configuration information. Java-Springboot applications provide Profile files to record and store application-related configuration information. Developers can distinguish Profile files based on different environments.
ConfigMap and Secret can be configured in Kubernetes to support the form of both environment variable Key/Value and application configuration Profiles. Environment variable Key is generally named with uppercase letters, while Profile files with lowercase letters.
Kubernetes provides Secret resource objects to configure sensitive data, such as the username and password of a database link.
ConfigMap and Secret objects are mounted to Pod via Volume, making the configuration information be shared by container groups in Pod. The data storage limit for ConfigMap and Secret is 1 MB. Therefore, when the application configuration file is too large, a configuration management container can be initialized by InitContainer in the same Pod. Before the application container starts, application configuration can be sent to assigned mounting directory in the application to update configuration information.
Application development often involves batch or scheduled tasks. Currently, popular application frameworks, such as Spring-Batch of Java or Celery of Python, can implement asynchronous or scheduled tasks. However, in cloud native, this application-level implementation method bears too much burden. For example, asynchronous tasks usually expect applications to meet requirements of high availability, elastic resource scaling, and fault self-recovery. Kubernetes is born with these features, making it possible to delegate the asynchronous tasks implementation to Job and Cronjob controller objects in Kubernetes.
Job controller object in Kubernetes, similar to Deployment, functions as a way to implement the creation and management of Pod lifecycle. Different from Deployment, Pod controlled by Job stops immediately after running completes. In other words, the final state of Pod is "Completed". Pod in Job is defaulted not to be directly destroyed, aiming at providing queries of task operation logs.
Cronjob controller object in Kubernetes combines the time-triggered event logic based on Job object. The main scenarios include but are not limited to file transmission, email or SMS sending, backup, and scheduled cleaning of expired backups.
This article introduces some basic knowledge about Kubernetes for developers to master and use Kubernetes. It's believed that the future applications will be based on cloud. Therefore, one must master the necessary knowledge about Kubernetes if he wants to do well in cloud native development.
Last but not least, team's emphasis on the Kubernetes technology, and attention and support from team leaders also contribute to this article.
By Liu Chen (Lorraine), working on Fintech, proficient in continuous integration and release. Liu Chen has practical experience in continuous deployment and release of more than 100 applications across all platforms, and is now aspiring to become a Kubernetes developer.
Alibaba Container Service - March 12, 2021
Alibaba Developer - September 16, 2020
Aliware - February 5, 2021
Alibaba Clouder - September 3, 2020
Alibaba Clouder - September 24, 2020
Alibaba Developer - June 30, 2020
Accelerate and secure the development, deployment, and management of containerized applications cost-effectively.Learn More
A secure image hosting platform providing containerized image lifecycle managementLearn More
This solution helps you improve and secure network and application access performance.Learn More
Link IoT Edge allows for the management of millions of edge nodes by extending the capabilities of the cloud, thus providing users with services at the nearest location.Learn More
More Posts by Alibaba Container Service