Kubernetes的基础概念

时间:2024-04-13 20:27:06

目录

一、概述

二、为什么要用Kubernetes

2.1 从技术层面分析

2.1.1 问题解答

2.1.2 Docker等“裸容器”的不足

2.1.2.1 宕机无法自动恢复

2.1.2.2 健康检查不到位

2.1.2.3 部署、回滚、扩容问题

2.1.2.4 运维难

2.1.3 总结

2.2 从开发人员层面分析

2.2.1 分析日志

2.2.1.1 使用Kubernetes前

2.2.1.2 使用Kubernetes后

2.2.2 代码发布

2.2.2.1 使用Kubernetes前

2.2.2.2 使用Kubernetes后

2.2.3 环境搭建

2.2.3.1 使用Kubernetes前

2.2.3.2 使用Kubernetes后

2.3 从运维人员层面分析

2.3.1 使用Kubernetes前

2.3.2 使用Kubernetes后

三、Kubernetes带来的挑战

四、Kubernetes架构解析

4.1 Kubernetes的架构图

4.2 Master节点

4.2.1 概述

4.2.2 Master节点组成

4.2.2.1 APIServer

4.2.2.2 Scheduler

4.2.2.3 Controller Manager

4.2.2.4 Etcd

4.3 Node节点

4.3.1 概述

4.3.2 Node节点组成

4.3.2.1 Kubelet

4.3.2.2 Kube-Proxy

4.3.2.3 Docker Engine

4.3.2.4 其他组件及工具

4.3.2.4.1 CoreDNS

4.3.2.4.2 Calico

4.4 Pod的概念

4.4.1 概述

4.4.2 什么是Pod

4.4.2.1 从使用方来看

4.4.2.2 从Kubernetes角度看

4.4.3 Pod 的状态

4.4.4 Pod 探针

4.4.5 Pod镜像拉取策略和重启策略

4.4.6 Pod 的基本操作

4.4.6.1 Pod 的创建

4.4.6.2 查看创建的Pod

4.4.6.3 删除Pod


一、概述

Kubernetes是谷歌以Borg为前身,基于谷歌15年生产环境经验开源的一个项目。Kubernetes致力于提供跨主机集群的自动部署、扩展、高可用以及运行应用程序容器的平台,其遵循主从式架构设计,其组件可以分为工作节点(Node)组件和控制平面组件。

Kubernetes Master是集群的主要控制单元,用于管理其工作负载并指导整个系统的通信。Kubernetes控制平面由各自的进程组成,每个组件都可以在单个主节点上运行,也可以在支持高可用集群的多个节点上运行。本文主要介绍Kubernetes的重要概念和相关组件。

二、为什么要用Kubernetes

2.1 从技术层面分析

2.1.1 问题解答

很多人会有疑问,有Docker了为什么还用Kubernetes?

在业务开始进行容器化时,前期需要容器化的项目可能并不多,涉及的容器也并不多,此时基于Docker容器直接部署至宿主机也能实现自己的需求。

但是随着项目越来越多,管理的容器也越来越多,此时使用“裸容器”部署的方式管理起来就显得很吃力,并且随着业务量的增加,会明显体会到“裸容器”的不足。

2.1.2 Docker等“裸容器”的不足

2.1.2.1 宕机无法自动恢复

宿主机宕机造成该宿主机上的容器不可用,且无法自动恢复。

2.1.2.2 健康检查不到位

容器明明在运行,接口就是不通(健康检查做得不到位)。

2.1.2.3 部署、回滚、扩容问题

应用程序部署、回滚、扩缩容困难。

2.1.2.4 运维难

成百上千的容器和涉及的端口难以维护。

2.1.3 总结

上面的问题只是做一个简单的罗列,真正使用时还有很多其他的问题。可能大家也体验过像docker-compose、docker-swarm等编排工具,但这些工具的功能和Kubernetes的功能还是相差甚远,所以注定Kubernetes编排工具将成为主流的容器编排工具。

2.2 从开发人员层面分析

2.2.1 分析日志

2.2.1.1 使用Kubernetes前

由于公司业务多,开发环境、测试环境、预生产环境和生产环境都是隔离的,而且除了生产环境,为了节省成本,其他环境可能没有进行日志收集。在没有用Kubernetes的时候,查看线下测试的日志,需要开发或者测试人员找到对应的机器,再找到对应的容器,才能查看日志。

2.2.1.2 使用Kubernetes后

在使用Kubernetes之后,开发和测试人员直接在Kubernetes的Dashboard上找到对应的Namespace,即可定位到业务的容器,然后可以直接通过控制台查看到对应的日志,大大降低了操作时间。

2.2.2 代码发布

2.2.2.1 使用Kubernetes前

在没有使用容器之前,使用传统的运维方式部署,比如Tomcat容器部署,Jetty 容器部署,都是运维通过远程工具ssh连接上服务器去部署,即使使用了Docker等容器,也是需要ssh连接到服务器使用Docker命令启动;即使使用了docker-compose、docker-swarm等编排工具进行编排任务的管理,也是一样需要连接到服务器进行部署,发布、回滚以及蓝绿发布、金丝雀发布等都变得不可控,运维比较消耗人员工时和人员精力。

2.2.2.2 使用Kubernetes后

把应用部署到Kubernetes之后,代码的发布、回滚以及蓝绿发布、金丝雀发布等都变得简单可控,不仅加快了业务代码的迭代速度,而且全程无须人工干预。生产环境可以使用Jenkins、GitRunner等工具进行发版或回滚等。从开发环境到测试环境,最后到生产环境,完全遵守一次构建,多集群、多环境部署,通过不同的启动参数、不同的环境变量、不同的配置文件区分不同的环境。

2.2.3 环境搭建

2.2.3.1 使用Kubernetes前

在测试过程中,可能同时存在多套环境,当然也会创建其他环境或临时环境,之前测试环境的创建需要找运维人员或者自行手工搭建。

2.2.3.2 使用Kubernetes后

在迁移至Kubernetes集群后,开发人员如果需要新的环境,无须再找运维,只需要在Jenkins上点点鼠标即可在Kubernetes集群上创建一套新的测试环境。

2.3 从运维人员层面分析

2.3.1 使用Kubernetes前

对于运维人员,可能经常因为一些重复、烦琐的工作感觉厌倦,比如一个项目需要一套新的测试环境,另一个项目需要迁移测试环境至其他平台。传统架构可能需要装系统、装依赖环境、部署域名、开通权限等,这一整套下来,不仅耗时,而且可能会因为有某些遗漏而造成诸多问题。

在传统架构体系下,公司业务故障可能是因为基础环境不一致、依赖不一致、端口冲突等问题。

另外,也有可能公司业务由于服务器宕机、网络等问题造成服务不可用,此类情况均需要运维人员及时去修复。

业务应用的扩容和缩容都需要人工去处理,从采购服务器、上架到部署依赖环境,不仅需要大量的人力物力,而且非常容易在中间过程出现问题,又要花费大量的时间去查找问题。

在反向代理配置方面,可能对Nginx的配置规则并不熟悉,一些高级的功能也很难实现。

在负载均衡方面,之前负载均衡可能是Nginx、LVS、HAProxy、F5等,每次添加删除节点时,都需要手动去配置前端负载均衡,手动去匹配后端节点。

在应用端口方面,传统架构中,一台服务器可能跑了很多进程,每个进程都有一个端口,需要人为地去配置端口,并且还需要考虑端口冲突的问题,如果有防火墙的话,还需要配置防火墙。

2.3.2 使用Kubernetes后

直接使用Kubernetes包管理工具,一键式部署一套新的测试环境,甚至全程无须自己干预,开发人员通过Jenkins或者自动化运维平台即可一键式创建,大大降低了运维成本。

现在使用Docker镜像部署,Kubernetes进行编排,所有的依赖、基础都是一样的,并且环境的自动化扩容、健康检查、容灾、恢复都是全自动的,大大减少了因为这类基础问题引发的故障。

可以利用Kubernetes的弹性计算一键式扩容和缩容,不仅大大提高了运维效率,而且还节省了不少的服务器资源,提高了资源利用率。

在Kubernetes上,利用Kubernetes的Ingress即可简单地实现那些复杂的逻辑,并且不会再遇到Nginx少加一个斜杠和多加一个斜杠的问题。

使用Kubernetes进行编排服务时,使用Kubernetes内部的Service即可实现自动管理节点,并且支持自动扩容、缩容。

在Kubernetes中,端口统一管理、统一配置,每个应用的端口都可以设置成一样的,之后通过Service进行负载均衡,大大降低了端口管理的复杂度和端口冲突。

三、Kubernetes带来的挑战

Kubernetes从诞生至今,一路突飞猛进,在容器编排的领域里过三关斩六将,最终拿下了容器编排的冠军宝座,成为最无可替代、不可撼动的佼佼者,但是针对Kubernetes的学习和使用始终是一个很大的难题。

首先Kubernetes本身的学习就很困难,因为Kubernetes概念太多,涉及的知识面也非常广泛,可能学习了一个月也无法入门,甚至连集群也搭建不出来,使人望而却步。

并且Kubernetes对运维的技术能力要求也比较高,因为运维不仅仅局限于传统运维,有时候可能要修改业务代码、制定业务上线体系、给研发人员在开发应用中给出更好的建议等。

需要掌握的知识也有很多,可能需要掌握公司内所有使用到的代码,比如代码如何进行编译、如何正确发布、如何修改代码配置文件等,这对于运维人员也是一种挑战。

Kubernetes之所以被叫作K8s,业界有两种说法,通俗的说法是k和s之间有8个字母;另一种说法是K8s集群至少需要搭建8遍才能搭建成功。

当然,在实际使用时,可能不止8遍。Kubernetes的诞生把运维从传统运维转变到了DevOps方向,需要面临的问题更多,需要面临的新技术也很多,但是当真正掌握了Kubernetes的核心和设计理念,就会受益终身。

四、Kubernetes架构解析

4.1 Kubernetes的架构图

由图可知,Kubernetes架构可简单分为主(Master)节点、从(工作/Worker/Node)节点和数据库Etcd。其中主节点为集群的控制单元,一般不会运行业务应用程序,主要包含的组件有Kube-APIServer、Kube-ControllerManager、Kube-Scheduler。

从节点为工作节点,也就是部署应用程序容器的节点,主要包含的组件有Kubelet、Kube-Proxy,当然如果Master节点也要部署容器,也会包含这两个组件。

同时,可以看出一个集群中可以有很多Node节点,用以保证集群容器的分布式部署用于实现业务的高可用性,也可以有很多Master节点,之后通过一个负载均衡保证集群控制节点的高可用。

负载均衡可以使用软件负载均衡Nginx/LVS/HAProxy+KeepAlived或者硬件负载均衡F5等,通过负载均衡对Kube-APIServer提供的VIP即可实现Master节点的高可用,其他组件通过该VIP连接至Kube-APIServer。

Etcd集群可以和Master节点部署在同一个宿主机,也可以单独部署,生产环境建议部署大于3的奇数台Etcd节点实现Etcd集群的高可用。

4.2 Master节点

4.2.1 概述

Master节点是Kubernetes集群的控制节点,在生产环境中不建议部署集群核心组件外的任何容器(在Kubeadm安装方式下,系统组件以容器方式运行在Master节点的宿主机上;二进制安装方式下,系统组件以守护进程的方式运行,Master节点可以不运行任何容器),公司业务程序的容器更是不建议部署到Master节点上,以免升级或者维护时对业务造成影响。

4.2.2 Master节点组成

4.2.2.1 APIServer

整个集群的控制中枢,提供集群中各个模块之间的数据交换,并将集群状态和信息存储到分布式键-值(key-value)存储系统Etcd集群中。同时,它也是集群管理、资源配额、提供完备的集群安全机制的入口,为集群各类资源对象提供增删改查以及watch的REST API接口。APIServer作为Kubernetes的关键组件,使用Kubernetes API和JSON over HTTP提供Kubernetes的内部和外部接口。

4.2.2.2 Scheduler

集群Pod的调度中心,主要通过调度算法将Pod分配到最佳的Node节点,它通过APIServer监听所有Pod的状态,一旦发现新的未被调度到任何Node节点的Pod(PodSpec.NodeName为空),就会根据一系列策略选择最佳节点进行调度,对每一个Pod创建一个绑定(Binding),然后被调度的节点上的Kubelet负责启动该Pod。Scheduler是集群可插拔式组件,它跟踪每个节点上的资源利用率以确保工作负载不会超过可用资源。因此,Scheduler必须知道资源需求、资源可用性以及其他约束和策略,例如服务质量、亲和力/反关联性要求、数据位置等。Scheduler将资源供应与工作负载需求相匹配以维持系统的稳定和可靠性,因此Scheduler在调度的过程中需要考虑公平、资源高效利用、效率等方面的问题。

4.2.2.3 Controller Manager

集群状态管理器(它的英文直译名为控制器管理器),以保证Pod或其他资源达到期望值。当集群中某个Pod的副本数或其他资源因故障和错误导致无法正常运行,没有达到设定的值时,Controller Manager会尝试自动修复并使其达到期望状态。

Controller Manager包含NodeController、ReplicationController、EndpointController、NamespaceController、ServiceAccountController、ResourceQuotaController、ServiceController和TokenController等,该控制器管理器可与API服务器进行通信,以在需要时创建、更新或删除它所管理的资源,如Pod、服务断点等。

Scheduler和Controller Manager虽然部署了多个节点,但同时工作的节点只有一个,因为Scheduler和Controller Manager属于有状态服务,为了防止重复调度,多个节点的Scheduler和Controller Manager进行了选主工作,工作节点(主节点)信息保存在Scheduler和Controller Manager的EndPoint中,可以通过kubectl describe ep kube-scheduler kube-controller-manager -n kube-system查看(Kubernetes 1.20版本以上需要在leases中查看:kubectl get leases -n kube-system)。

4.2.2.4 Etcd

CoreOS开发,用于可靠地存储集群的配置数据,是一种持久型、轻量型、分布式的键-值(key-value)数据存储组件。

Etcd作为Kubernetes集群的持久化存储系统,集群的灾难恢复、状态信息存储都与其密不可分,所以在Kubernetes高可用集群中,Etcd的高可用是至关重要的一部分,在生产环境中建议部署大于3的奇数个数的Etcd,以保证数据的安全性和可恢复性。

Etcd可与Master组件部署在同一个节点上,大规模集群环境下建议部署在集群外,并且使用高性能服务器来提高Etcd的性能和降低Etcd同步数据的延迟。

4.3 Node节点

4.3.1 概述

Node节点也被称为Worker、Node和Minion,是主要负责部署容器(工作负载)的单机(或虚拟机),集群中的每个节点都必须具备容器的Runtime(运行时),比如Docker或其他遵循CRI标准的Runtime等。

Kubelet作为守护进程运行在Node节点上,负责监听该节点上所有的Pod,同时负责上报该节点上所有Pod的运行状态,确保节点上的所有容器都能正常运行。当Node节点宕机或故障(NotReady状态)时,该节点上运行的Pod会被自动转移到其他节点上。

4.3.2 Node节点组成

4.3.2.1 Kubelet

负责与Master通信协作,管理该节点上的Pod,对容器进行健康检查及监控,同时负责上报节点和节点上面Pod的状态。

4.3.2.2 Kube-Proxy

负责各Pod之间的通信和负载均衡,将指定的流量分发到后端正确的机器上。

4.3.2.3 Docker Engine

Docker引擎,负载对容器的管理。

4.3.2.4 其他组件及工具
4.3.2.4.1 CoreDNS

用于Kubernetes集群内部Service的解析,可以让Pod把Service名称解析成Service的IP,然后通过Service的IP地址连接到对应的应用上。

4.3.2.4.2 Calico

符合CNI标准的一个网络插件,它负责给每个Pod分配一个不会重复的IP,并且把每个节点当作一个“路由器”,这样一个节点的Pod就可以通过IP地址访问其他节点的Pod。

4.4 Pod的概念

4.4.1 概述

在讲解Docker基础时,我们把一个应用程序封装进一个镜像,之后启动这个镜像并映射一个宿主机端口,就能访问这个应用。既然单个容器即可部署我们的应用,为什么Kubernetes不直接管理容器还要设计一个Pod呢?接下来我们带着这个问题学习Kubernetes最小的单元——Pod。

4.4.2 什么是Pod

4.4.2.1 从使用方来看

在实际使用时,单个容器是无法单独来支撑我们的应用,往往需要很多微服务才能组成一个系统,并且还会存在A服务依赖B服务,B服务需要和C服务共用某个目录,实现数据共享。另外,在使用裸容器时,很难实现对容器内进程的健康检查及横向扩容等,而Pod可以轻轻松松解决上述问题。

4.4.2.2 从Kubernetes角度看

Docker只是容器Runtime(运行时)中的一种,市面上还有很多容器的Runtime,比如Rkt、CRI-O等,而Kubernetes作为目前最流行的容器编排工具,需要支持各个Runtime并且不依赖于底层Runtime的实现技术,于是就抽象了Pod这个概念,用于管理多个紧密相连的符合CRI标准的容器,可以从下图来理解Pod。

由图可知,Pod可简单地理解为一组、一个或多个容器,每个Pod还包含一个Pause容器,Pause容器是Pod的父容器,它主要负责僵尸进程的回收管理,同时通过Pause容器可以使同一个Pod里面的不同容器共享存储、网络、PID、IPC等,容器之间可以使用localhost:port相互访问,可以使用Volume等实现数据共享。根据Docker的构造,Pod可被建模为一组具有共享命名空间、卷、IP地址和端口的容器。

使用裸容器时,需要将容器内应用程序的端口映射到宿主机,如果容器过多,端口管理就会比较困难,而且容易引起端口冲突。而Kubernetes为每个Pod都分配一个唯一的IP地址,这样就可以保证不同应用程序可以使用同一个端口,之后通过Kubernetes的内部Service进行访问,这样就避免了发生端口冲突的问题。

4.4.3 Pod 的状态

和裸容器部署一样,Pod在运行时也会有不同的状态,Pod的状态信息保存在PodStatus对象中,在PodStatus中有一个Phase字段,用于描述Pod在其生命周期中的不同状态。可以使用Kubernetes的客户端工具Kubectl查看某个Pod的Phase字段,比如查看kube-system命名空间下的metrics-server的状态:

可以看到此时Pod的状态是Running,当然状态不仅仅只有Running,常见的状态如下表所示。

4.4.4 Pod 探针

在生产环境下,进程正常启动并不代表应用能正常处理请求,所以合理地设计应用的健康检查尤为重要。在使用裸机或者裸容器部署时,一般很难对应用做很完善的健康检查,而Pod提供的探针可以很方便地用来检测容器内的应用是否正常。目前探针有3种检测方式,可以根据不同的场景选择合适的健康检查方式。检测方式如下表所示。

上述检查方式可以被周期性执行,每次检查容器后可能得到的容器状态如下表所示。

Kubelet实现上述检查有3种检测方式,在生产环境中多加利用可以提高应用的可用率。目前支持的探测器类型有3种,可以选择性地对容器进行检测,参考下表。

4.4.5 Pod镜像拉取策略和重启策略

在发布应用或更改控制器配置时,会触发Pod的滚动更新,此时针对容器的镜像有不同的拉取方式,参考下表所示。

Pod进行部署或运行时,难免会出现故障,对于故障Pod也有不同的处理方式,如下表所示。

4.4.6 Pod 的基本操作

4.4.6.1 Pod 的创建

在生产环境中,很少单独运行一个Pod,因为单独创建的Pod并不能实现一些高级的发布策略,所以在实际使用中经常会用Deployment、DaemonSet、StatefulSet等高级控制器调度并管理Pod。

当然有时候也会单独启动一个Pod用于测试业务等,此时可以单独创建一个临时Pod。创建一个Pod的标准格式如下(下面定义的内容可以直接用在Deployment、DaemonSet、StatefulSet中):

使用命令创建:

4.4.6.2 查看创建的Pod

上述pod.yaml定义了labels字段,可以根据该标签过滤查看该Pod的状态:

4.4.6.3 删除Pod

当不再使用该Pod时,可以删除该Pod(由于是单独创建的Pod,删除后不会重建,高级控制器删除后会自动重建):


     # kubectl delete -f pod.yaml # 或者 kubectl delete po nginx -n default pod "nginx" deleted
     # kubectl get po  -l app=nginx


  
 

好了,本次内容就分享到这,欢迎大家关注《Kubernetes》专栏,后续会继续输出相关内容文章。如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!