Novices can understand, Kubernetes is actually very simple

Kubernetes is the most popular and well-known technology in the past two years. It provides software engineers with powerful container orchestration capabilities, blurs the boundary between development and operation and maintenance, and allows us to develop, manage, and maintain a large-scale distribution Systems and projects become easier.


image.png

This article will first briefly introduce the background of Kuberentes, the technology it relies on, its architecture and design philosophy, and finally some key concepts and implementation principles will be mentioned.


Kuberentes background


As an open source project that has been widely used in the production environment, Kubernetes is defined as an open source system for automated deployment, expansion, and management of container applications; it packages a group of distributed software containers into one for easier management and The logical unit of discovery.


Kubernetes means "helmsman" in Greek. It was originally founded by several software engineers at Google. It was deeply influenced by the company's internal Borg and Omega projects. Many designs were borrowed from Borg, and at the same time, Borg's flaws were taken into account. Improved.


Kubernetes is currently a project of the Cloud Native Computing Foundation (CNCF) and is a solution for many companies to manage distributed systems.

image.png

Before Kubernetes dominated the field of container orchestration, there were actually many container orchestration solutions, such as compose and Swarm, but these solutions have basically been replaced by Kubernetes when operating and maintaining large-scale and complex clusters.


Kubernetes arranges packaged application images, so without the development of container technology and the complicated application relationship in the microservice architecture, it is actually difficult to find a suitable application scenario to use.


So here we will briefly introduce the two major "dependencies" of Kubernetes-container technology and microservice architecture.


Container technology


Docker is already the de facto standard for container technology. In the previous article, the author once introduced the core technology and implementation principle of Docker that the implementation of Docker mainly relies on Linux namespace, cgroups and UnionFS.


It allows developers to package their own applications and dependencies into a portable container, allowing applications to run independently of the environment.


We can use Docker to realize an environment in which processes, networks, and mount points are isolated from the file system, and can allocate host resources.


This allows us to run multiple different Docker containers on the same machine. Any Docker process does not need to care about the dependencies of the host, and each completes the installation and compilation of dependencies when the image is built.


This is why Docker is an important dependency of the Kubernetes project.


Microservice architecture


If today's software is not particularly complicated and the peak traffic that needs to be carried is not particularly large, then the deployment of back-end projects actually only needs to install some simple dependencies on the virtual machine, and then compile and run the projects that need to be deployed.


But as software becomes more and more complex, a complete back-end service is no longer a single service, but is composed of multiple services with different responsibilities and functions.


The complex topological relationship between services and the inability of a single machine to meet performance requirements make the deployment and operation and maintenance of software very complicated, which makes the deployment and operation and maintenance of large clusters a very urgent need.


Summary: The emergence of Kubernetes not only dominates the container orchestration market, but also changes the way of operation and maintenance in the past. It not only blurs the boundary between development and operation and maintenance, but also makes the role of DevOps clearer.


Every software engineer can use Kubernetes to define the topological relationship between services, the number of online nodes, and the amount of resource usage, and can quickly achieve horizontal expansion, blue-green deployment, and other complex operation and maintenance operations in the past.


Kuberentes design concept and architecture


design concept


Let's first introduce some design concepts of Kubernetes. These keywords can help understand some of the choices made by Kubernetes in the design:

image.png

Here, we will introduce in order what the design choices of declarative, explicit interface, non-invasiveness, and portability can bring to us.


Declarative


Declarative (Declarative) programming has always been compared with imperative (Imperative) by engineers. The two are completely different programming methods.


The one we are most often exposed to is actually imperative programming, which requires us to describe the instructions that need to be completed in order to achieve a certain effect or goal. Common programming languages ​​Go, Ruby, and C++ all provide developers with imperative programming methods.


In Kubernetes, we can directly use YAML files to define the topology and status of the service:

apiVersion: v1
kind: Pod
metadata:
  name: rss-site
  labels:
    app: web
spec:
  containers:
    - name: front-end
      image: nginx
      ports:
        - containerPort: 80
    - name: rss-reader
      image: nickchase/rss-php-nginx:v1
      ports:
        - containerPort: 88


This declarative approach can greatly reduce the workload of users and greatly increase the efficiency of development.


This is because the declarative style can simplify the required code and reduce the developer's work. If we use the imperative way to develop, although the configuration is more flexible, it brings more work.

SELECT * FROM posts WHERE user_id = 1 AND title LIKE 'hello%';


SQL is actually a common declarative "programming language", which allows developers to specify what data they want.


The YAML file in Kubernetes has the same principle. We can tell Kubernetes what the final state we want, and it will help us migrate from the existing state.


If Kubernetes uses imperative programming to provide interfaces, then engineers may need to tell Kubernetes what operations need to be taken to reach a certain state through code. Compared to declarative programming that focuses more on state and results, imperative programming is more Emphasize the process.


All in all, the declarative API in Kubernetes actually specifies the expected operating state of the cluster.


Therefore, in the event of any inconsistency, it can transfer the state of the online cluster through the specified YAML file.


Just like a horizontally triggered system, even if the system misses the corresponding event, it will eventually automatically make appropriate actions based on the current state.


Explicit interface


The second Kubernetes design specification is actually: there is no internal private interface, all interfaces are explicitly defined, and the interfaces used for communication between components are explicit for users, and we can all call them directly.

When the interface of Kubernetes cannot meet the complex needs of engineers, we need to use existing interfaces to implement more complex features. At this time, this design of Kubernetes will not become an obstacle to custom requirements.


Non-invasive


In order to meet the needs of users (engineers) as much as possible, reduce the workload and tasks of engineers, and enhance flexibility, Kubernetes provides engineers with a non-intrusive access method.


Once each application or service is packaged into an image, it can be used seamlessly in Kubernetes without modifying any code in the application.


Docker 和 Kubernetes 就像包裹在应用程序上的两层,它们两个为应用程序提供了容器化以及编排的能力。


在应用程序内部却不需要任何的修改就能够在 Docker 和 Kubernetes 集群中运行,这是 Kubernetes 在设计时选择无侵入带来最大的好处,同时无侵入的接入方式也是目前几乎所有应用程序或者服务都必须考虑的一点。


可移植性


在微服务架构中,我们往往都会让所有处理业务的服务变成无状态的服务。


以前在内存中存储的数据、Session 等缓存,现在都会放到 Redis、ETCD 等数据库中存储,微服务架构要求我们对业务进行拆分并划清服务之间的边界,所以有状态的服务往往会对架构的水平迁移带来障碍。


然而有状态的服务其实是无可避免的,我们将每一个基础服务或者业务服务都变成了一个个只负责计算的进程。


但是仍然需要有其他的进程负责存储易失的缓存和持久的数据,Kubernetes 对这种有状态的服务也提供了比较好的支持。


Kubernetes 引入了 Persistent Volume 和 Persistent Volume Claim 的概念用来屏蔽底层存储的差异性,目前的 Kubernetes 支持下列类型的 Persistent Volume:


这些不同的 Persistent Volimage.pngume 会被开发者声明的 Persistent Volume Claim 分配到不同的服务中。


对于上层来讲所有的服务都不需要接触 Persistent Volume,只需要直接使用 Persistent Volume Claim 得到的卷就可以了。


架构


Kubernetes 遵循非常传统的客户端服务端架构,客户端通过 RESTful 接口或者直接使用 kubectl 与 Kubernetes 集群进行通信。


这两者在实际上并没有太多的区别,后者也只是对 Kubernetes 提供的 RESTful API 进行封装并提供出来。


每一个 Kubernetes 集群都由一组 Master 节点和一系列的 Worker 节点组成,其中 Master 节点主要负责存储集群的状态并为 Kubernetes 对象分配和调度资源。


Master


作为管理集群状态的 Master 节点,它主要负责接收客户端的请求,安排容器的执行并且运行控制循环,将集群的状态向目标状态进行迁移,Master 节点内部由三个组件构成:

image.png

其中 API Server 负责处理来自用户的请求,其主要作用就是对外提供 RESTful 的接口,包括用于查看集群状态的读请求以及改变集群状态的写请求,也是唯一一个与 etcd 集群通信的组件。


而 Controller 管理器运行了一系列的控制器进程,这些进程会按照用户的期望状态在后台不断地调节整个集群中的对象,当服务的状态发生了改变,控制器就会发现这个改变并且开始向目标状态迁移。


最后的 Scheduler 调度器其实为 Kubernetes 中运行的 Pod 选择部署的 Worker 节点,它会根据用户的需要选择最能满足请求的节点来运行 Pod,它会在每次需要调度 Pod 时执行。


Worker


其他的 Worker 节点实现就相对比较简单了,它主要由 kubelet 和 kube-proxy 两部分组成:

image.png

kubelet 是一个节点上的主要服务,它周期性地从 API Server 接受新的或者修改的 Pod 规范并且保证节点上的 Pod 和其中容器的正常运行,还会保证节点会向目标状态迁移,该节点仍然会向 Master 节点发送宿主机的健康状况。


另一个运行在各个节点上的代理服务 kube-proxy 负责宿主机的子网管理,同时也能将服务暴露给外部,其原理就是在多个隔离的网络中把请求转发给正确的 Pod 或者容器。


Kubernetes 实现原理


到现在,我们已经对 Kubernetes 有了一些简单的认识和了解,也大概清楚了 Kubernetes 的架构,下面我们将介绍 Kubernetes 中的一些重要概念和实现原理。


对象


Kubernetes 对象是系统中的持久实体,它使用这些对象来表示集群中的状态,这些对象能够描述:

c880f4749e4be922859ae8264e7d2d48.png

这些对象描述了哪些应用应该运行在集群中,它们请求的资源下限和上限以及重启、升级和容错的策略。


每一个创建的对象都是我们对集群状态的改变,这些对象描述的其实就是集群的期望状态,Kubernetes 会根据我们指定的期望状态不断检查对当前的集群状态进行迁移。

type Deployment struct {
    metav1.TypeMeta `json:",inline"`
    metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`

    Spec DeploymentSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"`
    Status DeploymentStatus `json:"status,omitempty" protobuf:"bytes,3,opt,name=status"`
}


每一个对象都包含两个嵌套对象来描述规格(Spec)和状态(Status),对象的规格其实就是我们期望的目标状态。


而状态描述了对象的当前状态,这部分一般由 Kubernetes 系统本身提供和管理,是我们观察集群本身的一个接口。


Pod


Pod 是 Kubernetes 中最基本的概念,它也是 Kubernetes 对象模型中我们可以创建或者部署的最小并且最简单的单元。

它将应用的容器、存储资源以及独立的网络 IP 地址等资源打包到了一起,表示一个最小的部署单元。


但是每一个 Pod 中的运行的容器可能不止一个,这是因为 Pod 最开始设计时就能够在多个进程之间进行协调,构建一个高内聚的服务单元,这些容器能够共享存储和网络,非常方便地进行通信。


控制器


最后要介绍的就是 Kubernetes 中的控制器,它们其实是用于创建和管理 Pod 的实例,能够在集群的曾名提供复制、发布以及健康检查的功能,这些控制器都运行在 Kubernetes 集群的主节点上。


在 Kuberentes 的 kubernetes/pkg/controller/ 目录中包含了官方提供的一些常见控制器,我们可以通过下面这个函数看到所有需要运行的控制器:

func NewControllerInitializers(loopMode ControllerLoopMode) map[string]InitFunc {
    controllers := map[string]InitFunc{}
    controllers["endpoint"] = startEndpointController
    controllers["replicationcontroller"] = startReplicationController
    controllers["podgc"] = startPodGCController
    controllers["resourcequota"] = startResourceQuotaController
    controllers["namespace"] = startNamespaceController
    controllers["serviceaccount"] = startServiceAccountController
    controllers["garbagecollector"] = startGarbageCollectorController
    controllers["daemonset"] = startDaemonSetController
    controllers["job"] = startJobController
    controllers["deployment"] = startDeploymentController
    controllers["replicaset"] = startReplicaSetController
    controllers["horizontalpodautoscaling"] = startHPAController
    controllers["disruption"] = startDisruptionController
    controllers["statefulset"] = startStatefulSetController
    controllers["cronjob"] = startCronJobController
    // ...

    return controllers
}


这些控制器会随着控制器管理器的启动而运行,它们会监听集群状态的变更来调整集群中的 Kuberentes 对象的状态,在后面的文章中我们会展开介绍一些常见控制器的实现原理。


总结


Through the above, we have understood the background of its emergence and the key technologies it depends on. At the same time, we also introduced the architecture design of Kubernetes. The master node is responsible for processing client requests and node scheduling. Finally, we mentioned several very important ones in Kubernetes Concept: Object, Pod and Controller.


Guess you like

Origin blog.51cto.com/14410880/2551513