容器技术思想 Docker K8S
容器技术介绍
- 以Docker为代表的容器技术解决了程序部署运行方面的问题。在容器技术出现前,程序直接部署在物理服务器上,依赖管理复杂,包括各类运行依赖,且易变,多程序混合部署时还可能产生依赖冲突,给程序部署、管理效率和稳定性带来挑战。
虚拟机部署的缺陷
- 虚拟机技术虽解决依赖问题,但存在镜像过大(存储和传输成本高、运行成本高)、启停速度过慢、运行性能损耗大等问题。
容器技术的发展
- 解决镜像过大问题
- 利用联合文件系统(UnionFS),只保存一份相同文件的指针或链接,修改时再复制,减少存储空间。该技术2004年已出现,最初用于提供统一文件系统视图。
- 解决启停速度过慢问题
- Linux发展出name space和c group隔离技术,实现程序在多方面的专属隔离空间和配额,形成轻量化虚拟机(容器),其启停速度与原生进程相近,相关技术2008年基本成型。
- 解决性能损耗问题
- 容器内进程共用内核,消除了维护独立内核的重复和冗余开销,降低了软件层面的性能损耗;硬件层面,通用硬件虚拟化损耗已降低,但特殊硬件仍存在损耗,不过有望最终消除。
Docker的作用及意义
- Docker将容器基础技术(联合文件系统和轻量化隔离能力)打包,制定容器镜像和运行标准,提供工具,使用户友好地管理程序及其依赖环境,作为独立单元交付。其命名形象地体现了功能,像集装箱一样打包软件运行相关的东西为镜像,变革了软件部署和分发模式,将软件部署依赖的复杂性封装在镜像管理中,实现标准化交付。
K8S相关知识总结
一、K8S的广泛应用及引出问题
(一)工业界广泛使用K8S
在工业界实践中,有一定规模的公司、企业或团队广泛使用K8S这种容器技术形式,而非仅使用docker。主流中大型互联网公司及部分非互联网行业公司提供的软件程序多运行在K8S里,意味着我们每天使用软件时间接使用了K8S。
二、K8S出现的原因
(一)容器技术大规模应用后的问题
- 管理复杂:单机上容器可用docker管理,但企业规模扩大,应用和机器数量增多时,容器管理变得复杂,传统运维脚本管理方式存在诸多弊端,如操作管理效率低、具备人工误操作风险、对工程师来说是高重复性且枯燥的数字性操作。
- 缺失全局记录:多台机器上做容器化部署后,默认没有记录存储机制,无法感知应用程序在多台机器上的分布和运行情况,需自己建设管控系统记录并管理信息。
- 精细化控制操作成本高:实现一组应用程序的受控分批化、逐步升降级、根据资源使用情况进行扩缩容调整、机器宕机后对应用程序进行转移恢复等操作行为规划执行成本高。
- 难以进行高效的资源管理:涉及计算内存存储网络异构算力等资源的管理和供给,包括如何放置应用以降低资源碎片率、提高机器集群整体资源利用率等问题。
- 服务难以高效管理和治理:在微服务化背景下,应用服务之间在大规模机器集群上的互相感知、互联、协作,以及每个服务的配置跟踪、修改和管理,服务暴露给用户访问等方面存在问题。
(二)K8S的功能定位与理念核心
- 功能定位:K8S是为解决容器化应用在大规模机器集群部署场景中的问题而设计的管理系统,被称为容器编排系统,与管控系统在定义视角上有差异,编排是更上层更宏观且关注结果的视角,管控是更底层微观关注操作过程的视角,这一差异是K8S理念中最核心的一点。
- 理念核心:K8S在当时一堆解决方案项目中解决相关问题最成功,其核心思想之一是“面向终态”。
三、K8S核心思想“面向终态”阐述
(一)“面向终态”的含义
- 类似控制系统示例:如马桶水箱(终态是水箱内水达到指定水位)、冰箱热水器空调(终态是关注对象温度达到指定值)、自动驾驶汽车启用定速巡航功能(终态是达到设定的行驶速度)等,这些都是面向终态的控制系统,其关键在于让控制逻辑感知现状,根据感知状态进行针对性操作,最终达成目标终态,且终态动态变化,整个系统处于动态平衡。
- 在K8S中的体现:K8S要解决大规模容器化程序应用在大规模机器集群内的高效部署管理问题,可分解为操作、目标终态和最终目的三部分,目标终态是操作和最终目的之间的关键纽带。K8S面向终态的设计思想关注目标终态,将达成目标终态的操作进行自动化、公共化和抽象化,通过声明式API体现,使用YAML写入期望终态,K8S自动操作实现。
(二)“面向终态”思想带来的效果
- 自动化标准化通用操作流程
- 操作特点与流程标准化:对程序在大规模机器集群内的部署管理,大部分操作重复且有高度自动化可能性,K8S将如重启、升级、增加计算资源等基本操作流程固定的操作标准化自动化,这些操作和容器运行的程序无关,仅外部参数变化,如应用名、版本号、增加的计算资源数目等。
- 提升管理效率与稳定性:消除了管理运维人员重复繁重枯燥的手动人工操作和人工误操作风险,提升了管理效率和稳定性水平,释放技术红利,如同编程中封装公共函数。
- 重试机制
- 天然重试结果:面向终态思想下,当操作不符合预期,会因比较现状与目标终态差异而立即重试,重试成为天然结果,降低了人工操作重试成本。
- 实际案例:很多企业采用K8S后,服务异常能被迅速重写垃圾恢复,开发人员可能意识不到程序问题,因为K8S快速及时的重启执行避免了服务崩溃对外暴露问题。
- 实现全局记录
- 记录机制必要性:面向终态要时刻比较当下和目标终态差异,所以对当下目标终态信息记录是必要条件,K8S提供此功能。
- 记录机制优势:管理容器化程序和机器时有了记录机制,每一个部署的程序管理范围内的机器及彼此关系有明确记录,且能实时更新,可近乎实时感知程序和机器状态并做针对性调整,极大提升管理效率。
- 降低门槛
- 操作自动化标准化的影响:所有具体操作行为被自动化和标准化,运维人员无需关注达成目标终态的每一步细节操作,降低了管理程序和机器集群的门槛。
- 关注点改变与问题解决高效性:运维人员从关注过程变为关注结果,描述结果比描述过程简单,使问题解决更高效,受益人员主要是运维人员及运营操作人员。例如把大象放到冰箱里,关注结果时只需输出需求结果,无需考虑实施过程。
(三)“面向终态”解决的问题
-
管理操作效率低:面向终态后,高频重复操作自动化标准化,管理人员无需操心操作执行细节。
-
缺失全局记录:因面向动态需获知各类目标资源对象状态,所以有实时性的全局记录。
-
精细化控制操作成本高:基于自动化标准化基本操作和K8S的开源开放扩展性,开发人员可开发定制化精细化控制操作,用户无需关心实现细节即可重复使用,小白用户也能轻松完成精细化控制操作。
-
K8S解决资源分配、管理和调度问题
- 调度问题普遍性与本质:调度在多领域常见,本质是决定资源分配以达最优效果,K8S调度场景是在集群内安置应用程序以实现最大资源利用率,且资源利用率常与服务质量权衡,不同场景调度目标不同。
- K8S调度框架与默认策略
- 通用调度框架:K8S提供通用框架,以默认调度策略为例,其核心是过滤和打分。
- 过滤筛选满足容器组需求的节点,
- 打分根据规则对可调度节点打分并选得分最高节点(多节点时随机选),
- 可将调度简化为单纯打分。
- 默认打分策略:1.30版本默认策略包含污点容忍、节点亲和性等多种情况,权重各异。可分为用户主动指定偏好(权重较高)和客观资源条件(权重较低)两类,策略权重、计算方法及资源概念均可自定义,使K8S能满足不同调度需求,提升资源使用和满足各类诉求。
-
K8S解决服务管理问题
- 微服务与K8S关系:微服务流行时与容器、K8S技术相互促进,微服务理念是拆分单体应用为多个微型服务,这使服务数量上升,部署管理治理变复杂,而容器和K8S可解决这些问题。
- K8S对微服务架构功能范式的满足
- 配置中心:通过config map及secret实现配置管理,应用可挂载获取配置,用户修改配置可实时同步到应用实例。
- 注册中心服务发现:将服务实例管理为service资源,通过K8S API可获知服务,不同服务间可通过service互访。
- 负载均衡:利用kube - proxy组件及内核网络转发机制实现流量在服务实例间均衡分布。
- 网关:通过ingress gateway等资源以声明式提供网关实例,定义基本语义规范和协议接口,给予用户选择空间,K8S在多方面采用此模式。
- 远程调用RPC:出于语言中立性不提供具体RPC框架,将选择权交给用户。
- 限流熔断:因属于网关层和RPC范畴内功能,K8S不考虑此方面内容。K8S基于原中立立场和面向协议接口特点,为微服务架构提供关键能力支持。
-
总结与升华:K8S将应用与无关问题解耦,让专业人员解决,开发者可专注业务价值,专业技术平台可降本增效,符合生产力发展和社会分工趋势。
微服务需求 | K8s优势 | 适配说明 |
---|---|---|
资源管理与调度 | 可根据微服务资源请求调度到合适节点,支持资源限制 | K8s依据各微服务对CPU、内存等资源需求,合理分配资源,避免浪费与抢占,保障各微服务稳定运行 |
服务发现与负载均衡 | 通过Service提供固定虚拟IP,kube - proxy实现负载均衡与网络代理,支持多种服务暴露类型 | 微服务实例动态变化,K8s能让服务相互发现,并均匀分配请求,提高可用性与性能,还方便外部访问 |
自动扩缩容 | 基于CPU利用率等指标的自动扩缩容机制 | 微服务需依业务灵活调整资源,K8s可按设定阈值自动增减Pod副本,确保服务在不同负载下稳定运行 |
部署与管理 | 提供Deployment、StatefulSet等资源管理部署,支持滚动升级与回滚 | 微服务部署复杂,K8s简化流程,实现版本控制,升级时保证服务可用,出现问题可快速回滚 |
故障容错与自愈 | kubelet监控Pod状态,故障时自动重启或重建,控制器确保Pod副本数量 | 分布式系统中微服务易故障,K8s自动检测并修复故障,保证系统可用性 |
配置管理 | 通过ConfigMap和Secret管理配置,支持动态更新 | 各微服务配置不同且环境有别,K8s可集中管理,配置变化时自动更新Pod,无需手动重启 |
微服务与K8S
k8s 核心概念
Kubernetes(简称K8s)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8s的一些核心概念:
1. 节点(Node)
- 定义:Node是K8s集群中的工作机器,可以是物理机或虚拟机。每个Node都运行着Kubelet服务,负责与Master通信,管理Pod和容器的生命周期。
- 作用:Node为Pod提供运行环境,承载容器化应用程序的实际运行实例。它包括CPU、内存、存储等资源,供Pod中的容器使用。
2. Pod
- 定义:Pod是K8s中最小的可部署和可管理的计算单元,它可以包含一个或多个紧密相关的容器。这些容器共享存储、网络和命名空间等资源。
- 作用:Pod提供了一种将多个容器作为一个逻辑单元进行管理的方式,确保它们在同一节点上共同调度和运行。例如,一个Web应用的前端容器和后端API容器可以放在同一个Pod中,它们之间可以通过localhost进行高效通信。
3. 标签(Label)
- 定义:标签是附加到K8s资源(如Pod、Service等)上的键值对,用于对资源进行标识和分类。
- 作用:标签使得用户可以灵活地对资源进行选择和管理。例如,可以通过标签选择特定版本的Pod进行升级或回滚操作,也可以根据功能、环境等不同维度对资源进行分类。
4. 控制器(Controller)
- 定义:控制器用于管理Pod的生命周期,确保实际运行的Pod状态与用户期望的状态一致。常见的控制器类型有Deployment、ReplicaSet、DaemonSet、StatefulSet等。
- 不同类型控制器的作用:
- Deployment:最常用的控制器,用于部署无状态应用程序。它通过创建和管理ReplicaSet来确保指定数量的Pod副本始终处于运行状态,并支持滚动升级和回滚等功能。
- ReplicaSet:确保指定数量的Pod副本持续运行,主要用于保证应用的高可用性。通常由Deployment创建和管理,较少直接使用。
- DaemonSet:确保每个Node上都运行一个Pod副本,常用于运行系统级守护进程,如日志收集代理、监控代理等。
- StatefulSet:用于管理有状态应用程序,如数据库。它为每个Pod提供唯一的标识和稳定的网络标识,确保Pod在重新调度后仍能访问到相同的持久化存储。
5. 服务(Service)
- 定义:Service是一种抽象层,用于为一组功能相同的Pod提供一个固定的网络入口,使得客户端可以通过这个固定的地址访问到Pod,而无需关心Pod的实际IP地址和数量变化。
- 作用:Service提供了服务发现和负载均衡功能。例如,一个Web应用的多个Pod副本可以通过Service进行统一对外暴露,客户端请求会被Service负载均衡到不同的Pod上,提高应用的可用性和性能。常见的Service类型有ClusterIP、NodePort、LoadBalancer等。
- ClusterIP:在集群内部提供一个虚拟IP地址,用于集群内的Pod之间相互通信,默认类型。
- NodePort:在每个Node上开放一个特定端口,通过
<NodeIP>:<NodePort>
的方式可以从集群外部访问到Service。 - LoadBalancer:使用云提供商的负载均衡器,将外部流量引入到集群内部的Service,通常用于面向互联网的应用。
6. 命名空间(Namespace)
- 定义:命名空间是一种虚拟的隔离机制,用于将K8s集群中的资源划分为不同的逻辑组。不同命名空间中的资源名称可以相同,但在同一个命名空间内资源名称必须唯一。
- 作用:命名空间有助于在多租户环境中实现资源的隔离和管理。例如,不同的团队或项目可以使用不同的命名空间,避免资源命名冲突,同时可以对不同命名空间进行独立的资源配额管理。
7. 卷(Volume)
- 定义:卷是Pod中可以被多个容器访问的目录,用于在容器之间共享数据或持久化容器的数据。
- 作用:解决了容器数据持久化和容器间数据共享的问题。例如,一个Web应用的容器可能需要将日志文件写入卷,另一个日志收集容器可以从同一个卷中读取日志文件。常见的卷类型有EmptyDir、HostPath、PersistentVolume等。
- EmptyDir:在Pod创建时创建,Pod删除时销毁,主要用于容器间临时数据共享。
- HostPath:将Node上的文件或目录挂载到Pod中,常用于访问Node上的系统资源。
- PersistentVolume:一种集群级别的资源,用于提供持久化存储,与Pod的生命周期解耦,可被多个Pod使用。
这些核心概念是理解和使用Kubernetes进行容器化应用程序管理的基础,通过它们的协同工作,Kubernetes能够高效地管理大规模容器化应用的部署、运行和扩展。
Kubernetes(K8s)架构通过多种机制来保证高可用性,涵盖控制平面和工作节点等多个层面:
控制平面的高可用性
- 多实例部署
- kube - apiserver:通常会部署多个kube - apiserver实例,并通过负载均衡器(如硬件负载均衡器或软件负载均衡器,如HAProxy、Nginx等)对外提供统一的服务入口。这样,即使某个kube - apiserver实例出现故障,负载均衡器可以将请求转发到其他健康的实例上,保证API服务的连续性。
- etcd:etcd集群采用多节点部署,一般推荐奇数个节点(如3个、5个等),以利用Raft共识算法实现数据的一致性和容错。在etcd集群中,只要大多数节点(超过半数)正常运行,集群就能保持可用,继续提供数据的读写服务。例如,一个由3个节点组成的etcd集群,允许1个节点出现故障;5个节点的集群则允许2个节点故障。
- 自动故障检测与恢复
- kube - controller - manager:其中包含多个控制器,每个控制器负责监控特定资源的状态。例如,ReplicationController会持续监测Pod的副本数量,若实际副本数低于期望数量,会自动创建新的Pod;若高于期望数量,则会删除多余的Pod。这种机制确保了应用程序的运行实例始终符合用户定义的状态,即使部分Pod因节点故障或其他原因终止,也能自动恢复。
- kube - scheduler:如果某个工作节点出现故障,kube - scheduler会感知到节点状态变化,并将原本调度到该故障节点上的Pod重新调度到其他健康的节点上,保证应用程序的正常运行。
工作节点的高可用性
- 节点监控与自动修复
- kubelet:每个工作节点上的kubelet会定期向控制平面汇报节点和Pod的状态信息。控制平面通过这些信息实时监控节点的健康状况,例如节点的CPU、内存、磁盘使用情况以及网络连接状态等。如果发现某个节点出现故障(如硬件故障、网络隔离等),控制平面会将该节点上的Pod重新调度到其他健康节点。
- NodeController:作为kube - controller - manager的一部分,NodeController负责监控节点的状态。当检测到节点失联或故障时,它会执行一系列操作,如将节点标记为不可用,防止新的Pod调度到该节点,并触发对该节点上Pod的重新调度。
- 资源弹性与负载均衡
- kube - proxy:在每个工作节点上运行,负责实现K8s Service的网络代理和负载均衡功能。当客户端请求到达Service时,kube - proxy会根据一定的负载均衡算法(如轮询、随机等)将请求转发到后端的Pod上。这样,即使某个Pod出现故障,kube - proxy可以将流量自动导向其他健康的Pod,确保服务的可用性。同时,随着应用程序负载的增加,用户可以通过增加Pod的副本数量来实现水平扩展,kube - proxy能够自动将流量均匀分配到新增的Pod上。
- 服务发现:Kubernetes的服务发现机制使得客户端应用程序可以动态地发现和连接到后端的服务实例,而无需手动配置服务的IP地址和端口。例如,通过DNS服务(如CoreDNS),Pod可以通过服务名称解析到对应的IP地址,当后端Pod的数量或IP地址发生变化时,DNS记录会自动更新,保证客户端始终能够正确访问到服务。
数据持久化与备份恢复
- etcd数据备份与恢复:由于etcd存储了K8s集群的关键数据,对其进行定期备份至关重要。可以使用etcd自带的备份工具或第三方备份方案,将etcd的数据备份到外部存储(如对象存储、文件系统等)。在etcd集群出现故障导致数据丢失时,可以利用备份数据进行恢复,确保集群状态和配置信息的完整性,从而保障整个K8s集群的高可用性。
- 持久化存储:对于有数据持久化需求的应用程序,Kubernetes支持多种持久化存储方案,如PersistentVolume(PV)和PersistentVolumeClaim(PVC)。这些存储方案可以将容器内的数据存储在独立于Pod生命周期的存储设备上,如网络存储(NFS、iSCSI等)或分布式存储(Ceph等)。当Pod因为节点故障等原因重新调度到其他节点时,它可以挂载之前使用的持久化存储,继续访问和操作数据,保证应用程序的数据连续性和可用性。