Kubernetes概述
Kubernetes简介
Kubernetes是什么
Kubernetes是一个可移植的、可扩展的、用于管理容器化工作负载和服务的开源平台,它简化(促进)了声明式配置和自动化。它有一个庞大的、快速增长的生态系统。Kubernetes的服务、支持和工具随处可见。
Kubernetes一词源于希腊语,意为舵手或飞行员。2014年,谷歌开放了Kubernetes项目的源代码。Kubernetes基于谷歌在大规模运行生产工作负载方面的15年经验,以及来自社区的最佳想法和实践。
使用 Kubernetes, 我们可以快速高效地响应客户需求:
- 快速、可预测地部署你的应用程序
- 拥有即时扩展应用程序的能力
- 不影响现有业务的情况下,无缝地发布新功能
- 优化硬件资源,降低成本
Kubernetes的目标是构建一个软件和工具的生态系统,以减轻你在公共云或私有云运行应用程序的负担。
Kubernetes简史
源自谷歌的Borg,Borg是谷歌公司的内部容器管理系统。
Borg系统运行几十万个以上的任务,来自几千个不同的应用,跨多个集群,每个集群(cell)有上万个机器。它通过管理控制、高效的任务包装、超售、和进程级别性能隔离实现了高利用率,它支持高可用性应用程序与运行时功能,最大限度地减少故障恢复时间,减少相关故障概率的调度策略,该项目的目的是实现资源管理的自动化以及跨多个数据中心的资源利用率最大化,Kubernetes项目的目的就是将Borg最精华的部分提取出来,使现在的开发者能够更简单、直接地应用。它以Borg为灵感,但又没那么复杂和功能全面,更强调了模块性和可理解性。
部署模式发展
让我们把时间回溯到从前,看看为什么Kubernetes是如此有用
物理单机部署
早期在物理服务器上运行应用程序也叫做传统的部署。
- 在商用服务计算领域几乎都是以单机为基础计算单元对计算资源 进行管理和协调控制的
- 部署新应用往往需要购买一台物理机器或者一组机器,并在机器上进行构建,部署和运行,而且一台机器往往只能运行单个应用,成本高,利用率低
虚拟化部署
作为解决方案,引入了虚拟化,它允许您在单个物理服务器的CPU上运行多个虚拟机(VM)虚拟化允许在VM之间隔离应用程序,并提供安全级别,因为一个应用程序的信息不能被另一应用程序自由访问
虚拟化可以更好地利用物理服务器中的资源,并可以实现更好的可伸缩性,因为可以轻松地添加或更新应用程序,降低硬件成本等等。借助虚拟化,您可以将一组物理资源呈现为一组一次性虚拟机。
每个VM都是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。
容器部署部署
容器类似于VM,但是它们具有轻松的隔离属性,可以在应用程序之间共享操作系统(OS)
因此,容器被认为是轻质的,与VM相似,容器具有自己的文件系统,CPU,内存,进程空间等,由于它们与基础架构分离,因此可以跨云和OS分发进行移植
容器化优势
容器已经变得很流行,因为它们提供了额外的好处,比如:
- 敏捷应用程序创建和部署:与使用VM镜像相比,增加了容器镜像创建的方便性和效率
- 持续开发、集成和部署:提供可靠且频繁的容器镜像构建和部署,具有快速且轻松的回滚
- 开发和运维关注点分离:在构建/发布时而不是部署时创建应用程序容器镜像,从而将应用程序与基础设施分离
- 可观察性:不仅能显示操作系统级的信息和指标,还能显示应用程序的健康状况和其他信号
- 跨开发、测试和生产的环境一致性:在笔记本电脑上运行与在云上运行完全相同
- 云和操作系统发布的可移植性:运行在Ubuntu, RHEL, CoreOS, on-prem,谷歌Kubernetes引擎,和其他任何地方
- 以应用程序为中心的管理:将抽象级别从在虚拟硬件上运行操作系统提高到使用逻辑资源在操作系统上运行应用程序
- 松散耦合、分布式、弹性、解放的微服务:应用程序被分解成更小的独立部分,可以动态地部署和管理——而不是运行在一台大型单用途机器上的单片堆栈
- 资源隔离:可预测的应用程序性能
- 资源利用:效率高,密度大
Kubernetes发展历程
Kubernetes 是 Google 开源的容器编排系统,2014 年对外宣布,2015 年发布 1.0 版本,同年 Google 与 Linux 基金会一起成立云原生计算基金会(CNCF-Cloud Native Computing Foundation),并把 Kubernetes 作为种子产品捐赠给了 CNCF,Google 一直在带领着 Kubernetes 的开发,我们也可以看到 CNCF 的 Kubernetes 项目代码贡献量,Google 所占比重是最高的。
发展时间线
Google 在容器领域拥有超过 15 年的经验。
- 2003 年,Google 内部几个工程师做了一个集群自动化管理的工具,叫做 Borg;
- 2012 年,Google Borg 升级成 Omega,实现容器的管理;
- 2013 年,随着业界 Docker 发布,整个行业开始往容器方向迁移;
- 2014 年,Borg/Omega 开源为 Kubernetes 项目;
- 到如今,Kubernetes 已经成为整个容器编排的主流技术。
为什么需要Kubernetes
容器是捆绑和运行应用程序的好方法。
在生产环境中,你需要管理运行应用程序的容器,并确保没有停机时间,例如,如果一个容器发生故障,则需要启动另一个容器,如果这个行为由一个系统来处理不是更容易吗?
这就是Kubernetes的救援方法!Kubernetes为您提供了一个可弹性运行分布式系统的框架。它负责应用程序的扩展和故障转移,提供部署模式等,例如,Kubernetes可以轻松管理系统的Canary部署。
Kubernetes为你提供了一个能够弹性地运行分布式系统的框架。它负责处理应用程序的扩展和故障转移,提供部署模式,等等。
Kubernetes提高的功能
一个平台搞定所有
使用 Kubernetes,部署任何应用都是小菜一碟,只要应用可以打包进容器,Kubernetes 就一定能启动它。
不管什么语言什么框架写的应用(Java, Python, Node.js),Kubernetes 都可以在任何环境中安全的启动它,物理服务器、虚拟机、云环境。
云环境无缝迁移
如果你有换云环境的需求,例如从 GCP 到 AWS,使用 Kubernetes 的话,你就不用有任何担心。
Kubernetes 完全兼容各种云服务提供商,例如 Google Cloud、Amazon、Microsoft Azure,还可以工作在 CloudStack, OpenStack, OVirt, Photon, VSphere。
高效的利用资源
看下图,左边,是4个虚拟机,黄色和蓝色部分是运行的应用,白色部分是未使用的内存和处理器资源。
Kubernetes 如果发现有节点工作不饱和,便会重新分配 pod,帮助我们节省开销,高效的利用内存、处理器等资源。
如果一个节点宕机了,Kubernetes 会自动重新创建之前运行在此节点上的 pod,在其他节点上运行。
开箱即用的自动缩放能力
网络、负载均衡、复制等特性,对于 Kubernetes 都是开箱即用的。
pod 是无状态运行的,任何时候有 pod 宕了,立马会有其他 pod 接替它的工作,用户完全感觉不到。
如果用户量突然暴增,现有的 pod 规模不足了,那么会自动创建出一批新的 pod,以适应当前的需求。
反之亦然,当负载降下来的时候,Kubernetes 也会自动缩减 pod 的数量。
使 CI/CD 更加简单
你不必精通于 Chef 和 Ansible 这类工具,只需要对 CI 服务写个简单的脚本然后运行它,就会使用你的代码创建一个新的 pod,并部署到 Kubernetes 集群里面。
应用打包在容器中使其可以安全的运行在任何地方,例如你的 PC、一个云服务器,使得测试极其简单。
可靠性
Kubernetes 如此流行的一个重要原因是:应用会一直顺利运行,不会被 pod 或 节点的故障所中断。
如果出现故障,Kubernetes 会创建必要数量的应用镜像,并分配到健康的 pod 或节点中,直到系统恢复,而且用户不会感到任何不适。
Kubernetes的优势
虽然Kubernetes并不是市场里唯一的容器管理平台(还有Docker Swarm和Mesos),但是它更受欢迎。
从高层看,Kubernetes正获得关注,因为它提供了这样一个平台,容器化的应用程序可以只编写一次,就能够在所有类型的云供应商以及私有云上运行,无论底层使用的是哪种基础架构,而且Kubernetes还在发展,让开发人员能够在Kubernetes上运行任意适合的应用程序,Sam Ghods,Box的联合创始人认为只要是能运行的二进制文件,就可以运行在Kubernetes上。
使用Kubernetes,开发人员可以快速部署应用程序,而无需担心传统平台上的诸多风险(想想跨多OS环境的垂直扩展),可以随时扩展应用程序,并且更好地分配资源
硬件使用量的下降是使用Kubernetes带来的另一个好处,一些公司报告由于容器的轻量天性,以及能够快速杀死不需要的实体(和传统架构相比),硬件使用量减少了40-50%
Kubernetes的缺点
Kubernetes受到了广泛的称赞,但是它也有一些缺点
当第一次使用它做部署(大规模)时,它很复杂,并且很难搭建,它要求具有特定技能的工程师,在现在的行业里可能很难找到。
Kubernetes作为容器的第三方管理系统,容器技术本身的缺陷和成长之痛会影响到Kubernetes所能够提供的服务
Kubernetes欠缺的领域是调度器,默认的Kubernetes调度器依赖于应用程序所有者提供的分配资源的需求,而不管实时使用量,这个方案会加重每个节点上的资源分片情况。
可以做什么
Kubernetes
是容器集群管理系统,是一个开源的平台,可以实现容器集群的自动化部署、自动扩缩容、维护等功能,使用Kubernetes
可以:
- 自动化容器的部署和复制
- 随时扩展或收缩容器规模
- 将容器组织成组,并且提供容器间的负载均衡
- 很容易地升级应用程序容器的新版本
- 节省资源,优化硬件资源的使用
- 提供容器弹性,如果容器失效就替换它,等等…
K8s特点
- 便携性:支持公有云、私有云、混合云、多重云(multi-cloud)
- 可扩展:模块化、插件化、可组合、可挂载
- 自修复:自动部署,自动重启,自动复制,自动伸缩扩展
Kubernetes架构
Kubernetes是一个开源的编排引擎,用于自动部署、扩展、管理和提供托管容器化应用程序的基础架构,在基础架构级别,Kubernetes集群由一组物理或虚拟机组成,每个机器都以特定角色运行。
Kubernetes组件
当你部署Kubernetes的时候,你会得到一个集群
一个集群是一组机器,称为节点(nodes),它们运行由Kubernetes管理的容器化应用程序。
一个集群至少有一个工作节点(worker node)和一个主节点(master node)
工作节点承载应用程序的组件,主节点管理集群中的工作节点和pods。多个主节点用于提供具有故障转移和高可用性的集群。
Master节点
Master组件提供集群的控制面板,Master组件对集群做出全局决策(例如,调度),Master组件检测并响应集群事件(例如,当部署的replicas字段不满足时启动一个新的pod)
Master组件可以在集群中的任何机器上运行,但是,为了简单起见,设置脚本通常在同一台机器上启动所有Master组件,并且不在这台机器上运行用户容器,Master节点负责管理Kubernetes集群,它们管理pod的生命周期,pod是Kubernetes集群内部署的基本单元
- kube-apiserver - 主要组件,为其他master组件公开API。
- etcd - 分布式密钥/值存储库,Kubernetes使用它来持久化存储所有集群信息。
- kube-scheduler – 依照pod规范中的信息,来决定运行pod的节点。
- kube-controller-manager - 负责节点管理(检测节点是否出现故障)、pod复制和端点创建。
- cloud-controller-manager - 守护进程,充当API和不同云提供商工具(存储卷、负载均衡器等)之间的抽象层。
kube-apiserver/api接口
API服务器是一个Kubernetes面板控制组件,用于公开Kubernetes API,它是Kubernetes控制面板的前端
Kubernetes API服务器的主要实现是kube-apiserver,kube-apiserver被设计成水平伸缩——也就是说,它通过部署更多实例来伸缩。你可以运行kube-apiserver的多个实例,并在这些实例之间平衡流量
Kubernetes API 是 Kubernetes 控制平面的前端,用于处理内部和外部请求,API 服务器会确定请求是否有效,如果有效,则对其进行处理,您可以通过 REST 调用、kubectl 命令行界面或其他命令行工具(例如 kubeadm)来访问 API,我们需要搭建集群,可以安装基数节点的kube-apiserver,然后可通过负载均衡器做集群。
kube-scheduler/k8s pod调度器
监视没有分配节点的新创建的pod,并为它们选择要运行的节点。
K8s 调度程序,您的集群是否状况良好?如果需要新的容器,要将它们放在哪里?这些是 Kubernetes 调度程序所要关注的问题。
调度程序会考虑容器集的资源需求(例如 CPU 或内存)以及集群的运行状况。随后,它会将容器集安排到适当的计算节点。
需部署在 master 节点上,该组件监视那些新创建的未指定运行节点的 Pod,并选择节点让 Pod 在上面运行,调度决策考虑的因素包括单个 Pod 和 Pod 集合的资源需求、硬件/软件/策略约束、亲和性和反亲和性规范、数据位置、工作负载间的干扰和最后时限
kube-controller-manager/k8s管理器
K8s 控制器,控制器负责实际运行集群,而 Kubernetes 控制器管理器则是将多个控制器功能合而为一
运行控制器的组件,从逻辑上讲,每个控制器都是一个单独的进程,但是为了降低复杂性,它们都被编译成一个单一的二进制文件,并在一个进程中运行
控制器用于查询调度程序,并确保有正确数量的容器集在运行。如果有容器集停止运行,另一个控制器会发现并做出响应。控制器会将服务连接至容器集,以便让请求前往正确的端点。还有一些控制器用于创建帐户和 API 访问令牌。
需部署在 master 节点上,从逻辑上讲,每个控制器都是一个单独的进程,但是为了降低复杂性,它们都被编译到同一个可执行文件,并在一个进程中运行。
这些控制器包括:
节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应
副本控制器(Replication Controller): 负责为系统中的每个副本控制器对象维护正确数量的 Pod
端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 与 Pod)
服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌
etcd/k8s后台数据库
一致性和高可用的键值存储用作Kubernetes的所有集群数据备份存储。
配置数据以及有关集群状态的信息位于 etcd(一个键值存储数据库)中,etcd 采用分布式、容错设计,被视为集群的最终事实来源。
Node节点
Node组件在每个节点上运行,维护运行的pods并提供Kubernetes运行时环境
Node节点是Kubernetes中的worker机器,受到master的管理,节点可以是虚拟机(VM)或物理机器——Kubernetes在这两种类型的系统上都能良好运行
- kubelet – 为位于那个节点上的pod监视API服务器,确保它们正常运行
- kube-proxy - 监视API服务器,实时获取pod或服务的变化,以使网络保持最新
- 容器运行时 - 负责管理容器镜像,并在该节点上运行容器
- cAdvisor - 收集在特定节点上运行着的pod的相关指标
kubelet
一个在集群中每个node上运行的代理
它保证容器都 运行在 Pod 中,kubelet 定期接收新的或修改过的 pod 规范 PodSpecs(主要通过 kube-apiserver)并确保 pod 及容器健康并以所需状态运行。该组件还向 kube-apiserver 报告运行它的主机的健康状况,kubelet 不会管理不是由 Kubernetes 创建的容器。
kube-proxy
kube-proxy 是集群中每个节点上运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分
用于处理单个主机子网划分并向外部世界公开服务。它跨集群中的各种隔离网络将请求转发到正确的 pod/容器
kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与 Pod 进行网络通信。
如果操作系统提供了数据包过滤层并可用的话,kube-proxy 会通过它来实现网络规则。否则, kube-proxy 仅转发流量本身。
容器运行时(Container Runtime)
容器运行时负责创建容器运行环境,Kubernetes 支持多个容器运行时: Docker(即将被废弃)、containerd、CRI-O以及任何实现 Kubernetes CRI (容器运行环境接口)的runtime
每一个Node都会运行一个Container Runtime,其负责下载镜像和运行容器,Kubernetes本身并不停容器运行时环境,但提供了接口,可以插入所选择的容器运行时环境,kubelet使用Unix socket之上的gRPC框架与容器运行时进行通信,kubelet作为客户端,而CRI shim作为服务器。
cAdvisor
cAdvisor是一个开源代理,它能够监视资源使用情况并分析容器的性能,cAdvisor最初由谷歌创建,现在已与kubelet集成
位于每个节点上的cAdvisor实例,会收集、聚合、处理和导出所有正在运行的容器的指标,如CPU、内存、文件和网络使用情况等。所有数据都将发送到调度程序,以确保调度程序了解节点内部的性能和资源使用情况。这些信息会被用于执行各种编排任务,如调度、水平pod扩展、管理容器资源限制等
Kubernetes核心概念
Pod
我们可以将 Pod 和虚拟机做下类比,每个虚拟机里可以运行多个进程,每个 Pod 里也可以运行多个容器,容器的本质就是进程,多个容器之间可以通过
localhost
进行访问,容器间也可以共享数据卷
这一切是如何做到的呢?其实在 Pod 里最先启动的容器并不是我们的应用容器,而是有一个辅助容器叫做 infra(k8s.gcr.io/pause),infra 是 Pod 中最先启动的容器,它负责为 Pod 创建网络和共享存储,而我们的应用容器只是连接了 infra 容器创建的网络和数据卷,这样就达到了共享网络空间和数据卷的目的。
从以上 Pod 的结构图可以看出,它其实是容器的一个上层包装结构,这也就是为什么 K8s 可以支持多种容器类型的原因,基于这方面, k8s 的定位就是一个编排与调度工具,而容器只是它调度的一个资源对象而已。
Pod 可包含多个容器在里面,每个 Pod 至少会有一个 Pause 容器,其它用户定义的容器都共享该 Pause 容器,Pause 容器的主要作用是用于定义 Pod 的 ip 和 volume。
Pod 在 k8s 集群中的位置如下图所示:
Label
Label 在 k8s 中是一个非常核心的概念,我们可以将 Label 指定到对应的资源对象中
例如 Node、Pod、Replica Set、Service 等,一个资源可以绑定任意个 Label,k8s 通过 Label 可实现多维度的资源分组管理,后续可通过 Label Selector 查询和筛选拥有某些 Label 的资源对象,例如创建一个 Pod,给定一个 Label,workerid=123,后续可通过 workerid=123 删除拥有该标签的 Pod 资源。
ReplicaSet
ReplicaSet 这个控制器就是为了启动多个 Pod 副本设计的,我们通过 ReplicaSet 重新部署这个应用。
假设 Replica Set 定义 Pod 的副本数目为:replicas=2,当该 Replica Set 提交给 Master 后,Master 会定期巡检该 Pod 在集群中的数目,如果发现该 Pod 挂掉了一个,Master 就会尝试依据 Replica Set 设置的 Pod 模版创建 Pod,以维持 Pod 的数量与 Replica Set 预期的 Pod 数量相同。
通过 Replica Set,k8s 集群实现了用户应用的高可用性,而且大大减少了运维工作量。因此生产环境一般用 Deployment 或者 Replica Set 去控制 Pod 的生命周期和期望值,而不是直接单独创建 Pod。
类似 Replica Set 的还有 Deployment,它的内部实现也是通过 Replica Set 实现的,可以说 Deployment 是 Replica Set 的升级版,它们之间的 yaml 配置文件格式大部分都相同。
Deployment
一个 ReplicaSet 对象,其实就是由副本数目的定义和一个 Pod 模板组成的,不难发现,它的定义其实是 Deployment 的一个子集。Deployment 控制器实际操纵的正是这样的 ReplicaSet 对象,而不是 Pod 对象
和ReplicaSet区别
Deployment 与 ReplicaSet 以及 Pod 的关系是怎样的呢,Deployment 与它的 ReplicaSet 以及 Pod 的关系,实际上是一种“层层控制”的关系
ReplicaSet 负责通过“控制器模式”,保证系统中 Pod 的个数永远等于指定的个数(比如,3 个),这也正是 Deployment 只允许容器的 restartPolicy=Always 的主要原因:只有在容器能保证自己始终是 Running 状态的前提下,ReplicaSet 调整 Pod 的个数才有意义。而在此基础上,Deployment 同样通过“控制器模式”,来操作 ReplicaSet 的个数和属性,进而实现“水平扩展 / 收缩”和“滚动更新”这两个编排动作。
Service
集群中的每一个 Pod 都可以通过 Pod IP 直接访问,但是正如我们所看到的,Kubernetes 中的 Pod 是有生命周期的,尤其是被 ReplicaSet、Deployment 等对象管理的 Pod,随时都有可能被销毁和重建
Kubernetes 中的 Service 对象将一组 Pod 以统一的形式对外暴露成一个服务,它利用运行在内核空间的 iptables 或 ipvs 高效地转发来自节点内部和外部的流量
和pod关系
本文上面提及的 Pod、Replica Set 等都是为 Service 服务的资源, 如下图表示 Service、Pod、Replica Set 的关系
从上图可看出,Service 定义了一个服务访问的入口,客户端通过这个入口即可访问服务背后的应用集群实例,而 Service 则是通过 Label Selector 实现关联与对接的,Replica Set 保证服务集群资源始终处于期望值。
Namespace
Namespace 顾名思义是命名空间的意思,在 k8s 中主要用于实现资源隔离的目的
用户可根据不同项目创建不同的 Namespace,通过 k8s 将资源分配到不同 Namespace 中,即可实现不同项目的资源隔离: