Summary
From the Kubernetes Practical Guide. In the previous article, we discussed cloud-native and service-centric development. In this article, we will review the value of containers and Kubernates in cloud-native applications.
In this article, we will review the value of containers and Kubernates in cloud-native applications.
In the previous article, we discussed container orchestration, which is expected to be an important part of the process, as well as the steps companies are taking to become cloud-native. However, a major challenge in implementing cloud-native will be the environmental dependence on cloud technologies. For example, when using a specific cloud vendor service, the application architecture is forced to change depending on the functionality and service level of that service. This means that no matter how much cloud computing is used, it is not always possible to respond quickly to business changes.
One reason container technology is attracting attention is its freedom from such vendor dependence. Its technical elements utilize Linux Kernel functions and are not significantly different from conventional application execution environments. However, the first step toward becoming cloud-native lies in the fact that the cloud can be used without being occupied by a specific vendor, thanks to the standardization of container technology.
In this section, we will discuss the technology behind these containers and how containers and Kubernates provide business value.
Container Overview
In the pre-container era, application deployment was typically done on an OS configured on a physical machine. However, in recent years, deploying the application itself as a container has become one of the main options. The advantage of deploying applications as containers is that applications can be operated independently of the execution environment. This frees the application from its own library dependence on the OS and the operating environment of the cloud environment itself. This is very similar to the concept of the JVM in Java.
Java can be run on any OS as long as the program is written, and Sun Microsystems, Inc. On the other hand, containers are called “Build once, Run anywhere” in contrast to Java’s vision, because they can be run anywhere and in any language as long as a container image is prepared.
This portability of containers is called “portability. Cloud-native applications are supported by the high portability of containers. For example, applications that were dependent on a specific cloud or hardware can be freed from location restrictions by using containers. These characteristics are largely due to the technology built up by Linux and the work of standardization mechanisms that integrate vendor technologies.
Value provided by containers
Now that server virtualization technology has become the de facto standard, container technology is sometimes viewed as a next-generation technology that is an extension of virtualization. This is largely due to investment decisions in existing businesses, such as resource consolidation through virtualization and cost reduction. In other words, just as virtualization technology has consolidated many resources into a single physical resource, containers can be used to deploy multiple applications on a single OS. This efficient rate of resource aggregation may be the reason for planning system investments. Furthermore, many companies are pursuing next-generation investments on the grounds that while server virtualization could only aggregate up to the OS layer, containers can aggregate the application layer, thereby increasing the aggregation rate even further.
While these are not mistakes, the benefits of containers are not limited to the aspect of next-generation application virtualization technology for resource aggregation; containers are a technology that was created from the background of rapid application deployment, and as a result of the standardization of container technology, it is now possible to realize a platform where applications can run anywhere. Containers are not only a next-generation application virtualization technology for next-generation applications, but also a technology that was created from the background of rapid application deployment. The value of containers is precisely the guiding principle for achieving the speed (Agility) and portability (Portability) of cloud-native applications.
In order to build cloud-native applications, it is desirable to know the background surrounding container technology and container orchestration before using them. If you start implementation without knowing the background, you will end up simply containerizing applications, as described in “Cloud-native and Service-centric Development“. This is a point that all users who build and operate cloud-native applications must be aware of. The goal is not to containerize applications, but to constantly consider ways to use the characteristics of containers to speed up development and lower the operational load, and to make improvements on a daily basis.
Container Characteristics
Docker is an open source container management software developed by dotCloud Inc, a PaaS cloud provider, and released in 2013. Initially, Docker was a technology that only packaged and imaged applications and the libraries necessary to run them, but it has since realized an environment in which these images can be deployed on any OS, promoting automation of application deployment.
Docker’s superiority in container technology is due to its ability to “image” the elements necessary for containers (resource management abstraction) and “automate deployment” (code-based deployment), which is a key element of Docker’s success. Docker excelled in container technology because it implemented a mechanism to automate deployment (execution of the container by code) by “imaging” the necessary elements of the container (abstraction of resource management). The image described here is a container image (Docker Image), and the environment in which the container can be executed is the container engine (Docker Engine). The container image is downloaded (pulled) from the container registry and deployed.
With Docker, application processes can be reproduced in any environment as long as container images are deployed. This has created a user experience for application developers that eliminates the complexity of setting up the environment and aids in rapid code development.
Currently, container imaging and container execution specifications are standardized by the Open Container Initiative (OCI). There are also several container technologies other than Docker. In this section, we review the value that container technology has provided against this background.
Characteristics of Containers
Characteristics of containers include the following
- Rapid application management via APIs: Imaging and execution can be managed via standardized specifications (APIs), enabling automation of application deployment and continuous integration.
- High portability: As long as you have a container image, you can run your application anywhere, including cloud and local environments.
- Lightweight container images: Only the minimum libraries required to run the application are included in the image, allowing for speedy deployment.
- Container reuse: Once container images are created, they can be used in different environments to reproduce the same execution results. They can also be shared.
By taking advantage of the characteristics of containers, it is possible to achieve benefits such as increased efficiency and reduced man-hours in application development. This is true not only for Docker, but also for other container technologies.
Elemental Technologies for Containers
When we assume a virtual machine, we inevitably cannot get away from the concept of a “container” or “container image” as a small machine using virtualization technology. If the concept of “container” is left unchanged, it will diverge from the actual image, so we can assume that containers are “application executables” themselves. In other words, it is nothing more than the packaging of the process itself. For example, launching a container is not like launching a virtual OS, but rather like launching an application from a linux init system: just as systemctl launches an executable process, a container can be launched by the docker command Containers are launched by docker commands, just as systemctl launches an executable process. Of course, just as the startup options in systemd are set in “etc/systemd/<SERVER name>.service”, containers can be started by specifying startup options in the Dockerfile or command options. This way of handling containers makes sense for the concept of one container and one process.
A common example would be to launch the sshd daemon process in the same container as the application process. This is used in the concept that the container is completely treated as a virtual machine, and the application is managed within it. In normal operation, there is no SSH connection to the container.
The mechanism to make the application feel as if it exists on a different host is based on the elemental technologies of containers. The container elemental technology is the establishment of an execution process utilizing the Linux Kernel mechanism, which creates an environment in which the application seems to be running on its own OS by implementing the following two main features.
- Group executable processes to run only in isolated spaces (namespace)
- Limit hardware resources to executing processes (cgroups)
It also uses file system technology to manage container images and container trajectories. Although only the major yesterday is discussed here, multiple other Kernel functions, such as security and networking, are used to isolate the execution process.
Namespace(namespace)
The execution process running inside the container needs to present the host’s resources as the application’s own proprietary resources. This is done using the namespace feature of the Kernel. A namespace is created for each container to separate user space. From the perspective of the host running the container, each namespace shares the host’s system resources, but inside the namespace it appears as if it is an independent host. As a result, multiple containers can share resources on a single host. The following figure shows an example of a network namespace. From within the container, it looks like an occupied network device, but from the host side, a virtual network is communicating.
Not limited to networks alone, namespace is divided by system resources, and containers can share system resources as long as they are within the namespace.
Control Groups (cgroups)
In order to launch a process, it is necessary to allocate physical resources of the system. This is done using the Kernel’s Control Groups (cgroups) function. Control groups are interfaces that provide detailed management of allocation, priority setting, denial, management, monitoring, etc. of physical resources that can be shared by specified processes in a file system format. For example, by limiting memory to 200 MB for specific cgroups, the container will not be able to handle more memory.
cgroups is a hierarchical structure, in which children inherit some of the attributes of their parents, and a number of different hierarchies can share in the system. Each of these hierarchies is connected to a single or multiple “subsystems”. The subsystems here refer to physical resources such as CPUs and memory.
file system
In the case of a virtual machine, the virtual machine is copied from the virtual machine image and converted to a format that the hypervisor can boot. Once a virtual machine is started, all the resources of the virtual machine, not just the file system, are dedicated to it. In the case of containers, however, the image itself is shared. Even though the image is shared, the container image itself is created as a read-only layer, and the file system in the image is not written to directly. Any data written by the executing process during startup is written to a file on a new layer (Thin R/W Layer). This mechanism is called “Copy-On-Write (COW). The term is usually used for memory writes of shared processes, but it is used here as an application to file systems. In Copy-On-Write, the state of a particular file system (container image) is used as the original, and any changes to the file after it is started are reflected only in the newly created original file, thereby responding to write requests.
Thus, by handling only the updated difference data as a separate file, container image sharing and reuse are realized. When a container is deleted, only the writable layers are deleted, so the contents set after startup are also lost. Therefore, if you want to save the contents after startup, you need to update the container image again and make it into an image, or build a mechanism to export it to an external file separately.
container runtime
The above is a combination of Kernel implementations, and the container execution engine is a library that implements these Kernel functions as an API.
Initially, Docker used the LXC (Linux Container) functionality, but since version 0.9, it has used its own library called libcontainer. The Open Container Initiative (OCI) was established to standardize the container runtime. This project consists of the Runtime Specification, which is a standard specification for container runtime, and the Format Specification, which is a standard specification for container image formatting, and is called “OCI vx.x.” The OCI vx.x standard was developed in accordance with the OCI specifications.
The container runtime (CLI) for creating and executing containers according to the OCI specification is called “runC,” and Docker and other container execution engines call runC as an internal operation to achieve standardized container execution.
However, when executing containers, runC is not often manipulated directly. The user calls runC via Docker or other container engines. Thus, container execution is implemented via several container runtimes. By using an API for runtimes based on this standard, it is possible to construct a system that can handle a wide variety of workloads.
There are two main runtime layers: the low-level container runtime (Low-level Container Runtime), which handles containers like runC, and the container runtime (Low-level Container Runtime), which expands container images and passes them to the low-level container runtime. The container runtime that deploys the container image and passes it to the low-level container runtime is called the “High-level Container Runtime“.
- Low-level Container Runtime (Low-level Container Runtime): A runtime that creates container isolation environments and directly manipulates containers while utilizing kernel functions, etc. This refers to RunC and gVisor.
- High-level Container Runtime: A runtime that deploys images according to OCI’s container image format (answers to file system bundles) and passes container execution tasks to the low-level container runtime. This refers to containerd and cri-o.
In addition to the container runtime, Docker is a package that includes container build and network management, and uses Containerd for the internal runtime.
When using Kerbernetes, it is not necessary to be aware of these container runtimes in detail. However, it is important to understand that the high-level container runtime is called from Kubernetes via an API.
containerd and cri-o
containerd is a container runtime originally developed independently by Docker Inc, but was donated to CNCF in 2017 in order to maintain container technology neutrality.
Containerd has evolved along with OCI‘s intentions, and there are differences in implementation architecture between versions. In version 1.0, CRI was not supported, and when using containerd from Kubernetes, CRI-Containerd had to be installed as a bridge, but since version 1.1, CRI Plugin has been built into containerd However, since version 1.1, CRI’s Plugin has been built into containerd, allowing direct connection to Kebernates.
cri-o will be a project that provides the minimum functionality required for CRI and aims to make the container execution engine lightweight. cri-o is being actively developed as part of the Kubernetes community, and in contrast to the wealth of containerd functionality that Docker has, cri-o will serves as an implementation of CRI’s scope of offerings, so while it has some functionality for monitoring and resource partitioning according to CRI’s requirements, it does not have commands for flexibly manipulating containers or Build/Push functionality for container images. Basically, the role of cri-o is to execute containers.
コメント