介绍 #### Kubernetes(常简称为K8s)是用于自动部署、扩展和管理容器化(containerized)应用程序的开源系统。该系统由Google设计并捐赠给Cloud Native Computing Foundation(今属Linux基金会)来使用。 它旨在提供“跨主机集群的自动部署、扩展以及运行应用程序容器的平台”。 它支持一系列容器工具, 包括Docker等。CNCF于2017年宣布首批Kubernetes认证服务提供商(KCSPs),包含IBM、华为、MIRANTIS、inwinSTACK迎栈科技等服务商。 Kubernetes Objects ------------------------ Kubernetes在设计结构上定义了一系列的构建模块(building blocks),其目的是为了提供一个基于 CPU, memory or custom metrics可以部署(deploy)、维护(maintain)和扩展(scale)应用程序的机制。 组成Kubernetes的组件设计概念为松耦合和可扩展的,这样可以使之满足多种不同的工作负载。可扩展性在很大程度上由Kubernetes API提供,此API主要被作为扩展的内部组件以及Kubernetes上运行的容器来使用。 etcd, api server, scheduler, controller manager .. option:: Pod Kubernetes的基本调度单元称为“pod”。通过该种抽象类别可以把更高级别的抽象内容增加到容器化组件。一个pod一般包含一个或多个容器,这样可以保证它们一直位于主机上,并且可以共享资源。Kubernetes中的每个pod都被分配一个唯一的(在集群内的)IP地址这样就可以允许应用程序使用同一端口,而避免了发生冲突的问题。Pod可以定义一个卷,例如本地磁盘目录或网络磁盘,并将其暴露在pod中的一个容器之中。pod可以通过Kubernetes API手动管理,也可以委托给控制器来实现自动管理。 .. option:: 标签和选择器 Kubernetes使客户端(用户或内部组件)将:: 称为“标签”的键值对附加到系统中的任何API对象,如pod和节点。 相应地,“标签选择器”是针对匹配对象的标签的查询方法。 标签和选择器是Kubernetes中的主要分组机制,用于确定操作适用的组件。 例如:: 如果应用程序的Pods具有: 系统的标签 tier (比如"front-end"、"back-end") 和一个 release_track (比如"canary"、"production"), 那么对所有"back-end" 和 "canary" 节点的操作可以使用如下所示的标签选择器: tier=back-end AND release_track=canary .. option:: Services 如图显示服务如何与Kubernetes集群中的Pod网络进行交互: .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/microservices/kubernetes_architecture2.png :width: 80% :: Kubernetes服务是协同工作的pod集,例如多层应用程序的一层。 根据标签选择器(label selector)中的定义,把pod集组成一个服务。 Kubernetes提供两种服务发现模式: 1.使用环境变量 2.使用Kubernetes DNS。 服务发现: 为服务分配稳定的IP地址和DNS名称, 并以round-robin方式将流量负载均衡到与选择器匹配的容器中的该IP地址的网络连接 (即使故障导致容器从一台机器移动到另一台机器) 默认情况下,服务在群集内部公开,例如: 后端pod可能被分组到一个服务中,前端pod的请求在它们之间进行负载平衡 但是服务也可以在群集外部公开,例如: 对于客户端请求前端pods .. option:: Volumes :: 默认情况下,Kubernetes容器中的文件系统提供临时存储。 这意味着重新启动容器将消除此类容器上的任何数据, 因此,这种形式的存储在除了很不重要的应用程序之外,其他很少使用。 Kubernetes卷(Volume)提供持久存储,该存储在pod本身的生命周期中存在。 此存储还可用作pod里面容器间的共享磁盘空间。 卷(Volumes)安装在容器内的特定安装点上,这些安装点由pod配置定义,无法安装到其他卷或链接到其他卷。 同一Volume可以被不同的容器安装在文件系统树中的不同点。 .. option:: Namespaces :: Kubernetes将其管理的资源划分为非重叠集(non-overlapping sets)。 此非重叠集即为命名空间 它们旨在用于多个用户分布在多个团队或项目中的环境中,甚至用于开发,测试和生产等分离环境。 架构设计 ========= .. figure:: https://img.zhaoweiguo.com/knowledge/images/architectures/microservices/kubernetes_architecture.png :width: 80% Kubernetes control plane (primary) --------------------------------------- .. option:: etcd :: etcd 是由CoreOS开发, 一种持久性,轻量型的,分布式的键-值数据存储, 用于可靠地存储集群的配置数据, 表示在任何给定时间点集群的整体状态 就像Apache ZooKeeper一样,etcd是一个在网络分区的情况下支持一致性而非可用性的系统(参见CAP定理) 这种一致性对于正确调度和运营服务至关重要 Kubernetes API服务器使用etcd的watch API来: 监控集群并推出关键配置更改, 或者对任何差异只是简单地恢复集群状态,回到deployer声明的状态。 例如,如果deployer指定某pod需要三个运行实例,此数据存储在etcd中。 如果发现只有两个实例正在运行,则将通过与etcd数据对比发现此不同, Kubernetes根据此不同来安排创建该pod的第3个实例。 .. option:: API服务器(API server) :: API服务器是一个关键组件并提供Kubernetes API 服务 Kubernetes API是JSON格式数据的HTTP接口 Kubernetes API提供了Kubernetes的内部和外部接口。 API服务器处理并验证REST请求并更新etcd中的API Object状态数据 从而允许客户端在Worker节点之间配置工作负载和容器。 .. option:: 调度器(Scheduler) :: 调度程序是可插拔式组件,基于资源可用性来选择未调度的pod应该运行哪个节点。 调度程序跟踪每个节点上的资源利用率,以确保工作负载不会超过可用资源。 为此,调度程序必须知道: 资源需求, 资源可用性 以及各种其他用户提供的约束和策略指令,例如: 服务质量,关联性/反关联性要求,数据位置等 调度器的本质作用是将资源“供应”匹配给工作负载“需求” .. option:: 控制器管理(Controller Manager) :: 控制器管理器:控制器是一个协调循环(reconciliation loop), 通过管理一组控制器来实现,它将实际的集群状态驱动到所需的集群状态。。 复制控制器(replication controller): 它通过在集群中运行指定数量的pod副本来处理复制和扩展。 如果底层节点出现故障,它还会处理创建替换pod的问题。 DaemonSet Controller(核心Kubernetes系统一部分): 用于在每台机器(或某些机器的子集)上运行一个pod Job Controller(核心Kubernetes系统一部分): 作为批处理工作的一部分,用于运行到完成。 控制器管理的pod集由标签选择器确定,这些标签选择器是控制器定义的一部分。 控制器管理器是核心Kubernetes控制器的一个进程, 其包括DaemonSet控制器和复制控制器等。 该控制器可与API服务器进行通信以在需要时: 创建,更新和删除他们管理的资源(pod,服务端点等) Kubernetes node --------------------- Node也称为Worker或Minion,是部署容器(工作负载)的单机器(或虚拟机)。集群中的每个节点都必须具备容器的运行环境(runtime)——比如 Docker,以及下面提到的其他组件,以便与这些容器的网络配置进行通信。 .. option:: Kubelet :: Kubelet负责每个节点的运行状态(即确保节点上的所有容器都正常运行)。 它按照控制面板的指示来处理启动,停止和维护应用程序容器(按组织到pod中)。 Kubelet会监视pod的状态,如果pod没有处在所需状态,则此pod将被重新部署到此节点。 节点状态每隔几秒通过消息中继到主控器。 一旦主控器检测到节点故障后,复制控制器监控此状态更改,就会在其他健康节点上启动pod。 .. option:: 容器(Container runtime) :: 容器从属于pod。在运行应用、库及其依赖的微服务中,容器是最低层级的。 通过绑定一个外部IP,容器可以被外网访问。 Kubernetes从第一个版本开始就支持Docker容器,并在2016年7月添加了rkt容器引擎。 .. option:: Kube代理(Kube-proxy) :: Kube代理是网络代理和负载均衡的实现,支持服务抽象以及其他网络操作。 根据传入请求的IP和端口,该组件会将流量路由到合适的容器中。 .. option:: cAdvisor :: 是监视和收集例如每个节点上的容器的CPU,内存,文件和网络使用情况等的资源使用情况和性能指标的代理组件 附加组件(Add-ons) -------------------- 附加组件的运行方式与集群中运行的任何其他应用程序类似,都通过pod和服务实现,只是附加组件实现的是Kubernetes集群的功能。可以通过Deployments,ReplicationControllers等管理pod。附加组件还在增加中,其中最重要的几个组件是: .. option:: DNS :: 所有Kubernetes集群都应具有集群DNS;这是一项强制性功能。 集群DNS是DNS服务器,为Kubernetes服务提供DNS记录。 Kubernetes启动的容器会在DNS搜索中自动包含DNS服务器。 .. option:: Web UI :: 这是Kubernetes集群的基于Web的通用UI。 它允许用户管理和解决运行在集群中的应用程序和集群本身。 .. option:: 容器资源监控 :: 提供可靠的应用程序运行时,并能够根据工作负载进行扩展或缩小, 这意味着能够持续有效地监控工作负载性能。 容器资源监视通过在中央数据库中记录有关容器的度量标准来提供此功能, 并提供用于浏览该数据的UI。 cAdvisor是slave节点上的一个组件,它提供有限的度量监视功能。 还有完整的指标管道,如Prometheus,它可以满足大多数监控需求。 .. option:: 集群级日志记录 :: 日志应具有独立于节点(node),pod或容器(container)的单独存储和生命周期。 否则,节点或pod故障可能导致事件数据丢失。 执行此操作的能力称为集群级日志记录,此类机制负责将容器日志保存到具有搜索/浏览界面的中央日志存储。 Kubernetes没有为日志数据提供本地存储解决方案, 但可以将许多现有的日志记录解决方案集成到Kubernetes集群中。 收集 ==== * 水平触发(Level Triggered,也称条件触发): select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll()的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息。 epoll版本: 当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!! * 边缘触发(Edge Triggered): 只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发。 epoll版本: 当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!! * 说明: 两者都会带来一系列问题:例如当100字节到达后,应用程序只读取了一部分,然后重新等待,此时水平触发的API会始终提醒应用程序;而边缘触发的则不会发出任何提醒。因此后者应执行到recv返回EWOULDBLOCK为止。而对于水平触发而言,如果关注了socket可写事件,当写缓冲始终可用的时候,就会一直得到可写提醒,造成CPU负载过高。 * 阻塞IO:当你去读一个阻塞的文件描述符时,如果在该文件描述符上没有数据可读,那么它会一直阻塞(通俗一点就是一直卡在调用函数那里),直到有数据可读。当你去写一个阻塞的文件描述符时,如果在该文件描述符上没有空间(通常是缓冲区)可写,那么它会一直阻塞,直到有空间可写。以上的读和写我们统一指在某个文件描述符进行的操作,不单单指真正的读数据,写数据,还包括接收连接accept(),发起连接connect()等操作… * 非阻塞IO:当你去读写一个非阻塞的文件描述符时,不管可不可以读写,它都会立即返回,返回成功说明读写操作完成了,返回失败会设置相应errno状态码,根据这个errno可以进一步执行其他处理。它不会像阻塞IO那样,卡在那里不动!!! 说明:: select()/poll()模型都是水平触发模式, 信号驱动I/O是边缘触发模式, epoll()模型既支持水平触发,也支持边缘触发,默认是水平触发。 :: 云原生、中台、微服务、CI/CD、Devops、SaaS在云原生时代是相辅相成的: 云原生好比集装箱革命,货船可以类比操作系统,集装箱类比容器,里面装的货物则是一个个的微服务, 吊臂、吊桥、起重机等自动化操作设备是Kubernetes,而一整套集装箱的操作方法和流程则是DevOps。 所有这些加起来构成了现代PaaS所具备的能力:操作系统、集群管理、应用编排、应用发布、持续集成等等。