Kubernetes权威指南:从Docker到Kubernetes实践全接触(第4版)(txt+pdf+epub+mobi电子书下载)


发布时间:2020-07-01 18:54:34

点击下载

作者:龚正 等

出版社:电子工业出版社

格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT

Kubernetes权威指南:从Docker到Kubernetes实践全接触(第4版)

Kubernetes权威指南:从Docker到Kubernetes实践全接触(第4版)试读:

内容简介

Kubernetes是由谷歌开源的Docker容器集群管理系统,为容器化的应用提供了资源调度、部署运行、服务发现、扩容及缩容等一整套功能。本书从架构师、开发人员和运维人员的角度,阐述了Kubernetes的基本概念、实践指南、核心原理、开发指导、运维指南、新特性演进等内容,图文并茂、内容丰富、由浅入深、讲解全面;并围绕在生产环境中可能出现的问题,给出了大量的典型案例,比如安全配置方案、网络方案、共享存储方案、高可用方案及Trouble Shooting技巧等,有很强的实战指导意义。本书内容随着Kubernetes的版本更新不断完善,目前涵盖了Kubernetes从1.0到1.14版本的主要特性,努力为Kubernetes用户提供全方位的Kubernetes技术指南。本书源码已上传至GitHub的kubeguide/K8sDefinitiveGuide-V4-Sourcecode目录,可自行下载本书源码进行练习。

无论是对于软件工程师、测试工程师、运维工程师、软件架构师、技术经理,还是对于资深IT人士,本书都极具参考价值。

推荐序

经过作者们多年的实践经验积累及近一年的精心准备,本书终于与我们见面了。我有幸作为首批读者,提前见证和学习了在云时代引领业界技术方向的Kubernetes和Docker的最新动态。

从内容上讲,本书从一个开发者的角度去理解、分析和解决问题:从基础入门到架构原理,从运行机制到开发源码,再从系统运维到应用实践,讲解全面。本书图文并茂,内容丰富,由浅入深,对基本原理阐述清晰,对系统架构分析透彻,对实践经验讲解深刻。

我认为本书值得推荐的原因有以下几点。

首先,作者的所有观点和经验,均是在多年建设、维护大型应用系统的过程中积累形成的。例如,读者通过学习书中的Kubernetes开发指南、集群管理等章节的内容,不仅可以直接提高开发技能,还可以解决在实践过程中经常遇到的各种关键问题。书中的这些内容具有很高的借鉴和推广意义。

其次,通过大量的实例操作和详尽的源码解析,本书可以帮助读者深刻理解Kubernetes的各种概念。例如,书中介绍了使用Java程序访问Kubernetes API的几种方法,读者参照其中的案例,只要稍做修改,再结合实际的应用需求,就可以将这些方法用于正在开发的项目中,达到事半功倍的效果,对有一定Java基础的专业人士快速学习Kubernetes的各种细节和实践操作十分有利。

再次,为了让初学者快速入门,本书配备了即时在线交流工具和专业后台技术支持团队。如果你在开发和应用的过程中遇到各类相关问题,均可直接联系该团队的开发支持专家。

最后,我们可以看到,容器化技术已经成为计算模型演化的一个开端,Kubernetes作为谷歌开源的Docker容器集群管理技术,在这场新的技术革命中扮演着重要的角色。Kubernetes正在被众多知名公司及企业采用,例如Google、VMware、CoreOS、腾讯、京东等,因此,Kubernetes站在了容器新技术变革的浪潮之巅,将具有不可预估的发展前景和商业价值。

无论你是架构师、开发者、运维人员,还是对容器技术比较好奇的读者,本书都是一本不可多得的带你从入门到进阶的Kubernetes精品书,值得阅读!初瑞中国移动业务支撑中心高级经理自 序

本书第1版出版于2016年,几年过去,Kubernetes已从一个新生事物发展为一个影响全球IT技术的基础设施平台,也推动了云原生应用、微服务架构、Service Mesh等热门技术的普及和落地。现在,Kubernetes已经成为明星项目,其开源项目拥有超过两万名贡献者,成为开源历史上发展速度超快的项目之一。

在这几年里:

Kubernetes背后的重要开源公司RedHat被IBM大手笔收购,使RedHat基于Kubernetes架构的先进PaaS平台——OpenShift成为IBM在云计算基础设施中的重要筹码;

Kubernetes的两位核心创始人Joe Beda 和Craig McLuckie所创立的提供Kubernetes咨询和技术支持的初创公司Heptio也被虚拟化领域的巨头VMware收购;

Oracle收购了丹麦的一家初创公司Wercker,然后开发了Click2Kube,这是面向Oracle裸机云(Oracle Bare Metal Cloud)的一键式Kubernetes集群安装工具;

世界500强中的一些大型企业也决定以Kubernetes为基础重构内部IT平台架构,大数据系统的一些用户也在努力将其生产系统从庞大的大数据专有技术栈中剥离出来靠拢Kubernetes。

Kubernetes是将“一切以服务(Service)为中心,一切围绕服务运转”作为指导思想的创新型产品,这是它的一个亮点。它的功能和架构设计自始至终地遵循了这一指导思想,构建在Kubernetes上的系统不仅可以独立运行在物理机、虚拟机集群或者企业私有云上,也可以被托管在公有云上。

Kubernetes的另一个亮点是自动化。在Kubernetes的解决方案中,一个服务可以自我扩展、自我诊断,并且容易升级,在收到服务扩容的请求后,Kubernetes会触发调度流程,最终在选定的目标节点上启动相应数量的服务实例副本,这些服务实例副本在启动成功后会自动加入负载均衡器中并生效,整个过程无须额外的人工操作。另外,Kubernetes会定时巡查每个服务的所有实例的可用性,确保服务实例的数量始终保持为预期的数量,当它发现某个实例不可用时,会自动重启该实例或者在其他节点上重新调度、运行一个新实例,这样,一个复杂的过程无须人工干预即可全部自动完成。试想一下,如果一个包括几十个节点且运行着几万个容器的复杂系统,其负载均衡、故障检测和故障修复等都需要人工介入进行处理,其工作量将多大。

通常,我们会把Kubernetes看作Docker的上层架构,就好像Java与J2EE的关系一样:J2EE是以Java为基础的企业级软件架构,Kubernetes则以Docker为基础打造了一个云计算时代的全新分布式系统架构。但Kubernetes与Docker之间还存在着更为复杂的关系,从表面上看,似乎Kubernetes离不开Docker,但实际上在Kubernetes的架构里,Docker只是其目前支持的两种底层容器技术之一,另一种容器技术则是Rocket,Rocket为CoreOS推出的竞争产品。

Kubernetes之所以同时支持Docker和Rocket这两种互相竞争的容器技术,是有深刻的历史原因的。快速发展的Docker打败了谷歌名噪一时的开源容器技术lmctfy,并迅速风靡世界。但是,作为一个已经对全球IT公司产生重要影响的技术,Docker容器标准的制定不可能被任何一个公司主导。于是,CoreOS推出了与Docker抗衡的开源容器项目Rocket,动员一些知名IT公司一起主导容器技术的标准化,并与谷歌共同发起基于CoreOS+ Rocket+Kubernetes的新项目 Tectonic,使容器技术分裂态势加剧。最后,Linux基金会于2015年6月宣布成立开放容器技术项目(Open Container Project),谷歌、CoreOS及Docker都加入了该项目。OCP项目成立后,Docker公司放弃了自己的独家控制权,Docker容器格式也被OCP采纳为新标准的基础,Docker负责起草OCP草案规范的初稿文档,并提交自己的容器执行引擎的源码作为OCP项目的启动资源。

2015年7月,谷歌正式宣布加入OpenStack阵营,其目标是确保Linux容器及其关联的容器管理技术Kubernetes能够被OpenStack生态圈所接纳,这也意味着对数据中心控制平面的争夺已经结束,以容器为代表的应用形态与以虚拟化为代表的系统形态将会完美融合于OpenStack之上,并与软件定义网络和软件定义存储一起主导下一代数据中心。

谷歌凭借着几十年大规模容器使用的丰富经验,步步为营,先是祭出Kubernetes这个神器,然后掌控了容器技术的制定标准,最后入驻OpenStack阵营全力支持Kubernetes的发展。可以预测,Kubernetes的影响力可能超过十年,所以,我们每个IT人都有理由重视这门新技术。

谁能比别人领先一步掌握新技术,谁就能在竞争中赢得先机。慧与中国通信和媒体解决方案领域的资深专家团一起分工协作、并行研究,并废寝忘食地合力撰写,才促成了这部巨著的出版。经过这些年的高速发展,Kubernetes先后发布了十几个大版本,每个版本都带来了大量的新特性,能够处理的应用场景也越来越丰富。本书遵循从入门到精通的学习路线,涵盖了入门、安装指南、实践指南、核心原理、开发指南、运维指南、新特性演进等内容,内容翔实、图文并茂,几乎囊括了Kubernetes当前主流版本的方方面面,无论是对于软件工程师、测试工程师、运维工程师、软件架构师、技术经理,还是对于资深IT人士,本书都极具参考价值。吴治辉HPE资深架构师第1章 Kubernetes入门1.1 Kubernetes是什么

Kubernetes是什么?

首先,它是一个全新的基于容器技术的分布式架构领先方案。这个方案虽然还很新,但它是谷歌十几年以来大规模应用容器技术的经验积累和升华的重要成果。确切地说,Kubernetes是谷歌严格保密十几年的秘密武器—Borg的一个开源版本。Borg是谷歌的一个久负盛名的内部使用的大规模集群管理系统,它基于容器技术,目的是实现资源管理的自动化,以及跨多个数据中心的资源利用率的最大化。十几年以来,谷歌一直通过Borg系统管理着数量庞大的应用程序集群。由于谷歌员工都签署了保密协议,即便离职也不能泄露Borg的内部设计,所以外界一直无法了解关于它的更多信息。直到2015年4月,传闻许久的Borg论文伴随Kubernetes的高调宣传被谷歌首次公开,大家才得以了解它的更多内幕。正是由于站在Borg这个前辈的肩膀上,汲取了Borg过去十年间的经验与教训,所以Kubernetes一经开源就一鸣惊人,并迅速称霸容器领域。

其次,如果我们的系统设计遵循了Kubernetes的设计思想,那么传统系统架构中那些和业务没有多大关系的底层代码或功能模块,都可以立刻从我们的视线中消失,我们不必再费心于负载均衡器的选型和部署实施问题,不必再考虑引入或自己开发一个复杂的服务治理框架,不必再头疼于服务监控和故障处理模块的开发。总之,使用Kubernetes提供的解决方案,我们不仅节省了不少于30%的开发成本,还可以将精力更加集中于业务本身,而且由于Kubernetes提供了强大的自动化机制,所以系统后期的运维难度和运维成本大幅度降低。

然后,Kubernetes是一个开放的开发平台。与J2EE不同,它不局限于任何一种语言,没有限定任何编程接口,所以不论是用Java、Go、C++还是用Python编写的服务,都可以被映射为Kubernetes的Service(服务),并通过标准的TCP通信协议进行交互。此外,Kubernetes平台对现有的编程语言、编程框架、中间件没有任何侵入性,因此现有的系统也很容易改造升级并迁移到Kubernetes平台上。

最后,Kubernetes是一个完备的分布式系统支撑平台。Kubernetes具有完备的集群管理能力,包括多层次的安全防护和准入机制、多租户应用支撑能力、透明的服务注册和服务发现机制、内建的智能负载均衡器、强大的故障发现和自我修复能力、服务滚动升级和在线扩容能力、可扩展的资源自动调度机制,以及多粒度的资源配额管理能力。同时,Kubernetes提供了完善的管理工具,这些工具涵盖了包括开发、部署测试、运维监控在内的各个环节。因此,Kubernetes是一个全新的基于容器技术的分布式架构解决方案,并且是一个一站式的完备的分布式系统开发和支撑平台。

在正式开始本章的Hello World之旅之前,我们首先要学习Kubernetes的一些基本知识,这样才能理解Kubernetes提供的解决方案。

在Kubernetes中,Service是分布式集群架构的核心,一个Service对象拥有如下关键特征。

◎ 拥有唯一指定的名称(比如mysql-server)。

◎ 拥有一个虚拟IP(Cluster IP、Service IP或VIP)和端口号。

◎ 能够提供某种远程服务能力。

◎ 被映射到提供这种服务能力的一组容器应用上。

Service的服务进程目前都基于Socket通信方式对外提供服务,比如Redis、Memcache、MySQL、Web Server,或者是实现了某个具体业务的特定TCP Server进程。虽然一个Service通常由多个相关的服务进程提供服务,每个服务进程都有一个独立的Endpoint(IP+Port)访问点,但Kubernetes能够让我们通过Service(虚拟Cluster IP +Service Port)连接到指定的Service。有了Kubernetes内建的透明负载均衡和故障恢复机制,不管后端有多少服务进程,也不管某个服务进程是否由于发生故障而被重新部署到其他机器,都不会影响对服务的正常调用。更重要的是,这个Service本身一旦创建就不再变化,这意味着我们再也不用为Kubernetes集群中服务的IP地址变来变去的问题而头疼了。

容器提供了强大的隔离功能,所以有必要把为Service提供服务的这组进程放入容器中进行隔离。为此,Kubernetes设计了Pod对象,将每个服务进程都包装到相应的Pod中,使其成为在Pod中运行的一个容器(Container)。为了建立Service和Pod间的关联关系,Kubernetes首先给每个Pod都贴上一个标签(Label),给运行MySQL的Pod贴上name=mysql标签,给运行PHP的Pod贴上name=php标签,然后给相应的Service定义标签选择器(Label Selector),比如MySQL Service的标签选择器的选择条件为name=mysql,意为该Service要作用于所有包含name=mysql Label的Pod。这样一来,就巧妙解决了Service与Pod的关联问题。

这里先简单介绍Pod的概念。首先,Pod运行在一个被称为节点(Node)的环境中,这个节点既可以是物理机,也可以是私有云或者公有云中的一个虚拟机,通常在一个节点上运行几百个Pod;其次,在每个Pod中都运行着一个特殊的被称为Pause的容器,其他容器则为业务容器,这些业务容器共享Pause容器的网络栈和Volume挂载卷,因此它们之间的通信和数据交换更为高效,在设计时我们可以充分利用这一特性将一组密切相关的服务进程放入同一个Pod中;最后,需要注意的是,并不是每个Pod和它里面运行的容器都能被映射到一个Service上,只有提供服务(无论是对内还是对外)的那组Pod才会被映射为一个服务。

在集群管理方面,Kubernetes将集群中的机器划分为一个Master和一些Node。在Master上运行着集群管理相关的一组进程kube-apiserver、kube-controller-manager和kubescheduler,这些进程实现了整个集群的资源管理、Pod调度、弹性伸缩、安全控制、系统监控和纠错等管理功能,并且都是自动完成的。Node作为集群中的工作节点,运行真正的应用程序,在Node上Kubernetes管理的最小运行单元是Pod。在Node上运行着Kubernetes的kubelet、kube-proxy服务进程,这些服务进程负责Pod的创建、启动、监控、重启、销毁,以及实现软件模式的负载均衡器。

最后,看看传统的IT系统中服务扩容和服务升级这两个难题,以及Kubernetes所提供的全新解决思路。服务的扩容涉及资源分配(选择哪个节点进行扩容)、实例部署和启动等环节,在一个复杂的业务系统中,这两个难题基本上靠人工一步步操作才得以解决,费时费力又难以保证实施质量。

在Kubernetes集群中,只需为需要扩容的Service关联的Pod创建一个RC(Replication Controller),服务扩容以至服务升级等令人头疼的问题都迎刃而解。在一个RC定义文件中包括以下3个关键信息。

◎ 目标Pod的定义。

◎ 目标Pod需要运行的副本数量(Replicas)。

◎ 要监控的目标Pod的标签。

在创建好RC(系统将自动创建好Pod)后,Kubernetes会通过在RC中定义的Label筛选出对应的Pod实例并实时监控其状态和数量,如果实例数量少于定义的副本数量,则会根据在RC中定义的Pod模板创建一个新的Pod,然后将此Pod调度到合适的Node上启动运行,直到Pod实例的数量达到预定目标。这个过程完全是自动化的,无须人工干预。有了RC,服务扩容就变成一个纯粹的简单数字游戏了,只需修改RC中的副本数量即可。后续的服务升级也将通过修改RC来自动完成。

以将在第2章中介绍的PHP+Redis留言板应用为例,只要为PHP留言板程序(frontend)创建一个有3个副本的RC+Service,为Redis读写分离集群创建两个RC:写节点(redis-master)创建一个单副本的RC+Service,读节点(redis-slaver)创建一个有两个副本的RC+Service,就可以快速完成整个集群的搭建过程,是不是很简单?1.2 为什么要用Kubernetes

使用Kubernetes的理由很多,最重要的理由是,IT行业从来都是由新技术驱动的。

当前,Docker这门容器化技术已经被很多公司采用,从单机走向集群已成为必然,云计算的蓬勃发展正在加速这一进程。Kubernetes作为当前被业界广泛认可和看好的基于Docker的大规模容器化分布式系统解决方案,得到了以谷歌为首的IT巨头们的大力宣传和持续推进。

2015年,谷歌联合20多家公司一起建立了CNCF(Cloud Native Computing Foundation,云原生计算基金会)开源组织来推广Kubernetes,并由此开创了云原生应用(Cloud Native Application)的新时代。作为CNCF“钦定”的官方云原生平台,Kubernetes正在颠覆应用程序的开发方式。

如今,数百家厂商和技术社区共同构建了非常强大的云原生生态,市面上几乎所有提供云基础设施的公司都以原生形式将Kubernetes作为底层平台,可以预见,会有大量的新系统选择Kubernetes,不论这些新系统是运行在企业的本地服务器上,还是被托管到公有云上。

使用Kubernetes会收获哪些好处呢?

首先,可以“轻装上阵”地开发复杂系统。以前需要很多人(其中不乏技术达人)一起分工协作才能设计、实现和运维的分布式系统,在采用Kubernetes解决方案之后,只需一个精悍的小团队就能轻松应对。在这个团队里,只需一名架构师负责系统中服务组件的架构设计,几名开发工程师负责业务代码的开发,一名系统兼运维工程师负责Kubernetes的部署和运维,因为Kubernetes已经帮我们做了很多。

其次,可以全面拥抱微服务架构。微服务架构的核心是将一个巨大的单体应用分解为很多小的互相连接的微服务,一个微服务可能由多个实例副本支撑,副本的数量可以随着系统的负荷变化进行调整。微服务架构使得每个服务都可以独立开发、升级和扩展,因此系统具备很高的稳定性和快速迭代能力,开发者也可以自由选择开发技术。谷歌、亚马逊、eBay、Netflix等大型互联网公司都采用了微服务架构,谷歌更是将微服务架构的基础设施直接打包到Kubernetes解决方案中,让我们可以直接应用微服务架构解决复杂业务系统的架构问题。

再次,可以随时随地将系统整体“搬迁”到公有云上。Kubernetes最初的设计目标就是让用户的应用运行在谷歌自家的公有云GCE中,华为云(CCE)、阿里云(ACK)和腾讯云(TKE)先后宣布支持Kubernetes集群,未来会有更多的公有云及私有云支持Kubernetes。同时,在Kubernetes的架构方案中完全屏蔽了底层网络的细节,基于Service的虚拟IP地址(Cluster IP)的设计思路让架构与底层的硬件拓扑无关,我们无须改变运行期的配置文件,就能将系统从现有的物理机环境无缝迁移到公有云上。

然后,Kubernetes内在的服务弹性扩容机制可以让我们轻松应对突发流量。在服务高峰期,我们可以选择在公有云中快速扩容某些Service的实例副本以提升系统的吞吐量,这样不仅节省了公司的硬件投入,还大大改善了用户体验。中国铁路总公司的12306购票系统,在客流高峰期(如节假日)就租用了阿里云进行分流。

最后,Kubernetes系统架构超强的横向扩容能力可以让我们的竞争力大大提升。对于互联网公司来说,用户规模等价于资产,因此横向扩容能力是衡量互联网业务系统竞争力的关键指标。我们利用Kubernetes提供的工具,不用修改代码,就能将一个Kubernetes集群从只包含几个Node的小集群平滑扩展到拥有上百个Node的大集群,甚至可以在线完成集群扩容。只要微服务架构设计得合理,能够在多个云环境中进行弹性伸缩,系统就能够承受大量用户并发访问带来的巨大压力。1.3 从一个简单的例子开始

考虑到Kubernetes提供的PHP+Redis留言板的Hello World例子对于绝大多数刚接触Kubernetes的人来说比较复杂,难以顺利上手和实践,所以在此将其替换成一个简单得多的Java Web应用例子,可以让新手快速上手和实践。

此Java Web应用的结构比较简单,是一个运行在Tomcat里的Web App,如图1.1所示,JSP页面通过JDBC直接访问MySQL数据库并展示数据。出于演示和简化的目的,只要程序正确连接到了数据库,就会自动完成对应的Table的创建与初始化数据的准备工作。所以,当我们通过浏览器访问此应用时,就会显示一个表格的页面,数据则来自数据库。图1.1 Java Web应用的结构

此应用需要启动两个容器:Web App容器和MySQL容器,并且Web App容器需要访问MySQL容器。在Docker时代,假设我们在一个宿主机上启动了这两个容器,就需要把MySQL容器的IP地址通过环境变量注入Web App容器里;同时,需要将Web App容器的8080端口映射到宿主机的8080端口,以便在外部访问。在本章的这个例子里,我们介绍在Kubernetes时代是如何达到这个目标的。1.3.1 环境准备

首先,安装Kubernetes和下载相关镜像,本书建议采用VirtualBox或者VMware Workstation在本机虚拟一个64位的CentOS 7虚拟机作为学习环境。虚拟机采用NAT的网络模式以便连接外网,然后使用kubeadm快速安装一个Kubernetes集群(安装步骤详见2.2节的说明)。之后就可以在这个Kubernetes集群中进行练习了。

注:本书示例中的Docker镜像下载地址为https://hub.docker.com/u/kubeguide/。1.3.2 启动MySQL服务

首先,为MySQL服务创建一个RC定义文件mysql-rc.yaml,下面给出了该文件的完整内容和解释:

以上YAML定义文件中的kind属性用来表明此资源对象的类型,比如这里的值为ReplicationController,表示这是一个RC;在spec一节中是RC的相关属性定义,比如spec.selector是RC的Pod标签选择器,即监控和管理拥有这些标签的Pod实例,确保在当前集群中始终有且仅有replicas个Pod实例在运行,这里设置replicas=1,表示只能运行一个MySQL Pod实例。当在集群中运行的Pod数量少于replicas时,RC会根据在spec.template一节中定义的Pod模板来生成一个新的Pod实例,spec.template.metadata.labels指定了该Pod的标签,需要特别注意的是:这里的labels必须匹配之前的spec.selector,否则此RC每创建一个无法匹配Label的Pod,就会不停地尝试创建新的Pod,陷入恶性循环中。

在创建好mysql-rc.yaml文件后,为了将它发布到Kubernetes集群中,我们在Master上执行命令:

接下来,用kubectl命令查看刚刚创建的RC:

查看Pod的创建情况时,可以运行下面的命令:

我们看到一个名为mysql-xxxxx的Pod实例,这是Kubernetes根据mysql这个RC的定义自动创建的Pod。由于Pod的调度和创建需要花费一定的时间,比如需要一定的时间来确定调度到哪个节点上,以及下载Pod里的容器镜像需要一段时间,所以我们一开始看到Pod的状态显示为Pending。在Pod成功创建完成以后,状态最终会被更新为Running。

我们通过docker ps指令查看正在运行的容器,发现提供MySQL服务的Pod容器已经创建并正常运行了,此外会发现MySQL Pod对应的容器还多创建了一个来自谷歌的pause容器,这就是Pod的“根容器”,详见1.4.3节的说明。

最后,创建一个与之关联的Kubernetes Service—MySQL的定义文件(文件名为mysql-svc.yaml),完整的内容和解释如下:

其中,metadata.name是Service的服务名(ServiceName);port属性则定义了Service的虚端口;spec.selector确定了哪些Pod副本(实例)对应本服务。类似地,我们通过kubectl create 命令创建Service对象。

运行kubectl命令,创建Service:

运行kubectl命令查看刚刚创建的Service:

可以发现,MySQL服务被分配了一个值为169.169.253.143的Cluster IP地址。随后,Kubernetes集群中其他新创建的Pod就可以通过Service的Cluster IP+端口号3306来连接和访问它了。

通常,Cluster IP是在Service创建后由Kubernetes系统自动分配的,其他Pod无法预先知道某个Service的Cluster IP地址,因此需要一个服务发现机制来找到这个服务。为此,最初时,Kubernetes巧妙地使用了Linux环境变量(Environment Variable)来解决这个问题,后面会详细说明其机制。现在只需知道,根据Service的唯一名称,容器可以从环境变量中获取Service对应的Cluster IP地址和端口,从而发起TCP/IP连接请求。1.3.3 启动Tomcat应用

上面定义和启动了MySQL服务,接下来采用同样的步骤完成Tomcat应用的启动过程。首先,创建对应的RC文件myweb-rc.yaml,内容如下:

注意:在Tomcat容器内,应用将使用环境变量MYSQL_SERVICE_HOST的值连接MySQL服务。更安全可靠的用法是使用服务的名称mysql,详见本章Service的概念和第4章的说明。运行下面的命令,完成RC的创建和验证工作:

最后,创建对应的Service。以下是完整的YAML定义文件(myweb-svc.yaml):

type=NodePort和nodePort=30001的两个属性表明此Service开启了NodePort方式的外网访问模式。在Kubernetes集群之外,比如在本机的浏览器里,可以通过30001这个端口访问myweb(对应到8080的虚端口上)。

运行kubectl create命令进行创建:

我们看到上面有提示信息,意思是需要把30001这个端口在防火墙上打开,以便外部的访问能穿过防火墙。

运行kubectl命令,查看创建的Service:

至此,我们的第1个Kubernetes例子便搭建完成了,我们将在下一节中验证结果。1.3.4 通过浏览器访问网页

经过上面的几个步骤,我们终于成功实现了Kubernetes上第1个例子的部署搭建工作。现在一起来见证成果吧!在你的笔记本上打开浏览器,输入http://虚拟机IP:30001/demo/。

比如虚拟机IP为192.168.18.131(可以通过#ip a命令进行查询),在浏览器里输入地址http:// 192.168.18.131:30001/demo/后,可以看到如图1.2所示的网页界面。图1.2 通过浏览器访问Tomcat应用

如果看不到这个网页界面,那么可能有几个原因,比如因为防火墙的问题无法访问30001端口,或者因为是通过代理上网的,浏览器错把虚拟机的IP地址当作远程地址了。可以在虚拟机上直接运行curl 192.168.18.131:30001来验证此端口能否被访问,如果还是不能访问,就肯定不是机器的问题了。

接下来,可以尝试单击“Add…”按钮添加一条记录并提交,如图1.3所示,在提交以后,数据就被写入MySQL数据库中了。图1.3 在留言板网页添加新的留言

至此,我们终于完成了Kubernetes上的Tomcat例子,这个例子并不是很复杂。我们也看到,相对于传统的分布式应用的部署方式,在Kubernetes之上我们仅仅通过一些很容易理解的配置文件和相关的简单命令就完成了对整个集群的部署,这让我们惊诧于Kubernetes的创新和强大。

下一节,我们将对Kubernetes中的基本概念和术语进行全面学习,在这之前,读者可以继续研究这个例子里的一些拓展内容,如下所述。

◎ 研究RC、Service等配置文件的格式。

◎ 熟悉kubectl的子命令。

◎ 手工停止某个Service对应的容器进程,然后观察有什么现象发生。

◎ 修改RC文件,改变副本数量,重新发布,观察结果。1.4 Kubernetes的基本概念和术语

Kubernetes中的大部分概念如Node、Pod、Replication Controller、Service等都可以被看作一种资源对象,几乎所有资源对象都可以通过Kubernetes提供的kubectl工具(或者API编程调用)执行增、删、改、查等操作并将其保存在etcd中持久化存储。从这个角度来看,Kubernetes其实是一个高度自动化的资源控制系统,它通过跟踪对比etcd库里保存的“资源期望状态”与当前环境中的“实际资源状态”的差异来实现自动控制和自动纠错的高级功能。

在声明一个Kubernetes资源对象的时候,需要注意一个关键属性:apiVersion。以下面的Pod声明为例,可以看到Pod这种资源对象归属于v1这个核心API。

Kubernetes平台采用了“核心+外围扩展”的设计思路,在保持平台核心稳定的同时具备持续演进升级的优势。Kubernetes大部分常见的核心资源对象都归属于v1这个核心API,比如Node、Pod、Service、Endpoints、Namespace、RC、PersistentVolume等。在版本迭代过程中,Kubernetes先后扩展了extensions/v1beta1、apps/v1beta1、apps/v1beta2等API组,而在1.9版本之后引入了apps/v1这个正式的扩展API组,正式淘汰(deprecated)了extensions/v1beta1、apps/v1beta1、apps/v1beta2这三个API组。

我们可以采用YAML或JSON格式声明(定义或创建)一个Kubernetes资源对象,每个资源对象都有自己的特定语法格式(可以理解为数据库中一个特定的表),但随着Kubernetes版本的持续升级,一些资源对象会不断引入新的属性。为了在不影响当前功能的情况下引入对新特性的支持,我们通常会采用下面两种典型方法。

◎ 方法1,在设计数据库表的时候,在每个表中都增加一个很长的备注字段,之后扩展的数据以某种格式(如XML、JSON、简单字符串拼接等)放入备注字段。因为数据库表的结构没有发生变化,所以此时程序的改动范围是最小的,风险也更小,但看起来不太美观。

◎ 方法2,直接修改数据库表,增加一个或多个新的列,此时程序的改动范围较大,风险更大,但看起来比较美观。

显然,两种方法都不完美。更加优雅的做法是,先采用方法1实现这个新特性,经过几个版本的迭代,等新特性变得稳定成熟了以后,可以在后续版本中采用方法2升级到正式版。为此,Kubernetes为每个资源对象都增加了类似数据库表里备注字段的通用属性Annotations,以实现方法1的升级。以Kubernetes 1.3版本引入的Pod的Init Container新特性为例,一开始,Init Container的定义是在Annotations中声明的,如下面代码中粗体部分所示,是不是很不美观?

在Kubernetes 1.8版本以后,Init container特性完全成熟,其定义被放入Pod的spec.initContainers一节,看起来优雅了很多:

在Kubernetes 1.8中,资源对象中的很多Alpha、Beta版本的Annotations被取消,升级成了常规定义方式,在学习Kubernetes的过程中需要特别注意。

下面介绍Kubernetes中重要的资源对象。1.4.1 Master

Kubernetes里的Master指的是集群控制节点,在每个Kubernetes集群里都需要有一个Master来负责整个集群的管理和控制,基本上Kubernetes的所有控制命令都发给它,它负责具体的执行过程,我们后面执行的所有命令基本都是在Master上运行的。Master通常会占据一个独立的服务器(高可用部署建议用3台服务器),主要原因是它太重要了,是整个集群的“首脑”,如果它宕机或者不可用,那么对集群内容器应用的管理都将失效。

在Master上运行着以下关键进程。

◎ Kubernetes API Server(kube-apiserver):提供了HTTP Rest接口的关键服务进程,是Kubernetes里所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程。

◎ Kubernetes Controller Manager(kube-controller-manager):Kubernetes里所有资源对象的自动化控制中心,可以将其理解为资源对象的“大总管”。

◎ Kubernetes Scheduler(kube-scheduler):负责资源调度(Pod调度)的进程,相当于公交公司的“调度室”。

另外,在Master上通常还需要部署etcd服务,因为Kubernetes里的所有资源对象的数据都被保存在etcd中。1.4.2 Node

除了Master,Kubernetes集群中的其他机器被称为Node,在较早的版本中也被称为Minion。与Master一样,Node可以是一台物理主机,也可以是一台虚拟机。Node是Kubernetes集群中的工作负载节点,每个Node都会被Master分配一些工作负载(Docker容器),当某个Node宕机时,其上的工作负载会被Master自动转移到其他节点上。

在每个Node上都运行着以下关键进程。

◎ kubelet:负责Pod对应的容器的创建、启停等任务,同时与Master密切协作,实现集群管理的基本功能。

◎ kube-proxy:实现Kubernetes Service的通信与负载均衡机制的重要组件。

◎ Docker Engine(docker):Docker引擎,负责本机的容器创建和管理工作。

Node可以在运行期间动态增加到Kubernetes集群中,前提是在这个节点上已经正确安装、配置和启动了上述关键进程,在默认情况下kubelet会向Master注册自己,这也是Kubernetes推荐的Node管理方式。一旦Node被纳入集群管理范围,kubelet进程就会定时向Master汇报自身的情报,例如操作系统、Docker版本、机器的CPU和内存情况,以及当前有哪些Pod在运行等,这样Master就可以获知每个Node的资源使用情况,并实现高效均衡的资源调度策略。而某个Node在超过指定时间不上报信息时,会被Master判定为“失联”,Node的状态被标记为不可用(Not Ready),随后Master会触发“工作负载大转移”的自动流程。

我们可以执行下述命令查看在集群中有多少个Node:

然后,通过kubectl describe node 查看某个Node的详细信息:

上述命令展示了Node的如下关键信息。

◎ Node的基本信息:名称、标签、创建时间等。

◎ Node当前的运行状态:Node启动后会做一系列的自检工作,比如磁盘空间是否不足(DiskPressure)、内存是否不足(MemoryPressure)、网络是否正常(NetworkUnavailable)、PID资源是否充足(PIDPressure)。在一切正常时设置Node为Ready状态(Ready=True),该状态表示Node处于健康状态,Master将可以在其上调度新的任务了(如启动Pod)。

◎ Node的主机地址与主机名。

◎ Node上的资源数量:描述Node可用的系统资源,包括CPU、内存数量、最大可调度Pod数量等。

◎ Node可分配的资源量:描述Node当前可用于分配的资源量。

◎ 主机系统信息:包括主机ID、系统UUID、Linux kernel版本号、操作系统类型与版本、Docker版本号、kubelet与kube-proxy的版本号等。

◎ 当前运行的Pod列表概要信息。

◎ 已分配的资源使用概要信息,例如资源申请的最低、最大允许使用量占系统总量的百分比。

◎ Node相关的Event信息。1.4.3 Pod

Pod是Kubernetes最重要的基本概念,如图1.4所示是Pod的组成示意图,我们看到每个Pod都有一个特殊的被称为“根容器”的Pause容器。Pause容器对应的镜像属于Kubernetes平台的一部分,除了Pause容器,每个Pod还包含一个或多个紧密相关的用户业务容器。图1.4 Pod的组成示意图

为什么Kubernetes会设计出一个全新的Pod的概念并且Pod有这样特殊的组成结构?

原因之一:在一组容器作为一个单元的情况下,我们难以简单地对“整体”进行判断及有效地行动。比如,一个容器死亡了,此时算是整体死亡么?是N/M的死亡率么?引入业务无关并且不易死亡的Pause容器作为Pod的根容器,以它的状态代表整个容器组的状态,就简单、巧妙地解决了这个难题。

原因之二:Pod里的多个业务容器共享Pause容器的IP,共享Pause容器挂接的Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。

Kubernetes为每个Pod都分配了唯一的IP地址,称之为Pod IP,一个Pod里的多个容器共享Pod IP地址。Kubernetes要求底层网络支持集群内任意两个Pod之间的TCP/IP直接通信,这通常采用虚拟二层网络技术来实现,例如Flannel、Open vSwitch等,因此我们需要牢记一点:在Kubernetes里,一个Pod里的容器与另外主机上的Pod容器能够直接通信。

Pod其实有两种类型:普通的Pod及静态Pod(Static Pod)。后者比较特殊,它并没被存放在Kubernetes的etcd存储里,而是被存放在某个具体的Node上的一个具体文件中,并且只在此Node上启动、运行。而普通的Pod一旦被创建,就会被放入etcd中存储,随后会被Kubernetes Master调度到某个具体的Node上并进行绑定(Binding),随后该Pod被对应的Node上的kubelet进程实例化成一组相关的Docker容器并启动。在默认情况下,当Pod里的某个容器停止时,Kubernetes会自动检测到这个问题并且重新启动这个Pod(重启Pod里的所有容器),如果Pod所在的Node宕机,就会将这个Node上的所有Pod重新调度到其他节点上。Pod、容器与Node的关系如图1.5所示。图1.5 Pod、容器与Node的关系

Kubernetes里的所有资源对象都可以采用YAML或者JSON格式的文件来定义或描述,下面是我们在之前的Hello World例子里用到的myweb这个Pod的资源定义文件:

Kind为Pod表明这是一个Pod的定义,metadata里的name属性为Pod的名称,在metadata里还能定义资源对象的标签,这里声明myweb拥有一个name=myweb的标签。在Pod里所包含的容器组的定义则在spec一节中声明,这里定义了一个名为myweb、对应镜像为kubeguide/tomcat-app:v1的容器,该容器注入了名为MYSQL_SERVICE_HOST='mysql'和MYSQL_SERVICE_PORT='3306'的环境变量(env关键字),并且在8080端口(containerPort)启动容器进程。Pod的IP加上这里的容器端口(containerPort),组成了一个新的概念—Endpoint,它代表此Pod里的一个服务进程的对外通信地址。一个Pod也存在具有多个Endpoint的情况,比如当我们把Tomcat定义为一个Pod时,可以对外暴露管理端口与服务端口这两个Endpoint。

我们所熟悉的Docker Volume在Kubernetes里也有对应的概念—Pod Volume,后者有一些扩展,比如可以用分布式文件系统GlusterFS实现后端存储功能;Pod Volume是被定义在Pod上,然后被各个容器挂载到自己的文件系统中的。

这里顺便提一下Kubernetes的Event概念。Event是一个事件的记录,记录了事件的最早产生时间、最后重现时间、重复次数、发起者、类型,以及导致此事件的原因等众多信息。Event通常会被关联到某个具体的资源对象上,是排查故障的重要参考信息,之前我们看到Node的描述信息包括了Event,而Pod同样有Event记录,当我们发现某个Pod迟迟无法创建时,可以用kubectl describe pod xxxx来查看它的描述信息,以定位问题的成因,比如下面这个Event记录信息表明Pod里的一个容器被探针检测为失败一次:

每个Pod都可以对其能使用的服务器上的计算资源设置限额,当前可以设置限额的计算资源有CPU与Memory两种,其中CPU的资源单位为CPU(Core)的数量,是一个绝对值而非相对值。

对于绝大多数容器来说,一个CPU的资源配额相当大,所以在Kubernetes里通常以千分之一的CPU配额为最小单位,用m来表示。通常一个容器的CPU配额被定义为100~300m,即占用0.1~0.3个CPU。由于CPU配额是一个绝对值,所以无论在拥有一个Core的机器上,还是在拥有48个Core的机器上,100m这个配额所代表的CPU的使用量都是一样的。与CPU配额类似,Memory配额也是一个绝对值,它的单位是内存字节数。

在Kubernetes里,一个计算资源进行配额限定时需要设定以下两个参数。

◎ Requests:该资源的最小申请量,系统必须满足要求。

◎ Limits:该资源最大允许使用的量,不能被突破,当容器试图使用超过这个量的资源时,可能会被Kubernetes“杀掉”并重启。

通常,我们会把Requests设置为一个较小的数值,符合容器平时的工作负载情况下的资源需求,而把Limit设置为峰值负载情况下资源占用的最大量。下面这段定义表明MySQL容器申请最少0.25个CPU及64MiB内存,在运行过程中MySQL容器所能使用的资源配额为0.5个CPU及128MiB内存:

试读结束[说明:试读内容隐藏了图片]

下载完整电子书


相关推荐

最新文章


© 2020 txtepub下载