Kubernetes-手册-全-

Kubernetes 手册(全)

原文:zh.annas-archive.org/md5/5052204F13641918EE166946F5C50D62

译者:飞龙

协议:CC BY-NC-SA 4.0

第一章:关于这本书

这是一本关于 Kubernetes 的最新书籍。它相对较短,而且直截了当。这本书的理念是您可以在几天内读完它!不需要任何先前的知识。

让我明确一点,因为我不想误导人... 这不是深入研究!它涵盖了 Kubernetes 最重要的方面。我认为这是市场上最好的快速掌握的书籍!

平装书

平装版本在部分亚马逊市场上有售。我无法控制亚马逊在哪些市场上提供平装版 - 如果由我选择,我会让它在所有地方都有售。

我选择了一本高质量的全彩版,我认为您会喜欢。这意味着没有廉价的纸张,也没有来自上世纪 90 年代的黑白图表:-D

电子书和 Kindle 版本

获取电子副本的最简单的地方是 leanpub.com。这是一个流畅的平台,所有更新都是免费的。

您也可以在亚马逊上获得 Kindle 版本,还可以获得免费更新。然而,Kindle 在同步更新方面声名狼藉。如果您在将更新同步到您的 Kindle 上遇到问题,请联系 Kindle 支持,他们将解决问题。

反馈

我会很高兴如果您能在亚马逊上给这本书写一篇评论。写技术书是孤独的工作。我实际上花了几个月的时间让这本书尽可能地好,所以花几分钟时间写一篇评论对我来说是很好的。不过,没有压力,如果您不写,我也不会因此失眠。

为什么有人要读这本书或关心 Kubernetes?

Kubernetes 非常热门,Kubernetes 技能需求量很高。所以,如果您想在职业生涯上取得进展,并且想要使用塑造未来的技术,您需要阅读这本书。如果您不关心自己的职业生涯,并且愿意被抛在后面,那就不要读它。这就是事实。

如果我已经观看了您的视频培训课程,我应该买这本书吗?

Kubernetes 是 Kubernetes。所以我的书和视频课程之间显然有一些相似的内容。但阅读书籍和观看视频是完全不同的体验。在我看来,视频更有趣,但书籍更容易做笔记,当你试图找到某些东西时可以翻阅。

如果我是您,我会观看视频购买这本书。它们互补,通过多种方法学习是一种被证明的策略。但您还能期待我说什么呢:-D

最后的话:我觉得我的书籍和视频课程已经得到了足够多的好评,可以让您放心它们将是很好的投资。

注意:我的视频培训课程可在 pluralsight.com 和 acloud.guru 上找到。

书籍的版本

Kubernetes 正在快速发展!因此,这样一本书的价值与其年龄成反比!换句话说,这本书越老,价值就越低。考虑到这一点,我承诺每年至少更新一次。当我说“更新”时,我的意思是真正的更新 - 每个词和概念都经过审查,每个示例都经过测试和更新。我对这本书百分之百的承诺!

如果每年至少更新一次似乎很多...欢迎来到新常态!

我们不再生活在一个两年前的技术书籍有价值的世界。事实上,我对一个关于 Kubernetes 这样快速发展的主题的一年前的书籍的价值表示怀疑!作为作者,我希望这不是真的,但事实却是如此!再次...欢迎来到新常态!

书籍的免费更新

我已尽一切努力确保您对这本书的投资尽可能安全!

所有 Kindle 和 Leanpub 的客户都可以免费获得所有更新!Leanpub 上的更新效果很好,但在 Kindle 上情况就不一样了。许多读者抱怨他们的 Kindle 设备无法获得更新。这是一个常见问题,可以通过联系 Kindle 支持轻松解决。

如果您从Amazon.com购买平装书,您可以以$2.99 的折扣价获得 Kindle 版本。这是通过Kindle Matchbook计划完成的。不幸的是,Kindle Matchbook 只在美国提供,并且存在错误 - 有时 Kindle Matchbook 图标不会出现在书的亚马逊销售页面上。如果您遇到此类问题,联系 Kindle 支持,他们会帮助您解决问题。

这是我能做的最好的了!

如果您通过其他渠道购买这本书,情况会有所不同,因为我无法控制它们。嘿...我是一个技术人员,不是一个书籍分销商:-D

书籍的版本

  • 版本 3 2018 年 11 月。将所有内容和概念与 Kubernetes 的最新版本以及云原生领域的最新动态保持一致。重新排列了一些章节以获得更好的流畅性。删除了ReplicaSets章节,并将该内容转移到改进的Deployments章节。添加了新章节,概述了其他未在专门章节中涵盖的重要概念。

  • 版本 2.2 2018 年 1 月。修正了一些拼写错误,增加了一些解释,并添加了一些新的图表。

  • 版本 2.1 2017 年 12 月。修正了一些拼写错误,并更新了图 6.11 和 6.12 以包括缺失的标签。

  • 版本 2. 2017 年 10 月。更新了 Kubernetes 1.8.0 的内容。增加了关于 ReplicaSets 的新章节。对 Pods 章节进行了重大修改。修正了拼写错误,并对现有章节进行了一些其他小的更新。

  • 版本 1. 初始版本。

第二章:Kubernetes 入门

本章分为两个主要部分。

  • Kubernetes 背景-它来自何处等等。

  • 将 Kubernetes 视为数据中心操作系统的想法

Kubernetes 背景

Kubernetes 是一个编排器。在大多数情况下,它编排容器化的应用程序。但是,有一些项目使其能够编排虚拟机和函数(无服务器工作负载)。所有这些都使 Kubernetes 成为云原生应用程序的事实上的编排器。

那么,什么是编排器,什么是云原生应用程序

编排器是一个部署和管理应用程序的后端系统。这意味着它可以帮助您部署应用程序,扩展和缩小它,执行更新和回滚等操作。如果它是一个好的编排器,它可以在您不需要监督的情况下完成这些操作。

云原生应用程序由一组小型独立服务组成,这些服务相互通信并形成一个有用的应用程序。正如其名称所示,这种设计使其能够应对类似云的需求并在云平台上本地运行。例如,云原生应用程序被设计和编写成可以轻松扩展和缩小以满足需求的变化。更新和回滚也很简单。它们还可以自我修复。

本书中将更多地涉及所有这些概念。

注意:尽管名称如此,云原生应用程序也可以在本地运行。事实上,云原生应用程序的一个特性可能是能够在任何地方运行-任何云,或任何本地数据中心。

Kubernetes 源自何处

让我们从头开始吧... Kubernetes 源自 Google!2014 年夏天,它被开源并移交给了云原生计算基金会(CNCF)。

图 1.1

图 1.1

从那时起,它已成为全球最重要的云原生技术。

像许多现代云原生项目一样,它是用 Go(Golang)编写的。它在 Github 上的kubernetes/kubernetes上。它在 IRC 频道上活跃讨论,你可以在 Twitter 上关注它(@kubernetesio),还有一个很好的 slack 频道-slack.k8s.io。全球各地也定期举行聚会!

Kubernetes 和 Docker

Kubernetes 和 Docker 是互补的技术。例如,通常会使用 Docker 开发应用程序,然后使用 Kubernetes 进行编排。

在这个模型中,你可以用你喜欢的语言编写代码,然后使用 Docker 对其进行打包、测试和部署。但在测试或生产中运行的最后一步是由 Kubernetes 处理的。

在高层次上,你可能会有一个包含 10 个节点的 Kubernetes 集群来运行你的生产应用程序。然而,在幕后,每个节点都在运行 Docker 作为其容器运行时。这意味着 Docker 是启动和停止容器等低级技术,而 Kubernetes 是处理更大范围事务的高级技术,比如决定在哪些节点上运行应用程序的某些部分,何时扩展或缩减,以及执行更新。

图 1.2 显示了一个简单的 Kubernetes 集群,其中的节点使用 Docker 作为容器运行时。

图 1.2

图 1.2

正如图 1.2 所示,Docker 并不是 Kubernetes 支持的唯一容器运行时。事实上,Kubernetes 有一些抽象运行时的特性:

  1. 容器运行时接口(CRI)是一个抽象层,标准化第三方容器运行时与 Kubernetes 接口的方式。它允许容器运行时代码存在于 Kubernetes 之外,但以受支持和标准化的方式与其接口。

  2. 运行时类是 Kubernetes 1.12(alpha)中的一个新功能,允许不同类别的运行时。例如,gVisor可能提供比 Docker 或 containerd 更好的隔离性。

在撰写本文时,containerd正在超越 Docker 成为 Kubernetes 中最常用的容器运行时。containerd实际上是 Docker 的精简版本,只包含 Kubernetes 所需的内容。

然而,这是低级的东西,不应该影响你作为 Kubernetes 用户的体验。无论你使用哪种容器运行时,常规的 Kubernetes 命令和模式将继续正常工作。

Kubernetes 与 Docker Swarm 有什么不同

在 2016 年和 2017 年,我们经历了编排器之战,Docker Swarm、Mesosphere DCOS 和 Kubernetes 争夺成为事实上的容器编排器。长话短说,Kubernetes 获胜了。

是的,Docker Swarm 和其他容器编排器仍然存在,但它们的发展和市场份额与 Kubernetes 相比微不足道。

Kubernetes 和 Borg:抵抗是徒劳的!

很有可能你会听到人们谈论 Kubernetes 与谷歌的BorgOmega系统的关系。

谷歌多年来一直在容器上运行许多系统并不是什么秘密。传说中他们每周处理数十亿个容器的故事很常见。所以是的,很长一段时间以来 - 甚至在 Docker 出现之前 - 谷歌一直在容器上运行搜索GmailGFS等东西 - 大量的容器!

控制这数十亿个容器并保持其正常运行的是一些内部技术和框架,称为BorgOmega。因此,把它们与 Kubernetes 联系起来并不是什么大问题 - 它们都在进行规模化容器编排的游戏,并且它们都与谷歌有关。

这有时让人们误以为 Kubernetes 是 Borg 或 Omega 的开源版本。但事实并非如此!它更像是与它们共享 DNA 和家族史。就像这样...一开始是 Borg...然后 Borg 产生了 Omega。Omega 认识了开源社区,然后产生了她的 Kubernetes 😉

图 1.3 - 共享的 DNA

图 1.3 - 共享的 DNA

关键是,这三者是分开的,但又是相关的。事实上,许多参与建立 Borg 和 Omega 的人也参与了建立 Kubernetes。

因此,尽管 Kubernetes 是从头开始构建的,但它利用了在谷歌与 Borg 和 Omega 学到的许多东西。

目前,Kubernetes 是 CNCF 下的一个开源项目,根据 Apache 2.0 许可证授权,并且 1.0 版本早在 2015 年 7 月就发布了。

Kubernetes - 名字的含义

Kubernetes这个名字来自希腊词,意思是舵手 - 驾驶船只的人。这个主题反映在标志中。

图 1.4 - Kubernetes 标志

图 1.4 - Kubernetes 标志

传闻: Kubernetes 最初的名字是要叫九号七。如果你了解《星际迷航》,你会知道九号七是一位由凯瑟琳·詹妮薇船长指挥的 USS 航行者号救出的女性Borg。标志上的7个轮辐也是对九号七的一个参考。

在继续之前,关于名字的最后一件事...你经常会看到 Kubernetes 被缩写为K8s。这个想法是数字 8 替代了 K 和 S 之间的 8 个字符 - 对于推特和像我这样的懒惰打字者来说非常方便 😉

数据中心操作系统

一般来说,容器让我们以前的可扩展性挑战看起来很容易 - 我们刚刚说过谷歌每周处理数十亿个容器!

好吧……但并非每个人都像谷歌那样大。那么我们其他人呢?

一般来说,如果你的传统应用程序有数百个虚拟机(VM),那么你的容器化云原生应用程序很可能会有数千个容器!考虑到这一点,我们迫切需要一种管理它们的方法。

对 Kubernetes 打个招呼!

当你开始理解像 Kubernetes 这样的东西时,重要的是要理解现代数据中心架构。例如,我们正在放弃将数据中心视为计算机集合的传统观点。相反,我们将其视为一个大型计算机

但这意味着什么?

典型的计算机是由 CPU、RAM、存储和网络组成的。但是我们已经很好地构建了抽象掉许多细节的操作系统(OS)。例如,开发人员很少关心他们的应用程序使用哪个 CPU 核心或确切的内存地址 - 我们让操作系统决定所有这些。这是件好事,应用程序开发的世界因此变得更加友好。

因此,将这一点提升到下一个级别,并将这些相同的抽象应用于数据中心资源 - 将数据中心视为计算、网络和存储的池,并具有一个总体系统来对其进行抽象化是很自然的。这意味着我们不再需要关心我们的容器运行在哪台服务器或 LUN 上 - 只需将其留给数据中心操作系统处理。

在某些方面,Kubernetes 是一个数据中心操作系统。其他操作系统也存在,但它们都处于牲畜业中。忘掉给你的服务器命名,在电子表格中映射逻辑单元(LUN),或者以其他方式像宠物一样对待它们。像 Kubernetes 这样的系统并不在乎。那种把你的应用程序拿出来然后说“在这个节点上运行应用程序的这一部分,使用这个 IP,在这个特定的 LIUN 上……“的日子已经过去了。在云原生的 Kubernetes 世界中,我们更多地是说“嘿,Kubernetes,我有这个应用程序,它由这些部分组成……请帮我运行它”。然后 Kubernetes 会去做所有艰难的调度和编排工作。

注意:在使用术语宠物牲畜时,不是针对任何人或任何动物。

让我们来看一个快速的类比……

考虑一下通过快递服务发送货物的过程。您将货物打包在快递公司的标准包装中,贴上标签,然后交给快递员。快递员会处理其他所有事情 - 所有复杂的物流,包括货物搭乘的飞机和卡车,使用哪些司机等等。他们还提供让您跟踪包裹的服务。关键是,快递员唯一需要的是货物按照他们的要求打包和贴标签。

对于 Kubernetes 中的应用程序也是一样。将它们打包为容器,给它们一个声明性清单,然后让 Kubernetes 负责运行它们并保持运行。您还会获得丰富的工具和 API,让您了解发生了什么。这是一件美好的事情!

虽然这些听起来都很棒,但不要把这个“数据中心操作系统”的比喻太过分。这不是一个 DVD 安装,你不会得到一个 shell 提示符来控制整个数据中心。而且你绝对不会得到一个纸牌游戏!我们还处于早期阶段,但 Kubernetes 正在引领潮流,我相信你会喜欢它。

章节总结

Kubernetes 是云原生应用程序的领先编排器。我们给它一个应用程序,告诉它我们希望应用程序看起来像什么,然后让 Kubernetes 实现。

它来自谷歌,根据 Apache 2.0 许可开源,并且属于 Cloud Native Computing Foundation(CNCF)。

提示!

Kubernetes 是一个快速发展的项目,正在积极开发中,所以事情变化很快!但不要因此而却步 - 拥抱它!快速变化是新常态!

除了阅读本书,我建议您关注 Twitter 上的@kubernetesio,加入各种 k8s 的 slack 频道,并参加当地的聚会。这些都将帮助您了解 Kubernetes 世界中的最新和最伟大的事物。我还会定期更新这本书,并制作更多的视频培训课程!请关注 pluralsight.com 和 acloud.guru 获取我的最新课程!

第三章:Kubernetes 操作原则

在这一章中,我们将学习构建 Kubernetes 集群和部署应用程序所需的主要组件。游戏的目的是为您提供主要概念的概述。但是如果您不立刻理解一切,不要担心,随着我们在书中的进展,我们将再次涵盖大部分内容。

我们将按以下方式划分本章:

  • 从 40K 英尺高度看 Kubernetes

  • 主节点和节点

  • 打包应用程序

  • 声明性配置和期望状态

  • Pods

  • 部署

  • 服务

从 40K 英尺高度看 Kubernetes

在最高层次上,Kubernetes 是云原生微服务应用程序的编排器。这只是一个由许多小独立服务组成的应用程序的花哨名称,它们共同工作形成一个有用的应用程序。

让我们看一个快速的类比。

在现实世界中,一个足球(足球)队由个体组成。没有两个是相同的,每个人在团队中扮演不同的角色 - 有些防守,有些进攻,有些擅长传球,有些擅长射门... 教练来了,他或她给每个人一个位置,并将他们组织成一个有目的的团队。我们从图 2.1 到图 2.2。

图 2.1

图 2.1

图 2.2

图 2.2

教练还确保团队保持队形,坚持计划,并处理任何伤病。好吧,猜猜… Kubernetes 世界中的微服务应用程序也是一样的!

跟着我…

我们从许多个体化的专业服务开始 - 有些提供网页,有些进行身份验证,有些进行搜索,其他一些持久化数据。Kubernetes 出现了 - 就像足球类比中的教练一样 - 将所有东西组织成一个有用的应用程序,并保持一切运行顺利。

在体育界,我们称之为教练。在应用程序世界中,我们称之为编排

Kubernetes 是一个编排器

为了实现这一点,我们从一个应用程序开始,打包它并将其交给集群(Kubernetes)。集群由一个或多个主节点和一堆节点组成。

主节点负责集群并做出所有调度决策。他们还监视集群,实施更改并响应事件。因此,我们经常将主节点称为控制平面

节点是应用程序服务运行的地方,有时我们称它们为数据平面。它们向主节点汇报,并不断观察新的工作任务。

要在 Kubernetes 集群上运行应用程序,我们遵循这个简单的模式:

  1. 用我们喜欢的语言将应用程序编写为小型独立服务。

  2. 将每个服务打包在自己的容器中。

  3. 将每个容器包装在自己的 Pod 中。

  4. 通过更高级别的对象(例如;*Deployments, DaemonSets, StafeulSets, CronJobs 等)将 Pod 部署到集群中。

我们仍然处在书的开头阶段,不要指望你已经知道所有这些术语的含义。但在高层次上,Deployments 提供了可伸缩性和滚动更新,DaemonSets 在集群中的每个节点上运行一个 Pod 实例,StatefulSets 用于应用程序的有状态组件,CronJobs 用于需要在设定时间运行的工作。还有更多选项,但现在这些就够了。

Kubernetes 喜欢以声明方式管理应用程序。这是一种模式,我们在一组 YAML 文件中描述我们希望应用程序的外观和感觉,将这些文件发送到 Kubernetes,然后坐下来,让 Kubernetes 完成所有工作。

但事情并不止于此。Kubernetes 不断监视我们应用程序的不同部分,以确保它运行的方式完全符合预期。如果有什么不对劲,Kubernetes 会尝试修复它。

这是一个大局观。让我们深入一点。

主节点和节点

Kubernetes 集群由主节点和节点组成。这些是可以是虚拟机、数据中心中的裸金属服务器,或者是私有或公共云中的实例的 Linux 主机。

主节点(控制平面)

Kubernetes 主节点是构成集群控制平面的系统服务的集合。

最简单的设置在单个主机上运行所有主服务。然而,多主高可用性对于生产环境变得越来越重要,并且对于生产环境来说是必不可少的。这就是为什么主要的云提供商在其 Kubernetes 作为服务平台中实现高可用性主节点,如 AKS、EKS 和 GKE。

还有一个被认为是一个好的实践不要在主节点上运行应用程序工作负载。这使得主节点可以完全集中于管理集群。

让我们快速看一下组成控制平面的 Kubernetes 主节点的主要部分。

API 服务器

API 服务器是进入 Kubernetes 的前门。它公开了一个 RESTful API,我们可以通过它向服务器发送 YAML 配置文件。这些 YAML 文件,有时我们称之为清单,包含了我们应用程序的期望状态。这包括诸如要使用哪个容器镜像、要暴露哪些端口以及有多少个 Pod 副本等内容。

对 API 服务器的所有请求都要经过身份验证和授权检查,但一旦完成这些步骤,YAML 文件中的配置将被验证,持久化到集群存储中,并部署到集群中。

您可以将 API 服务器视为集群的大脑 - 智能实现的地方。

集群存储

如果 API 服务器是集群的大脑,那么集群存储就是它的记忆。它是控制平面中唯一有状态的部分,并且持久地存储了整个集群的配置和状态。因此,它是集群的重要组成部分 - 没有集群存储,就没有集群!

集群存储基于etcd,这是一个流行的分布式数据库。由于它是集群的唯一真相来源,您应该小心保护它,并提供足够的恢复方式以应对出现问题时的情况。

控制器管理器

控制器管理器是控制器的控制器,有点像一个单体。虽然它作为一个单一的进程运行,但它实现了几个控制循环,监视集群并响应事件。其中一些控制循环包括:节点控制器、端点控制器和命名空间控制器。每个控制器通常作为一个后台监视循环运行,不断地监视 API 服务器的变化 - 游戏的目标是确保集群的当前状态期望状态匹配(稍后会详细介绍)。

注意:在整本书中,我们将使用控制循环监视循环协调循环等术语来表示相同的意思。

调度器

在高层次上,调度器会监视新的工作并将其分配给节点。在幕后,它评估亲和性和反亲和性规则、约束和资源管理。

云控制器管理器

如果您在受支持的公共云平台(如 AWS、Azure 或 GCP)上运行集群,则您的控制平面将运行一个云控制器管理器。它的工作是管理与底层云平台的集成,如节点、负载均衡器和存储。

控制平面摘要

Kubernetes 的主节点运行着整个集群的控制平面服务。可以把它看作是集群的大脑 - 所有控制和调度决策都是在这里做出的。在幕后,主节点由许多小型专门的服务组成。这些包括 API 服务器、集群存储、控制器管理器和调度器。

API 服务器是控制平面的前端,也是我们直接交互的控制平面中唯一的组件。默认情况下,它在端口 443 上公开一个 RESTful 端点。

图 2.3 显示了 Kubernetes 主节点(控制平面)的高层视图。

图 2.3 - Kubernetes 主节点

图 2.3 - Kubernetes 主节点

节点

节点是 Kubernetes 集群的工作者。在高层次上,它们有三个功能:

  1. 监视 API 服务器以获取新的工作任务

  2. 执行新的工作任务

  3. 向控制平面报告

从图 2.4 可以看出,它们比主节点简单一些。让我们来看一下节点的三个主要组件。

图 2.4 - Kubernetes 节点(以前称为 Minion)

图 2.4 - Kubernetes 节点(以前称为 Minion)

Kubelet

Kubelet 是在集群中所有节点上运行的主要 Kubernetes 代理。事实上,通常可以互换使用术语节点kubelet。您在 Linux 主机上安装 kubelet,它会将主机注册为节点加入集群。然后它会监视 API 服务器以获取新的工作任务。每当它看到一个任务,它就会执行该任务并保持与主节点的报告通道。

如果 kubelet 无法运行特定的工作任务,它会向主节点报告,并让控制平面决定采取什么行动。例如,如果一个 Pod 在一个节点上失败,kubelet 负责找到另一个节点来运行它。它只是向控制平面报告,由控制平面决定如何处理。

容器运行时

Kubelet 需要一个容器运行时来执行与容器相关的任务 - 诸如拉取镜像、启动和停止容器等。

在早期,Kubernetes 原生支持一些容器运行时,比如 Docker。最近,它已经转移到了一个名为容器运行时接口(CRI)的插件模型。这是一个用于外部(第三方)容器运行时插入的抽象层。基本上,CRI 掩盖了 Kubernetes 的内部机制,并为第三方容器运行时提供了一个清晰的文档化接口。

CRI 是将运行时集成到 Kubernetes 中的支持方法。

Kubernetes 有很多可用的容器运行时。cri-containerd是一个基于社区的开源项目,将 CNCF 的containerd运行时移植到 CRI 接口。它得到了很多支持,并且正在取代 Docker 成为 Kubernetes 中最流行的容器运行时。

注意:containerd(发音为“container-dee”)是从 Docker Engine 中剥离出来的容器监督者和运行时逻辑。它由 Docker,Inc.捐赠给了 CNCF,并得到了很多社区支持。还有其他符合 CRI 标准的容器运行时存在。

Kube-proxy

node谜题的最后一部分是 kube-proxy。它在集群中的每个节点上运行,并负责本地网络。例如,它确保每个节点都有自己独特的 IP 地址,并实现本地的 IPTABLES 或 IPVS 规则来处理某些流量类型的路由和负载均衡。

既然我们了解了主节点和节点的基本原理,让我们转换方向,看看如何将应用程序打包运行在 Kubernetes 上。

打包应用程序

为了让应用程序在 Kubernetes 集群上运行,它需要满足一些条件。这些条件包括:

  1. 打包为一个容器

  2. 包装在 Pod 中

  3. 通过清单文件部署(Pod,Deployment. DaemonSet…)

步骤如下…我们用我们喜欢的语言编写代码。我们将其构建成一个容器镜像并存储在注册表中。此时,我们的代码就是containerized的。

接下来,我们定义一个 Kubernetes Pod 来容纳我们的容器化应用程序。在我们目前的高级别上,Pod 只是一个包装器,允许容器在 Kubernetes 集群上运行。一旦我们为我们的容器定义了一个 Pod,我们就可以在集群上部署它了。

Kubernetes 提供了几种对象来部署和管理 Pods。最常见的是Deployment,它提供了可伸缩性、自愈性和滚动更新。它们在 YAML 文件中定义,并指定诸如 - 部署哪个 Pod 以及部署多少个副本等内容。

图 2.5 显示了打包为container的应用程序代码,运行在Pod内,由Deployment管理。

图 2.5 - Kubernetes 节点(以前是 Minion)

图 2.5 - Kubernetes 节点(以前是 Minion)

一旦在Deployment YAML 文件中定义了所有内容,我们就将其作为我们应用程序的desired state发布到集群中,让 Kubernetes 来实现它。

说到 desired state…

声明模型和 desired state

声明模型期望状态的概念是 Kubernetes 核心的两个要素。如果把它们拿走,Kubernetes 就会崩溃!

在 Kubernetes 中,声明模型的工作方式如下:

  1. 我们在清单文件中声明了应用程序(微服务)的期望状态

  2. 我们将其 POST 到 Kubernetes API 服务器

  3. Kubernetes 将这些存储在集群存储中作为应用程序的期望状态

  4. Kubernetes 在集群上实现了期望状态

  5. Kubernetes 实现了监视循环,以确保应用程序的当前状态期望状态不变

让我们更详细地看看每个步骤。

清单文件是用简单的 YAML 编写的,它们告诉 Kubernetes 我们希望应用程序看起来是什么样子。我们称之为期望状态。它包括诸如要使用哪个镜像,要有多少副本,要监听哪些网络端口以及如何执行更新等内容。

一旦我们创建了清单,我们就会使用kubectl命令行实用程序将其POST到 API 服务器。这样做的最常见方式是使用kubectl命令行实用程序。这将清单作为请求 POST 到控制平面,通常在端口 443 上。

一旦请求经过身份验证和授权,Kubernetes 会检查清单,确定要将其发送到哪个控制器(例如部署控制器),并将配置记录在集群存储中作为集群整体期望状态的一部分。完成这些工作后,工作会被安排在集群上。这包括拉取镜像、启动容器和构建网络的艰苦工作。

最后,Kubernetes 设置了后台协调循环,不断监视集群的状态。如果集群的当前状态期望状态不符,Kubernetes 将执行必要的任务来协调解决问题。

图 2.6

图 2.6

重要的是要理解,我们所描述的是传统命令模型的相反。命令模型是指我们发出一长串特定于平台的命令来构建东西的模型。

声明模型不仅比长串的命令简单得多,而且还能实现自愈、扩展,并且适合版本控制和自我记录!它通过告诉集群事物应该是什么样子来实现这一点。如果它们停止看起来像这样,集群会注意到差异并做出所有艰苦的工作来协调情况(自我修复)。

但声明性的故事并不止于此-事情会出错,事情会改变。当这些事情发生时,集群的当前状态不再与期望状态匹配。一旦发生这种情况,Kubernetes 就会开始行动,并尝试将两者重新调和。

让我们看一个例子。

假设我们有一个应用程序,期望状态包括 10 个 web 前端 Pod 的副本。如果运行两个副本的节点失败,当前状态将减少到 8 个副本,但期望状态仍将是 10 个。协调循环将观察到这一点,并且 Kubernetes 将在集群中的其他节点上安排两个新副本。

如果我们有意地将期望的副本数量增加或减少,同样的事情也会发生。我们甚至可以更改我们想要使用的镜像。例如,如果应用程序当前使用图像的v2.00,并且我们更新期望状态以使用v2.01,Kubernetes 将注意到差异并经过更新所有副本的过程,以便它们使用期望状态中指定的新图像。

要清楚。我们不是写一长串命令来更新每个副本到新版本,而是简单地告诉 Kubernetes 我们想要新版本,Kubernetes 会为我们做艰苦的工作。

尽管这看起来很简单,但它非常强大!这也是 Kubernetes 运行的核心。我们给 Kubernetes 一个声明性清单,描述了我们希望应用程序的外观。这构成了应用程序期望状态的基础。Kubernetes 控制平面记录它,实施它,并运行后台协调循环,不断检查正在运行的内容是否符合我们要求的内容。当当前状态与期望状态匹配时,世界是一个快乐的地方。当不匹配时,Kubernetes 会忙起来并修复它。

Pods

在 VMware 世界中,调度的原子单位是虚拟机(VM)。在 Docker 世界中,是容器。嗯...在 Kubernetes 世界中,是Pod

图 2.7 - 调度的原子单位

图 2.7 - 调度的原子单位

Pods 和容器

Kubernetes 确实运行容器化的应用程序。但是你不能直接在 Kubernetes 集群上运行容器-容器必须始终运行在 Pod 内部!

最简单的模型是在一个 Pod 中运行一个单独的容器。然而,有一些高级用例在单个 Pod 内运行多个容器。这些多容器 Pod超出了我们在这里讨论的范围,但强大的例子包括:

  • 服务网格。

  • helper容器支持的 Web 容器,该容器拉取最新内容。

  • 容器与紧密耦合的日志刮取器,将日志传送到其他地方的日志服务。

这只是三个简单的例子。图 2.8 显示了一个多容器 Pod。

图 2.8

图 2.8

Pod 解剖

在最高级别,Pod是一个用于运行容器的环境。Pod 本身实际上并不运行任何东西,它只是一个用于托管容器的沙箱。保持高层次,您将一个主机操作系统的区域划分出来,构建一个网络堆栈,创建一堆内核命名空间,并在其中运行一个或多个容器 - 这就是一个 Pod。

如果您在一个 Pod 中运行多个容器,它们都共享相同的环境 - 诸如 IPC 命名空间、共享内存、卷、网络堆栈等。例如,这意味着同一 Pod 中的所有容器将共享相同的 IP 地址(Pod 的 IP)。这在图 2.8 中显示。

图 2.9

图 2.9

如果同一 Pod 中的两个容器需要相互通信(Pod 内的容器对容器),它们可以使用 Pod 的localhost接口,如图 2.10 所示。

图 2.10

图 2.10

当您需要紧密耦合的容器,并且可能需要共享内存和存储等要求时,多容器 Pod 是理想的。但是,如果您不需要紧密耦合您的容器,您应该将它们放在自己的 Pod 中,并通过网络松散耦合它们 - 这样每个容器只执行单个任务,保持清洁。

Pod 作为原子单位

Pod 也是 Kubernetes 中调度的最小单位。如果需要扩展应用程序,可以添加或删除 Pod。您通过向现有 Pod 添加更多容器来扩展!多容器 Pod 仅用于两个不同但互补的容器需要共享资源的情况。图 2.11 显示了如何使用多个 Pod 作为扩展单元来扩展应用程序的nginx前端。

图 2.11 - 使用 Pod 进行扩展

图 2.11 - 使用 Pod 进行扩展

Pod 的部署是一个原子操作。这意味着一个 Pod 要么完全部署,要么根本不部署。永远不会出现部分部署的 Pod 来处理请求的情况。整个 Pod 要么启动并投入使用,要么不启动,失败了。

一个 Pod 只能存在于一个节点上。多容器 Pod 也是如此。

Pod 生命周期

Pods 是有寿命的。它们被创建,生存,然后死亡。如果它们意外死亡,我们不会让它们复活!相反,Kubernetes 会在原地启动一个新的 Pod。但尽管新的 Pod 看起来、闻起来、感觉起来都像旧的,但它不是!它是一个全新的 Pod,有全新的 ID 和 IP 地址。

这对我们构建应用程序的方式有影响。不要构建它们与特定实例的 Pod 紧密耦合。相反,构建它们,以便当 Pod 失败时,一个全新的(带有新 ID 和 IP 地址)可以在集群的其他地方弹出并无缝地取代它。

部署

我们通常间接部署 Pod 作为更大的一部分。例如; 部署守护进程集有状态集

例如,部署是一个更高级别的 Kubernetes 对象,它包装了一组 Pod,并添加了诸如扩展、零停机更新和版本回滚等功能。

在幕后,它们实现了一个控制器和一个监视循环,始终监视集群,以确保当前状态与期望状态匹配。

自 Kubernetes 1.2 版本以来就存在部署,而在 1.9 版本中被提升为 GA(稳定)版本。你会经常看到它们。

服务

我们刚刚了解到 Pods 是有寿命的,可能会死亡。然而,如果它们通过部署或守护进程集部署,它们在失败时会被替换。但新的 Pod 会有完全不同的 IP!当我们进行扩展操作时,也会发生这种情况——扩展会添加具有新 IP 地址的新 Pod,而缩减会带走现有的 Pod。这些事件会导致大量的 IP 变动。

关键是Pods 是不可靠的。但这带来了一个挑战...假设我们有一个微服务应用程序,有一堆 Pod 执行视频渲染。如果应用程序的其他部分需要使用渲染服务,但不能依赖 Pod 在需要时存在,那该怎么办?

这就是服务发挥作用的地方。服务为一组 Pod 提供可靠的网络。

图 2.12 显示了上传微服务通过服务与渲染器微服务进行通信。服务提供可靠的名称和 IP,并在其后面的两个渲染器 Pods 之间进行请求的负载均衡。

图 2.12

图 2.12

再深入一点。服务是 Kubernetes API 中的完整对象 - 就像 Pods 和部署一样。它们有一个前端,包括稳定的 DNS 名称、IP 地址和端口。在后端,它们在一组动态的 Pods 之间进行负载均衡。Pods 会不断地出现和消失,服务会观察到这一点,自动更新自己,并继续提供稳定的网络端点。

如果我们扩展或缩减 Pods 的数量,情况也是一样的。新的 Pods 会无缝地添加到服务中,而终止的 Pods 也会无缝地被移除。

这就是服务的工作-它是一个稳定的网络抽象点,可以在一组动态的 Pods 之间进行流量负载均衡。

将 Pods 连接到服务

服务使用标签标签选择器来知道要将请求负载均衡到哪组 Pods。服务有一个包含所有标签标签选择器,一个 Pod 必须具有这些标签才能从服务中接收流量。

图 2.13 显示了一个配置为将流量发送到集群上所有带有以下三个标签的 Pods 的服务:

  • zone=prod

  • env=be

  • ver=1.3

图中的两个 Pod 都具有这三个标签,因此服务将对它们进行流量负载均衡。

图 2.13

图 2.13

图 2.14 显示了类似的设置。然而,右侧的另一个 Pod 与服务标签选择器中配置的标签集不匹配。这意味着服务不会将请求负载均衡到它。

图 2.14

图 2.14

关于服务的最后一件事。它们只会将流量发送到健康的 Pods。这意味着未能通过健康检查的 Pod 将不会从服务中接收流量。

这就是基础知识 - 服务将稳定的 IP 地址和 DNS 名称带入了不稳定的 Pods 世界!

章节总结

在本章中,我们介绍了 Kubernetes 集群的一些主要组件。

主节点是控制平面组件运行的地方。在幕后,它们是几个系统服务的组合,包括公共 REST 接口到控制平面的 API 服务器。主节点做出所有部署和调度决策,多主高可用对于生产级环境非常重要。

节点是用户应用程序运行的地方。每个节点运行一个名为kubelet的服务,该服务将节点注册到集群并与控制平面通信。这包括接收新的工作任务并报告它们的情况。节点还具有容器运行时和kube-proxy服务。容器运行时,如 Docker 或 containerd,负责所有与容器相关的操作。kube-proxy服务负责节点上的网络。

我们还谈到了一些主要的 Kubernetes API 对象,如 Pods、Deployments 和 Services。Pod 是基本构建块。Deployments 添加了自愈、扩展和更新功能。Services 添加了稳定的网络和负载均衡。

现在我们知道了基础知识,我们将开始深入了解细节。

第四章:安装 Kubernetes

在本章中,我们将看一下安装 Kubernetes 的几种不同方法。

自 2017 年 7 月我写下这本书的第一版以来,事情发生了很大变化。那时,安装 Kubernetes 很困难。如今,情况好多了!事实上,我们正接近一个可以要求一个 Kubernetes 集群,并获得一个的时刻。这在托管的 Kubernetes 服务,如 Azure Kubernetes Service(AKS)和 Google Kubernetes Engine(GKE)中尤其如此。

关于托管的 Kubernetes 服务,越来越多的人选择使用托管的 Kubernetes 服务,而且像GKE On-Prem(https://cloud.google.com/gke-on-prem/)这样的服务,越来越可能会有大量的 Kubernetes 集群通过主要的云服务提供商构建和管理。

在考虑构建自己的 Kubernetes 集群之前,请问自己以下问题:构建和管理自己的 Kubernetes 集群是你时间和精力的最佳利用吗?如果答案不是一个坚定的“是!”,我强烈建议你考虑使用托管服务。

好的,我们将看一下以下安装类型:

  • 使用 Kubernetes 玩(PWK)

  • Docker Desktop:在你的笔记本上进行本地开发集群

  • Minikube:在你的笔记本上进行本地开发集群

  • Google Kubernetes Engine(GKE):生产级托管集群

  • Kops:在 AWS 上安装你自己的集群

  • Kubeadm:使用 kubeadm 手动安装

在深入之前,有几件事情需要指出...

首先,还有很多其他安装 Kubernetes 的方法。我们在这里涵盖的是我认为最有帮助的方法。

其次,托管的 Kubernetes 服务是指控制平面(主节点)由平台管理的服务。例如,AKS、EKS 和 GKE 都是托管的 Kubernetes 服务,其中控制平面的管理由平台负责(你不需要负责)。2018 年看到了托管的 Kubernetes 平台的大幅增长。

是时候看一些安装了。

使用 Kubernetes 玩耍

使用 Kubernetes 玩(PWK)是免费的,是一个很好的方法,可以在不必在自己的设备上安装任何软件的情况下获得 Kubernetes 集群。你所需要的只是一台电脑,一个互联网连接,以及一个 Docker Hub 或 GitHub 的账户。在我看来,这是获得 Kubernetes 的最快最简单的方法。

但它也有局限性。首先,它是一个有时间限制的游乐场-您会得到一个持续 4 小时的实验室。它还缺少与云基负载均衡器等外部服务的一些集成。然而,除了限制之外,它是一个很棒的工具,我一直在使用!

让我们看看它是什么样子。

  1. 将浏览器指向 http://play-with-k8s.com

  2. 使用您的 GitHub 或 Docker Hub 帐户登录并单击“开始”

  3. 从浏览器左侧的导航窗格中单击“+添加新实例”

您将在浏览器右侧看到一个终端窗口。这是一个 Kubernetes 节点(node1)。

  1. 运行一些命令,查看节点上预安装的一些组件。
$ docker version
Docker version 18

.09.0-ce...

$ kubectl version --output=

yaml
clientVersion:
...
  major: "1"

  minor: "11"

正如输出所显示的,节点已经预安装了 Docker 和kubectl(Kubernetes 客户端)。其他工具包括kubeadm也已经预安装。

值得注意的是,虽然命令提示符是$,但我们实际上是以root身份运行的。我们可以通过运行whoamiid来确认这一点。

  1. 使用kubeadm命令初始化一个新的集群

当您在第 3 步中添加了一个新实例时,PWK 会给您一个初始化新 Kubernetes 集群的命令的简短列表。其中一个是kubeadm init...。以下命令将初始化一个新的集群并配置 API 服务器以侦听正确的 IP 接口。

您可以通过在命令中添加--kubernetes-version标志来指定要安装的 Kubernetes 版本。最新版本可以在 https://github.com/kubernetes/kubernetes/releases 上看到。并非所有版本都适用于 PWK。

$

 kubeadm

 init

 --

apiserver

-

advertise

-

address

 $

(

hostname

 -

i

)

[

kubeadm

]

 WARNING

:

 kubeadm

 is

 in

 beta

,

 do

 not

 use

 it

 for

 prod

...

[

init

]

 Using

 Kubernetes

 version

:

 v1

.11.1

[

init

]

 Using

 Authorization

 modes

:

 [

Node

 RBAC

]

<

Snip

>

Your

 Kubernetes

 master

 has

 initialized

 successfully

!

<

Snip

>

恭喜!您有一个全新的单节点 Kubernetes 集群!我们执行命令的节点(node1)被初始化为master

kubeadm init的输出会给您一个要运行的命令的简短列表。这些命令将复制 Kubernetes 配置文件并设置权限。您可以忽略这些,因为 PWK 已经为您配置好了。随意在$HOME/.kube内部查看。

  1. 使用以下kubectl命令验证集群。
$ kubectl get nodes
NAME      STATUS     AGE       VERSION
node1     NotReady   1m        v1.11.2

输出显示了一个单节点 Kubernetes 集群。但是,节点的状态是NotReady。这是因为我们还没有配置Pod 网络。当您首次登录到 PWK 节点时,您会得到一个配置集群的三个命令的列表。到目前为止,我们只执行了第一个(kubeadm init...)。

  1. 初始化 Pod 网络(集群网络)。

从首次创建node1时屏幕上打印的三个命令列表中复制第二个命令(这将是一个kubectl apply命令)。将其粘贴到终端的新行中。在书中,命令可能会跨越多行并插入反斜杠(\)。您应该删除页面右边出现的任何反斜杠。

$ kubectl apply -n kube-system -f \

 "https://cloud.weave.works/k8s/net?k8s-version=

$(

kubectl version |

 base64 |

 tr\

 -d '\n'

)

"

 serviceaccount "weave-net"

 created
 clusterrole "weave-net"

 created
 clusterrolebinding "weave-net"

 created
 role "weave-net"

 created
 rolebinding "weave-net"

 created
 daemonset "weave-net"

 created

  1. 再次验证集群,看看node1是否已更改为Ready
$ kubectl get nodes
NAME      STATUS    AGE       VERSION
node1     Ready     2m        v1.11.2

现在Pod 网络已经初始化,控制平面为Ready,您可以添加一些工作节点了。

  1. kubeadm init的输出中复制kubeadm join命令。

当您使用kubeadm init初始化新集群时,命令的最终输出列出了一个kubeadm join命令,用于添加节点时使用。此命令包括集群加入令牌、API 服务器正在侦听的 IP 套接字以及加入新节点到集群所需的其他位。复制此命令,并准备粘贴到新节点(node2)的终端中。

  1. 在 PWK 窗口的左侧窗格中点击+ ADD NEW INSTANCE按钮。

将会给你一个名为node2的新节点。

  1. kubeadm join命令粘贴到node2的终端中。

在您的环境中,加入令牌和 IP 地址将是不同的。

   $ kubeadm join --token 948f32.79bd6c8e951cf122 10.0.29.3:6443...
   Initializing machine ID from random generator.
   [preflight] Skipping pre-flight checks
   <Snip>
   Node join complete:
   * Certificate signing request sent to master and response received.
   * Kubelet informed of new secure connection details.

  1. 切换回node1并运行另一个kubectl get nodes
   $ kubectl get nodes
   NAME      STATUS    AGE       VERSION
   node1     Ready     5m        v1.11.2
   node2     Ready     1m        v1.11.2

您的 Kubernetes 集群现在有两个节点 - 一个主节点和一个工作节点。

随意添加更多节点。

恭喜!您现在拥有一个完全可用的 Kubernetes 集群,可以用作测试实验室。

值得指出的是,node1被初始化为 Kubernetes 的master,而其他节点将作为nodes加入集群。PWK 通常在masters旁边放置蓝色图标,在nodes旁边放置透明图标。这有助于您识别哪个是哪个。

最后,PWK 会话只持续 4 小时,显然不适用于生产环境。

玩得开心!

Docker Desktop

在我看来,Docker Desktop是在 Mac 或 Windows 笔记本电脑上获得本地开发集群的最佳方式。通过简单的几个步骤,您可以获得一个单节点 Kubernetes 集群,可以进行开发和测试。我几乎每天都在使用它。

它通过在笔记本电脑上创建一个虚拟机(VM)并在该虚拟机内启动单节点 Kubernetes 集群来工作。它还配置您的kubectl客户端,以便能够与集群通信。最后,您将获得一个简单的 GUI,允许您执行基本操作,如在所有kubectl上下文之间切换。

注意: kubectl 上下文是kubectl命令使用的一堆设置,以便它知道要向哪个集群发出命令。

  1. 将您的网络浏览器指向www.docker.com,然后选择Products > Docker Desktop

  2. 点击下载按钮,选择 Mac 或 Windows 版本。

您可能需要登录到 Docker Store。账户是免费的,产品也是免费的。

  1. 打开安装程序并按照简单的安装说明进行操作。

安装程序完成后,您将在 Windows 任务栏上或 Mac 的菜单栏上看到一个鲸鱼图标。

  1. 点击鲸鱼图标(您可能需要右键单击),转到Settings并从Kubernetes选项卡中启用 Kubernetes。

您可以打开一个终端窗口并查看您的集群:

$ kubectl get nodes
NAME                 STATUS   ROLES    AGE   VERSION
docker-for-desktop   Ready    master   68d   v1.10.3

恭喜,您现在拥有一个本地开发集群!

Minikube

Minikube 是另一个选项,如果您是开发人员,并且需要在笔记本电脑上的本地 Kubernetes 开发环境。与Docker Desktop一样,您可以在本地运行一个单节点 Kubernetes 集群进行开发。这不是用于生产!

注意: 我对 Minikube 的结果参差不齐。当它工作时很棒,但有时很难让它工作。因此,我更喜欢 Docker Desktop for Mac 和 Windows。

您可以在 Mac、Windows 和 Linux 上获取 Minikube。我们将快速查看 Mac 和 Windows,因为这是大多数人在笔记本电脑上运行的系统。

注意: Minikube 需要在系统的 BIOS 中启用虚拟化扩展。

在 Mac 上安装 Minikube

在安装 Minikube 之前,最好先安装kubectl(Kubernetes 客户端)。稍后您将使用它来向 Minikube 集群发出命令。

  1. 使用 Brew 安装kubectl
$ brew install kubernetes-cli
Updating Homebrew...

这将把 kubectl 二进制文件放在/usr/local/bin中,并使其可执行。

  1. 验证安装是否成功。
$ kubectl version --client
Client Version: version.Info{

Major:"1"

, Minor:"12"

...

现在我们已经安装了kubectl客户端,让我们安装 Minikube。

  1. 使用 Brew 安装 Minikube。
$ brew cask install minikube

==

> Downloading https://storage.googlapis.com/minikube...

如果提示,请提供您的密码。

  1. 使用 Brew 为 Mac 安装hyperkit轻量级超级管理程序。

其他的 Hypervisor 选项可用 - VirtualBox 和 VMware Fusion - 但我们只展示 hyperkit。

$ brew install hyperkit

==

> Downloading https://homebrew.bintray...

  1. 使用以下命令启动 Minikube。
$ minikube start --vm-driver=

hyperkit
Starting local

 Kubernetes cluster...
Starting VM...

minikube start是启动 Minikube 的最简单方法。指定--vm-driver=hyperkit标志将强制其使用hyperkit超级管理程序,而不是 VirtualBox。

您现在在 Mac 上已经有一个 Minikube 实例在运行!

在 Windows 10 上安装 Minikube

在本节中,我们将向您展示如何在 Windows 上使用 Hyper-V 作为虚拟机管理器使用 Minikube。还有其他选项,但我们在这里不展示它们。我们还将使用以管理员权限打开的 PowerShell 终端。

在安装 Minikube 之前,让我们安装kubectl客户端。有几种方法可以做到这一点:

  1. 使用 Chocolaty 软件包管理器

  2. 通过您的网络浏览器下载

如果您使用 Chocolaty,可以使用以下命令安装它。

> choco install kubernetes-cli

如果您不使用 Chocolaty,可以使用您的网络浏览器安装kubectl

将您的网络浏览器指向 https://kubernetes.io/docs/tasks/tools/install-kubectl/,并单击使用 curl 安装 kubectl 二进制文件选项。单击Windows选项卡。将 URL 复制并粘贴到您的网络浏览器中 - 这将下载kubectl二进制文件。确保只复制和粘贴 URL,而不是完整的curl命令。

下载完成后,将kubectl.exe文件复制到系统的%PATH%文件夹中。

使用kubectl version命令验证安装。

> kubectl version --client=true --output=yaml
clientVersion:
  ...
  gitVersion: v1.12.0
  ...
  major: "1"
  minor: "12"
  platform: windows/amd64

现在您有了kubectl,可以继续安装 Windows 的 Minikube。

  1. 在 GitHub 上的 Minikube 版本页面上打开一个网络浏览器
  1. 从 Minikube 的最新版本下方单击minikube-installer.exe。这将下载 64 位 Windows 安装程序。

  2. 启动安装程序,并通过向导接受默认选项。

  3. 确保 Hyper-V 有一个外部 vSwitch。

打开 Hyper-V 管理器(virtmgmt.msc),转到虚拟交换机管理器...。如果没有配置以下两个选项的虚拟交换机,请创建一个新的:

  • 连接类型=外部网络

  • 允许管理操作系统共享此网络适配器

在本节的其余部分,我们将假设您已经配置了一个名为external的 Hyper-V 外部 vSwitch。如果您的名称不同,您将需要在以下命令中替换您的名称。

  1. 使用以下命令验证 Minikube 版本。
> minikube version
minikube version: v0.30.0

  1. 使用以下命令启动运行 Kubernetes 版本 1.12.1 的本地 Minikube 实例。

该命令假定一个名为external的 Hyper-V vSwitch,并使用反引号“`”使命令跨多行以提高可读性。

第一次下载和启动集群可能需要一段时间。

> minikube start `
--vm-driver=hyperv `
--hyperv-virtual-switch="external" `
--kubernetes-version="v1.12.1" `
--memory=4096

  Starting local Kubernetes v1.12.1 cluster...
  Starting VM...
  139.09 MB / 139.09 MB [================] 100.00% 0s
  <Snip>
  Starting cluster components...
  Kubectl is now configured to use the cluster.

  1. 通过检查 Kubernetes 主版本的版本来验证安装。
> kubectl version -o yaml
clientVersion:
<Snip>
serverVersion:
  buildDate: 2018-10-05T16:36:14Z
  compiler: gc
  gitCommit: 4ed3216f3ec431b140b1d899130a69fc671678f4
  gitTreeState: clean
  gitVersion: v1.12.1
  goVersion: go1.10.4
  major: "1"
  minor: "12"
  platform: linux/amd64

如果目标机器积极拒绝网络连接,并显示无法连接到服务器:拨号 tcp...错误,这很可能是与网络相关的错误。确保您的 vSwitch 已正确配置,并且您已使用--hyperv-virtual-switch标志正确指定了它。kubectl通过端口 8443 与minikube Hyper-V VM 内的 Kubernetes 进行通信。

恭喜!您已在 Windows 10 PC 上成功运行了一个完全可用的 Minikube 集群。

现在,您可以在命令行上键入minikube以查看 minikube 子命令的完整列表。一个值得尝试的好命令可能是minikube ip,它将为您提供 Minikube 集群正在运行的 IP 地址。

使用kubectl验证 Minikube 安装

minikube start操作配置了一个kubectl 上下文,这样您就可以在新的 Minikube 环境中使用kubectl。通过从与您运行minikube start相同的 shell 中运行以下kubectl命令来测试这一点。

   $ kubectl config current-context
   minikube

太棒了,您的 kubectl 上下文已设置为 Minikube。这意味着kubectl命令将被发送到 Minikube 集群。

值得指出的是,kubectl可以通过设置不同的上下文来配置为与任何 Kubernetes 集群通信-您只需要在不同的上下文之间切换以向不同的集群发送命令。

使用kubectl get nodes命令列出集群中的节点。

   $ kubectl get nodes
   NAME       STATUS   AGE   VERSION
   minikube   Ready    1m    v1.12.1

这是一个准备好使用的单节点 Minikube 集群!

您可以使用minikube ip命令获取集群的 IP 地址。

删除 Minikube 集群

我们使用单个minikube start命令启动了 Minikube 集群。我们可以使用minikube stop命令停止它。

   $ minikube stop
   Stopping local Kubernetes cluster...
   Machine stopped

停止 Minikube 会保留所有磁盘上的配置。这样可以轻松地重新启动它,并从您离开的地方继续进行。

完全清除它-不留痕迹-使用minikube delete命令。

   $ minikube delete
   Deleting local Kubernetes cluster...
   Machine deleted

在 Minikube 内运行特定版本的 Kubernetes

Minikube 允许您使用--kubernetes-version标志指定要运行的 Kubernetes 版本。如果您需要匹配生产环境中使用的 Kubernetes 版本,这将非常有用。

以下命令将启动一个运行 Kubernetes 版本 1.10.7 的 Minikube 集群。

   $ minikube start \
     --kubernetes-version=v1.10.7

     Starting local Kubernetes cluster...
     Starting VM...

运行另一个kubectl get nodes命令来验证版本。

   $ kubectl get nodes
   NAME       STATUS   AGE   VERSION
   minikube   Ready    1m    v1.10.7

中了!

这就是 Minikube!在 Mac 或 PC 上快速启动一个简单的 Kubernetes 集群的绝佳方式。但这不适用于生产!

Google Kubernetes Engine(GKE)

Google Kubernetes Engine 是在 Google Cloud(GCP)上运行的托管 Kubernetes服务。像大多数托管 Kubernetes服务一样,它提供:

  • 快速轻松地获得生产级别的 Kubernetes 集群

  • 托管的控制平面(您不管理主节点

  • 逐项计费

警告:GKE 和其他托管的 Kubernetes 服务并非免费。一些服务可能提供免费层免费信用额的初始金额。但是,一般来说,您必须付费才能使用它们。

配置 GKE

要使用 GKE,您需要在 Google Cloud 上拥有一个已配置计费的账户和一个空白项目。这些都很容易设置,所以我们不会在这里花时间解释它们 - 在本节的其余部分,我们将假设您已经拥有这些。

以下步骤将指导您通过 Web 浏览器配置 GKE。一些细节可能会在将来发生变化,但整体流程将保持不变。

  1. 在您的 Google Cloud Platform(GCP)项目的控制台中,打开左侧的导航窗格,然后选择Kubernetes Engine > Clusters。您可能需要点击控制台左上角的三个水平条,以使导航窗格可见。

  2. 点击创建集群按钮。

这将启动创建新 Kubernetes 集群的向导。

  1. 向导目前提供了一些模板选项。这可能会在将来改变,但整体流程将保持不变。选择一个模板(Your first clusterStandard cluster 可能是不错的选择)。

  2. 为集群命名并添加描述。

  3. 选择您想要的区域区域内集群。区域是更新的,可能更具弹性 - 您的主节点和节点将分布在多个区域,但仍可通过单个高可用端点访问。

  4. 选择您的集群的区域或区域内。

  5. 选择集群版本。这是将在您的主节点和节点上运行的 Kubernetes 版本。您只能选择下拉列表中可用的版本。选择一个最新版本。

  6. 您可以在节点池部分选择工作节点的数量和大小。这允许您选择工作节点的大小和配置,以及数量。更大更快的节点会产生更高的成本。

如果您正在构建一个区域集群,您指定的数字将是每个区域中的节点数,而不是总数。

  1. 将所有其他选项保持默认值,然后点击创建

您还可以单击更多链接,查看您可以自定义的其他选项的长列表。值得一看,但我们不会在本书中讨论它们。

您的集群现在将被创建!

探索 GKE

现在您已经有了一个集群,是时候快速查看一下了。

确保您已登录到 GCP 控制台,并在Kubernetes Engine下查看Clusters

集群页面显示了您在项目中拥有的 Kubernetes 集群的高级概览。图 3.1 显示了一个名为gke1的单个 3 节点集群。

图 3.1

图 3.1

单击集群名称以查看更多详细信息。图 3.2 显示了一些您可以查看的详细信息的屏幕截图。

图 3.2

图 3.2

单击 Web UI 顶部的> CONNECT图标(图 3.2 中未显示)会给您一个命令,您可以在笔记本电脑上运行,以配置本地的gcloudkubectl工具与您的集群通信。将此命令复制到剪贴板。

为了使以下步骤生效,您需要从https://cloud.google.com/sdk/下载并安装 Google Cloud SDK。这将下载几个实用程序,包括gcloudkubectl命令行实用程序。

打开终端并将长的gcloud命令粘贴到其中。这将配置您的kubectl客户端以与您的新 GKE 集群通信。

运行kubectl get nodes命令以列出集群中的节点。

   $ kubectl get nodes
   NAME             STATUS     AGE    VERSION
   gke-cluster...   Ready      5m     v1.10.7-gke.6
   gke-cluster...   Ready      6m     v1.10.7-gke.6
   gke-cluster...   Ready      6m     v1.10.7-gke.6

恭喜!您知道如何使用 Google Kubernetes Engine(GKE)创建一个生产级别的 Kubernetes 集群。您还知道如何检查它并连接到它。

警告!确保在使用完毕后立即删除您的 GKE 集群。即使不使用,GKE 和其他托管的 K8s 平台可能会产生费用。

使用kops在 AWS 上安装 Kubernetes

kops是 Kubernetes Operations 的缩写。它是一个高度主观的集群引导工具,使得在受支持的平台上安装 Kubernetes相对简单

通过高度主观,我们的意思是在安装过程中您的自定义程度受到限制。如果您需要一个高度定制的集群,您应该看看kubeadm

通过“相对简单”,我们的意思是比起自己编译二进制文件来说更容易:-D 如果你对这些领域没有经验,仍然有一些部分可能会很复杂。例如,当涉及到 DNS 配置时,kops非常主观 - 如果 DNS 配置错误,你将会陷入困境!幸运的是,它支持不使用 DNS 的基于八卦的安装。这适用于开发用例,不需要额外的 DNS 配置。

Kops 目前支持在 AWS 和 GCE 上引导集群。其他平台可能在将来得到支持。

在撰写本文时,kops命令行工具仅适用于 Mac 和 Linux。

您需要以下所有内容才能使用kops引导集群:

  • 一个 AWS 账户和对 AWS 基础知识的良好理解

  • kubectl

  • 适用于您的操作系统(Mac 或 Linux)的最新版本的kops二进制文件

  • awscli工具

  • 具有以下权限的 AWS 账户凭据:

  • AmazonEC2FullAccess

  • AmazonRoute53FullAccess

  • AmazonS3FullAccess

  • IAMFullAccess

  • AmazonVPCFullAccess

以下示例来自 Linux 机器,但在 Mac 上(可能在将来也适用于 Windows)也是一样的。

以下示例展示了两种安装选项:

  1. DNS

  2. 八卦

基于八卦的安装是最简单的,适用于私有 DNS 域不可用的情况。它也非常适合 AWS 位置,比如中国,那里没有 Route53。

DNS 安装更加复杂,需要顶级域和一个委托给 AWS Route53 的子域。本章中的 DNS 示例使用一个名为tf1.com的域,该域由 GoDaddy 等第三方提供商托管。它有一个名为k8s的子域,该子域被委托给 Amazon Route53。如果您要跟随 DNS 示例,您将需要自己的工作域。

下载并安装kubectl

对于 Mac,下载和安装很简单,使用brew install kubernetes-cli

以下步骤适用于 Linux 机器。

  1. 使用以下命令将最新的kubectl二进制文件下载到您的主目录。
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(

curl -s \

https://storage.googleapis.com/kubernetes-release/release/stable.txt)

/bin/linux\

/amd64/kubectl

该命令是一个单一的命令,但相当长,在书中会换行多次。这个过程可能会在打印页面的边缘引入反斜杠,这些反斜杠不是命令的一部分,需要被移除。

  1. 使下载的二进制文件可执行,并将其移动到PATH中的目录。
$ chmod +x ./kubectl
$ mv ./kubectl /usr/local/bin/kubectl

运行kubectl命令,确保它已安装并正常工作。

下载并安装kops

对于 Mac,您只需要运行brew install kops

对于 Linux,请使用以下过程。

  1. 使用以下curl命令下载kops二进制文件。

命令应该在一行上发出,并且不应该有反斜杠\。它还嵌入了 URL 中kops工具的版本,您可以更改这个版本。请参阅 https://github.com/kubernetes/kops/releases 获取最新版本。

$ curl -LO https://github.com/kubernetes/kops/releases/download/1.10.0/kops-lin\

ux-amd64

  1. 使下载的二进制文件可执行,并将其移动到系统PATH中的目录。
$ chmod +x kops-linux-amd64
$ mv kops-linux-amd64 /usr/local/bin/kops

运行kops version命令验证安装。

   $ kops version
   Version 1.10.0

安装和配置 AWS CLI。

您可以使用brew install awscli在 Mac OS 上安装 AWS CLI 工具。

以下示例显示如何从 Ubuntu 18.04 使用的默认应用程序仓库安装 AWS CLI。如果您使用不同的 Linux 发行版,安装方法显然会有所不同。

  1. 运行以下命令安装 AWS CLI。
$ sudo apt-get install awscli -y

  1. 运行aws configure命令来配置 AWS CLI 的实例。

您将需要一个具有AmazonEC2FullAccessAmazonRoute53FullAccessAmazonS3FullAccessIAMFullAccessAmazonVPCFullAccess权限的 AWS IAM 帐户的凭据来完成此步骤。

$ aws configure
AWS Access Key ID [

None]

: **************
AWS Secret Access Key [

None]

: **************
Default region name [

None]

: enter-your-region-here
Default output format [

None]

:

  1. 为 kops 创建一个新的 S3 存储桶,用于存储配置和状态信息。

Kops 要求集群名称必须是有效的 DNS 名称。在这些示例中,我们将使用名称cluster1.k8s.tf1.com。您将需要在您的环境中使用不同的名称。让我们快速分解一下它是如何工作的。该示例假设我拥有一个名为tf1.com的域,并且我已经将一个名为k8s的子域委派给了 AWS Route53。在该子域中,我可以创建任何我喜欢的名称的集群。在该示例中,我们将创建一个名为cluster1的集群。这将使集群的完全限定域名为cluster1.k8s.tf1.com。我已经在父域tf1.com中创建了NS记录,指向了 Route53 中托管的k8s域。tf1.com是虚构的,仅在这些示例中用于保持命令行参数的简洁。

如果您计划创建一个基于 gossip 的集群,您需要使用以.k8s.local结尾的集群名称。

$ aws s3 mb s3://cluster1.k8s.tf1.com
make_bucket: cluster1.k8s.tf1.com

  1. 列出您的 S3 存储桶,并使用grep查找您创建的存储桶的名称。这将证明存储桶已成功创建。
$ aws s3 ls |

 grep k8s
2018

-10-10 13

:09:11 cluster1.k8s.tf1.com

  1. 告诉kops在哪里找到它的配置和状态 - 这将是在上一步中创建的 S3 存储桶。
$ export

 KOPS_STATE_STORE

=

s3://cluster1.k8s.tf1.com

  1. 使用以下kops create cluster命令之一创建新集群。

第一个命令使用 gossip 而不是 DNS 创建集群。要使用 gossip,集群名称必须.k8s.local结尾。

第二个命令使用 DNS 创建集群,并假定之前已经解释过的工作 DNS 配置。

您需要一份 AWS 公钥的副本才能使命令生效。在示例中,密钥名为np-k8s.pub,位于当前工作目录中。

$ kops create cluster \

  --cloud-aws \

  --zones=

eu-west-1b \

  --name=

mycluster.k8s.local \

  --ssh-public-key ~/np-k8s.pub \

  --yes

$ kops create cluster \

  --cloud=

aws \

  --zones=

eu-west-1b \

  --dns-zone=

k8s.tf1.com \

  --name cluster1.k8s.tf1.com  \

  --ssh-public-key ~/np-k8s.pub \

  --yes

命令分解如下。kops create cluster告诉kops创建一个新的集群。--cloud=aws告诉它使用 AWS 提供程序在 AWS 中创建集群。--zones=eu-west-1b告诉kops在 eu-west-1b 区创建集群。如果使用 DNS 创建集群,--dns-zone标志告诉它使用委托区域。我们使用--name标志命名集群-如果使用 gossip 创建,请记住以“.k8s.local”结尾。--ssh-public-key告诉它使用哪个密钥。最后,--yes标志告诉kops继续部署集群。如果省略--yes标志,将创建集群配置,但不会部署。

集群部署可能需要几分钟时间。这是因为kops正在创建构建集群所需的 AWS 资源。这包括诸如 VPC、EC2 实例、启动配置、自动缩放组、安全组等。在构建了 AWS 基础设施之后,它还必须构建 Kubernetes 集群。

  1. 部署集群后,您可以使用kops validate cluster命令对其进行验证。集群完全启动可能需要一段时间,所以请耐心等待。
$ kops validate cluster
Using cluster from kubectl context: cluster1.k8s.tf1.com

INSTANCE GROUPS
NAME      ROLE     MACHINETYPE  MIN  MAX  SUBNETS
master..  Master   m3.medium    1

    1

    eu-west-1b
nodes     Node     t2.medium    2

    2

    eu-west-1b

NODE STATUS
NAME             ROLE      READY
ip-172-20-38..   node      True
ip-172-20-58..   master    True
ip-172-20-59..   node      True

Your cluster cluster1.k8s.tf1.com is ready

恭喜!您现在知道如何使用kops工具在 AWS 中创建 Kubernetes 集群。

现在您的集群已经运行起来,您可以对其发出kubectl命令。也许值得在 AWS 控制台中查看一下kops创建的一些资源。

警告!确保在使用完毕后删除您的集群。在云平台上运行的集群可能会产生费用,即使它们没有被积极使用。

使用kops在 AWS 中删除 Kubernetes 集群

您可以使用kops delete cluster命令来删除您刚刚创建的集群。这也将删除为支持集群创建的所有 AWS 资源。

以下命令将删除前面步骤中创建的集群。

   $ kops delete cluster --name=cluster1.k8s.tf1.com --yes

使用kubeadm安装 Kubernetes

在这一部分,我们将看到如何使用kubeadm安装 Kubernetes。

kubeadm最好的一点是,您可以使用它在几乎任何地方安装 Kubernetes - 笔记本电脑、数据中心的裸机,甚至在公共云上。它不仅仅是安装 Kubernetes - 您还可以升级、管理和查询您的集群。人们经常说kubeadm是集群的kubectl - 一个用于构建管理 Kubernetes 集群的绝佳工具。无论如何,kubeadm是一个核心的 Kubernetes 项目,并且有着光明的未来。

本节中的示例基于 Ubuntu 18.04。如果您使用不同的 Linux 发行版,则先决条件部分中的一些命令将有所不同。但是,我们展示的过程可以用于在笔记本电脑、数据中心甚至云中安装 Kubernetes。

我们将演示一个简单的示例,使用三台配置为一个主节点和两个节点的 Ubuntu 18.04 机器,如图 3.3 所示。

图 3.3

图 3.3

高级计划将如下:

  1. 安装先决条件

  2. 使用node1初始化一个新的集群作为主节点

  3. 创建 Pod 网络

  4. node2node3添加为工作节点。

所有三个节点都将获得以下内容:

  • Docker

  • kubeadm

  • kubelet

  • kubectl

Docker是容器运行时。还存在其他运行时,但我们将使用 Docker。kubeadm是我们将用来构建集群的工具,kubelet是 Kubernetes 节点代理,kubectl是 Kubernetes 命令行实用程序。

先决条件

以下命令特定于 Ubuntu 18.04,并且需要在所有三个节点上运行。它们设置了一些东西,以便我们可以从正确的存储库安装正确的软件包。其他 Linux 版本也存在等效的命令和软件包。

使用以下两个命令获取稍后步骤中将需要的一些软件包的最新版本。

$ sudo apt-get update
<Snip>

$ sudo apt-get install -y \

  apt-transport-https \

  ca-certificates \

  curl \

  software-properties-common

下载并安装以下两个存储库密钥。其中一个存储库包含 Kubernetes 工具,另一个存储库包含 Docker。我们将在稍后的步骤中需要这些密钥。

$ curl -s \

 https://packages.cloud.google.com/apt/doc/apt-key.gpg |

 sudo apt-key add -
OK

$ curl -fsSL \

 https://download.docker.com/linux/ubuntu/gpg |

 sudo apt-key add -
OK

创建或编辑以下文件,并添加安装 Kubernetes 软件包所需的存储库。

$ sudo vim /etc/apt/sources.list.d/kubernetes.list

添加以下行。

deb

 https://apt.kubernetes.io/

 kubernetes-xenial

 main

下一步是安装kubeadmkubectlkubelet。使用以下两个命令。

$ sudo apt-get update
<Snip>

$ sudo apt-get install -y kubelet kubeadm kubectl
<Snip>

如果再次运行apt-get install命令,您可以看到已安装的版本。

现在让我们安装 Docker...

添加所需的指纹。

$ sudo apt-key fingerprint 0EBFCD88
pub   rsa4096 2017

-02-22 [

SCEA]

      9DC8 5822

 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [

 unknown]

 Docker Release (

CE deb)

 <docker@docker.com>
sub   rsa4096 2017

-02-22 [

S]

现在添加stable Docker 仓库。这是一个单一的命令,使用反斜杠将其分布在多行上。

$ sudo add-apt-repository \

   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \

$(

lsb_release -cs)

 \

 stable"

安装 Docker。

$ sudo apt-get update
<Snip>

$ sudo apt-get install docker-ce
<Snip>

这些是先决条件。

初始化一个新的集群

使用kubeadm init初始化一个新的 Kubernetes 集群就像输入kubeadm init一样简单。

   $ sudo kubeadm init
   <SNIP>
   Your Kubernetes master has initialized successfully!

   To start using your cluster, you need to run (as a regular user):

   mkdir -p $HOME/.kube
   sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
   sudo chown $(id -u):$(id -g) $HOME/.kube/config

   <SNIP>
   You can join any number of machines by running the following...

   kubeadm join --token b90685.bd53aca93b758efc 172.31.32.74:6443

该命令拉取所有必需的镜像并构建集群。当过程完成时,它会输出一些简短的命令,让您可以作为普通用户管理集群。它还会给出kubeadm join命令,让您可以将其他节点添加到集群中。

恭喜!这是一个全新的单主 Kubernetes 集群。

通过运行kubeadm init输出中列出的命令来完成该过程。

   $ mkdir -p $HOME/.kube
   $ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
   $ sudo chown $(id -u):$(id -g) $HOME/.kube/config

这些命令可能会有所不同,甚至在将来可能不再需要。但是,它们会将 Kubernetes 配置文件从/etc/kubernetes复制到您的主目录,并将所有权更改为您。

使用kubectl验证集群是否初始化成功。

   $ kubectl get nodes
   NAME    STATUS     ROLES    AGE     VERSION
   node1   NotReady   master   2m43s   v1.12.1

运行以下kubectl命令查找集群STATUS显示为NotReady的原因。

   $ kubectl get pods --all-namespaces
   NAMESPACE     NAME           READY   STATUS              RESTARTS   AGE
   kube-system   coredns-...vt  0/1     ContainerCreating   0          8m33s
   kube-system   coredns-...xw  0/1     ContainerCreating   0          8m33s
   kube-system   etcd...        1/1     Running             0          7m46s
   kube-system   kube-api...    1/1     Running             0          7m36s
   ...

该命令显示所有命名空间中的所有 Pods - 这包括系统命名空间(kube-system)中的系统 Pods。

正如我们所看到的,没有一个coredns Pods 在运行。这阻止了集群进入Ready状态,这是因为我们还没有创建 Pod 网络。

创建 Pod 网络。以下示例创建了一个由 Weaveworks 提供的多主机覆盖网络。还有其他选项可用,您不必选择这里显示的示例。

该命令可能会在书中跨越多行。在打印页面的边缘处的任何反斜杠(\)都应该被移除。

   $ kubectl apply -n kube-system -f \
   "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | \
tr -d '\n')"

检查主节点的状态是否从NotReady变为Ready

$ kubectl get nodes
NAME    STATUS   ROLES    AGE     VERSION
node1   Ready    master   3m51s   v1.12.1

好了,集群已经准备好了,DNS Pods 现在将会运行。

现在集群已经运行起来了,是时候添加一些节点了。

添加工作节点需要集群的加入令牌。您可能还记得,这是在集群首次初始化时作为输出的一部分提供的。滚动回到那个输出,将kubeadm join命令复制到剪贴板上,然后在node2node3上运行它。

注意:以下操作必须在node2node3上执行,并且您必须已经在这些节点上安装了先决条件(Docker、kubeadm、kubectl 和 kubelet)。

   node2$ kubeadm join 172.31.32.74:6443 --token b90...
   <SNIP>
   Node join complete:
   * Certificate signing request sent to master and response received
   * Kubelet informed of new secure connection details.

node3上重复该命令。

确保两个节点都成功注册,通过在主节点上再次运行 kubectl get nodes 来检查。

   $ kubectl get nodes
   NAME    STATUS   ROLES    AGE   VERSION
   node1   Ready    master   10m   v1.12.1
   node2   Ready    master   55s   v1.12.1
   node3   Ready    <none>   34s   v1.12.1

恭喜!您已经使用 kubeadm 手动构建了一个由 3 个节点组成的集群。但请记住,它只运行一个单一的主节点,没有 H/A。

随意使用 kubeadm 在集群中探索。您还应该调查 kubeadm 安装具有 H/A 管理器的集群的方法。

章节总结

在本章中,我们学习了如何在几种不同的平台上以几种不同的方式安装 Kubernetes。

我们看到了在 Play with Kubernetes (PWK) 上设置 Kubernetes 集群是多么快速简单。我们可以在没有在笔记本电脑或自己的云中安装任何东西的情况下获得 4 小时的游乐场。

我们在笔记本电脑上为开发人员提供了出色的开发体验,安装了 Docker Desktop 和 Minikube。

我们学习了如何在谷歌云中使用 Google Kubernetes Engine (GKE) 快速创建托管的 Kubernetes 集群。

然后我们看了如何使用 kops 工具在 AWS 上使用 AWS 提供程序快速创建集群。

我们完成了本章,看到了如何使用 kubeadm 工具执行手动安装。

我们可以在其他方式和地方安装 Kubernetes。但本章已经足够长了,我已经拔了太多头发了 😄

第五章:使用 Pods

我们将把本章分为两个主要部分:

  • 理论

  • 动手

让我们继续理论。

Pod 理论

在虚拟化世界中,调度的原子单位是虚拟机(VM)。这意味着在虚拟化世界中部署应用程序意味着在 VM 上调度它们。

在 Docker 世界中,原子单位是容器。这意味着在 Docker 上部署应用程序意味着将它们部署在容器内。

在 Kubernetes 世界中,原子单位是Pod。因此,在 Kubernetes 上部署应用程序意味着将它们作为 Pods 部署。

图 4.1

图 4.1

确保将这一点记在脑海中并标记为重要 - 虚拟化使用 VM,Docker 使用容器,Kubernetes 使用 Pods!

由于 Pods 是 Kubernetes 集群上部署的基本单位,我们必须了解它们是如何工作的。

注意:在本章中我们将大量讨论 Pods。然而,重要的是要记住 Pods 只是部署应用程序的一种工具。

Pods vs 容器

在高层次上,Pods 位于容器和 VM 之间。它们比容器大,但比 VM 小得多。

深入挖掘一下,Pod 是一个或多个容器的共享执行环境。往往情况下,一个 Pod 只有一个容器。但多容器 Pod 绝对是存在的,它们非常适合协同调度紧密耦合的工作负载。例如,共享资源并且如果它们被调度到集群中的不同节点上将无法正常工作的两个容器。多容器 Pod 越来越常见的另一个用例是日志记录和服务网格。

Pods:典型的例子

我们通常在比较单容器和多容器 Pods 时使用的例子是一个具有文件同步器的 Web 服务器。

在这个例子中,我们有两个明确的关注点

  1. 提供网页

  2. 确保内容是最新的

注意:关注点视为需求/任务。在微服务架构中,我们经常将关注点称为服务。在前面的列表中,我们可能将网页关注点称为网页服务。每个服务处理一个关注点

一般来说,微服务设计模式要求我们应该分离关注点。这意味着一个容器只处理一个关注点。假设前面的例子,一个容器用于 web 服务,另一个容器用于文件同步服务。

这种方法有很多优势。

我们不是构建单体应用程序,其中单个 Pod 运行 Web 服务文件同步服务,而是构建两个微服务-每个微服务都有自己独特的关注点。这意味着我们可以有不同的团队负责这两个服务。我们可以独立扩展每个服务。我们也可以独立更新它们。如果运行文件同步服务的 Pod 失败,Web 服务可以保持运行(尽管可能会提供过时内容)。

然而,有时在单个 Pod 中共同调度多个容器是有意义的。使用情况包括;需要共享内存或共享卷的两个容器。见图 4.2。

图 4.2

图 4.2

在这种情况下,我们没有分离关注点-一个单独的 Pod 正在执行两项任务。然而,实现共享卷的最简单方法是将将共享卷的容器调度到同一节点上。通过在同一个 Pod 中运行 Web 服务容器和文件同步容器,我们确保它们部署到同一节点上。我们还为它们提供了一个共享的操作环境,两者都可以访问相同的共享内存和共享卷等。稍后会详细介绍所有这些。

总之,一般规则是通过设计 Pod 和容器来分离关注点,每个 Pod 执行单个任务,然后为每个 Pod 调度单个容器。然而,有些情况下打破这个规则是有优势的。

我们如何部署 Pods

要将 Pod 部署到 Kubernetes 集群中,我们在清单文件中定义它,并将该清单文件POST到 API 服务器。控制平面检查它,将其记录在集群存储中,并调度器将其部署到具有足够可用资源的健康节点上。无论 Pod 运行多少个容器,这个过程都是相同的。

图 4.3

图 4.3

让我们深入一点…

Pod 的解剖

在最高级别上,Pod 是一个或多个容器的共享执行环境。“共享执行环境”意味着 Pod 具有一组资源,这些资源被 Pod 内的每个容器共享。这些资源包括;IP 地址,端口,主机名,套接字,内存,卷等等…

如果您将 Docker 用作 Kubernetes 的容器运行时,Pod 实际上是一种称为暂停容器的特殊容器。没错,Pod 只是一个特殊容器的花哨名称!

这意味着在 Pod 内运行的容器实际上是在容器内运行的容器!有关更多信息,请观看克里斯托弗·诺兰执导、莱昂纳多·迪卡普里奥主演的《盗梦空间》😄

但是,Pod(暂停容器)只是容器内运行的容器将继承和共享的一组系统资源。这些“系统资源”是“内核命名空间”,包括:

  • 网络命名空间:IP 地址、端口范围、路由表…

  • UTS 命名空间:主机名

  • IPC 命名空间:Unix 域套接字…

正如我们刚才提到的,这意味着 Pod 中的所有容器共享主机名、IP 地址、内存地址空间和卷。

让我们更仔细地看看这如何影响网络。

每个 Pod 都创建自己的网络命名空间 - 单个 IP 地址、单个端口范围和单个路由表。即使 Pod 是多容器 Pod,每个 Pod 中的容器也共享 Pod 的 IP、端口范围和路由表。

图 4.4 显示了两个具有自己 IP 的 Pod。即使其中一个 Pod 托管了两个容器,它仍然只有一个 IP。

图 4.4

图 4.4

在图 4.4 的示例中,我们可以使用 Pod IP 与容器的个别端口号(80 和 5000)来访问 Pod 1 中的各个容器。

最后一次(如果感觉我反复强调了,我很抱歉)… Pod 中的每个容器都共享Pod的整个网络命名空间 - IP、localhost适配器、端口范围、路由表等。

但正如我们所说,它不仅仅是网络。Pod 中的所有容器都可以访问相同的卷、相同的内存、相同的 IPC 套接字等。从技术上讲,Pod(暂停容器)包含所有命名空间,Pod 中的任何容器都会继承并共享它们。

这种网络模型使Pod 间通信变得非常简单。集群中的每个 Pod 都有自己的 IP 地址,在Pod 网络上是完全可路由的。如果您阅读了有关安装 Kubernetes 的章节,您会看到我们在Play with Kuberneteskubeadm部分末尾创建了一个 Pod 网络。因为每个 Pod 都有自己的可路由 IP,所以每个 Pod 都可以直接与其他 Pod 通信。不需要处理像恶心的端口映射之类的东西!

图 4.5 Pod 间通信

图 4.5 Pod 间通信

Pod 内部通信-同一 Pod 中的两个容器需要通信-可以通过 Pod 的localhost接口进行。

图 4.6 Pod 内部通信

图 4.6 Pod 内部通信

如果需要使同一 Pod 中的多个容器对外界可用,可以在各自的端口上公开它们。每个容器都需要自己的端口,同一 Pod 中的两个容器不能使用相同的端口。

总之。一切都关乎PodPod被部署,Pod获得 IP,Pod拥有所有的命名空间... Pod是 Kuberverse 的中心!

Pods 和 cgroups

在高层次上,控制组(cgroups)是阻止单个容器在节点上消耗所有可用的 CPU、RAM 和 IOPS 的东西。我们可以说 cgroups“监管”资源使用。

单个容器有自己的 cgroup 限制。

这意味着单个 Pod 中的两个容器可以拥有自己的 cgroup 限制集。这是一个强大而灵活的模型。如果我们假设前面章节中的典型多容器 Pod 示例,我们可以在文件同步容器上设置 cgroup 限制,以便它可以访问比 web 服务容器更少的资源。这将减少它使 web 服务容器饥饿的 CPU 和内存的风险。

Pod 的原子部署

部署 Pod 是一个原子操作。这意味着这是一个全包或全不包的操作-没有部分部署的 Pod 可以提供服务。

例如,要么:Pod 中的所有内容都启动并且 Pod 变得可用,或者,所有内容都没有启动并且 Pod 失败。这意味着你永远不会出现一个多容器 Pod 的一部分容器启动并且可访问,但另一个容器处于失败状态的情况!这不是它的工作方式。直到整个 Pod 都启动后,Pod 中的任何内容都不可用。一旦所有 Pod 资源准备就绪,Pod 就变得可用。

同样重要的是强调,任何给定的 Pod 只能在单个节点上运行。这与容器和虚拟机相同-你不能让一个 Pod 的一部分在一个节点上,另一部分在另一个节点上。一个 Pod 被调度到一个节点上!

Pod 生命周期

典型 Pod 的生命周期大致如下。你在一个 YAML 清单文件中定义它。然后你将清单文件扔给 API 服务器,它定义的 Pod 被调度到一个健康的节点上。一旦它被调度到一个节点,它就进入pending状态,同时节点下载镜像并启动任何容器。Pod 将保持在这个pending状态,直到它的所有资源都准备就绪。一旦一切都准备就绪,Pod 进入running状态。一旦它完成了它需要做的一切,它就被终止并进入succeeded状态。

如果你独立部署一个 Pod(而不是通过更高级别的对象),并且该 Pod 失败了,它不会被重新调度!因此,我们很少直接部署它们。更常见的是通过更高级别的对象如DeploymentsDaemonSets来部署它们,因为这些对象在它们失败时会重新调度 Pods。

当一个 Pod 无法启动时,它可以保持在pending状态或进入failed状态。这都显示在图 4.7 中。

图 4.7 Pod 生命周期

图 4.7 Pod 生命周期

将 Pod 视为有限的也很重要。当它们死了,它们就死了!不能让它们从死亡中复活。这遵循宠物与牛群的类比 - Pods 应该被视为牛群。当它们死了,你用另一个替换它们。没有眼泪,没有葬礼。旧的消失了,一个全新的 - 具有相同的配置,但不同的 ID 和 IP - 神奇地出现并取代它的位置。

注意:在提到宠物与牛群的类比时,不是针对任何人或动物的冒犯。

这是你应该编写应用程序的主要原因之一,这样它们就不会在 Pods 中存储状态。这也是为什么我们不应该依赖于单个 Pod IP 等。

Pod 理论总结

  1. Pods 是 Kubernetes 中调度的原子单位

  2. 一个 Pod 中可以有多个容器。单容器 Pods 是最简单的,但多容器 Pods 非常适合需要紧密耦合的容器 - 也许它们需要共享内存或卷。它们也非常适合日志记录和服务网格。

  3. Pods 被调度到节点上 - 你不能调度一个单个 Pod 实例跨越多个节点。

  4. Pods 在一个清单文件中被声明,并通过调度器分配给节点。

与 Pods 一起动手

是时候看看 Pods 的实际操作了!

在本章的其余示例中,我们将使用图 4.8 中显示的 3 节点集群。

图 4.8

图 4.8

这个集群在哪里并不重要,或者它是如何部署的。重要的是你有三个 Linux 主机配置成一个 Kubernetes 集群,至少有一个主节点和两个节点。你还需要安装并配置kubectl以便与集群通信。

如果您没有集群并希望跟随操作,请转到 http://play-with-k8s.com 并构建一个快速集群 - 这是免费且简单的。

遵循 Kubernetes 的可组合基础设施理念,我们在清单文件中定义 Pods,将清单发布到 API 服务器,并让调度器负责在集群上实例化 Pods。

Pod 清单文件

在本章的示例中,我们将使用以下 Pod 清单。它在书籍的 GitHub 存储库中的pods文件夹下的 pod.yml 中可用:

apiVersion

:

 v1

kind

:

 Pod

metadata

:

  name

:

 hello

-

pod

  labels

:

    zone

:

 prod

    version

:

 v1

spec

:

  containers

:

  -

 name

:

 hello

-

ctr

    image

:

 nigelpoulton

/

k8sbook

:

latest

    ports

:

    -

 containerPort

:

 8080

让我们逐步了解 YAML 文件在描述什么。

我们立即可以看到四个顶级资源:

  • .apiVersion

  • .kind

  • .metadata

  • .spec

.apiVersion字段告诉我们两件事 - 将用于创建对象的API 组API 版本。通常格式为<api-group>/<version>。但是,Pods 定义在一个称为core组的特殊 API 组中,该组省略了api-group部分。例如,StorageClass 对象在storage.k8s.io API 组的v1中定义,并在 YAML 文件中描述为storage.k8s.io/v1。但是,Pods 位于特殊的core API 组中,它省略了 API 组名称。

一个对象可以在 API 组的多个版本中定义。例如,some-api-group/v1some-api-group/v2。在这种情况下,较新组中的定义可能包括扩展对象功能的附加字段。将version字段视为定义对象模式 - 新版本通常更好。

无论如何,Pods 目前在v1 API 组中。

.kind字段告诉我们部署的对象类型。它有两个明显的功能。首先,它使阅读 YAML 文件更容易。其次,它明确告诉控制平面正在定义的对象类型,因此应将其传递给哪个控制器。

到目前为止,我们知道我们正在部署一个在core API 组v1中定义的 Pod 对象。

.metadata部分是我们附加名称和标签的地方。这些帮助我们在集群中识别对象。我们还定义了对象应该部署在哪个namespace中。简而言之,命名空间允许我们在管理目的上逻辑地划分集群。在现实世界中,强烈建议使用命名空间。但是,它们不应被视为强大的安全边界。

这个 Pod 清单的.metadata部分将 Pod 命名为“hello-pod”并分配了两个标签。标签是简单的键值对,但它们非常强大!随着我们知识的积累,我们将更多地讨论标签。

.spec部分是我们定义将在 Pod 中运行的任何容器的地方。我们的示例是部署一个基于nigelpoulton/k8sbook:latest镜像的单个容器的 Pod。它将其命名为 hello-ctr,并在端口8080上公开它。

如果这是一个多容器的 Pod,我们将在.spec部分定义额外的容器。

清单文件:代码中的共情

快速侧步。

配置文件,比如 Kubernetes 清单文件,是文档的绝佳来源。因此,它们有一些次要的好处。其中两个包括:

  • 帮助加快新团队成员的入职过程

  • 帮助弥合开发人员和运维之间的鸿沟

例如,如果你需要一个新团队成员理解一个应用的基本功能和需求,让他们阅读用于部署它的 Kubernetes 清单文件。

另外,如果你对开发人员没有清晰表达他们的应用需求有问题,让他们使用 Kubernetes。当他们通过 Kubernetes 清单描述他们的应用时,运维人员可以使用这些清单来理解应用的工作原理以及它对环境的需求。

这些好处被 Nirmal Mehta 描述为他在 2017 年 DockerCon 演讲中所说的代码中的共情的一种形式。

我知道将这些 YAML 文件描述为“代码中的共情”听起来有点极端。然而,这个概念是有价值的-它们确实有帮助。

回到正题...

从清单文件部署 Pod

如果你跟着示例操作,将以下清单文件保存为pod.yml在你当前的目录中。

apiVersion

:

 v1

kind

:

 Pod

metadata

:

  name

:

 hello

-

pod

  labels

:

    zone

:

 prod

    version

:

 v1

spec

:

  containers

:

  -

 name

:

 hello

-

ctr

    image

:

 nigelpoulton

/

k8sbook

:

latest

    ports

:

    -

 containerPort

:

 8080

使用以下kubectl命令将清单 POST 到 API 服务器,并从中部署一个 Pod。

$ kubectl apply -f pod.yml
pod "hello-pod"

 created

尽管 Pod 显示为已创建,但它可能尚未完全部署在集群上。这是因为拉取镜像可能需要一些时间。

运行kubectl get pods命令来检查状态。

$ kubectl get pods
NAME        READY    STATUS             RESTARTS   AGE
hello-pod   0

/1      ContainerCreating  0

          9s

我们可以看到容器仍在创建中 - 毫无疑问正在等待从 Docker Hub 拉取镜像。

您可以使用kubectl describe pods hello-pod命令来深入了解更多细节。

您可以向kubectl get pods命令添加--watch标志,以便可以监视它,并查看状态何时变为运行状态。

恭喜!您的 Pod 已被调度到集群中的健康节点,并且正在由节点上的本地kubelet进程监视。kubelet进程是在节点上运行的 Kubernetes 代理。

在以后的章节中,我们将看到如何连接到 Pod 中运行的 Web 服务器。

审视运行中的 Pods

尽管kubectl get pods命令很好,但细节有点少。不过,不用担心,有很多选项可以进行更深入的内省。

首先,kubectl get提供了一些非常简单的标志,可以为您提供更多信息:

-o wide标志提供了更多的列,但仍然是单行输出。

-o yaml标志将事情提升到了一个新的水平!它返回了从集群存储中的 Pod 清单的完整副本。此输出包括期望状态(.spec)和当前观察状态(.status)。

以下命令显示了kubectl get pods -o yaml命令的剪辑版本。

$ kubectl get pods hello-pod -o yaml
apiVersion: v1
kind: Pod
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |

      ...
  name: hello-pod
  namespace: default
spec:
  containers:
  - image: nigelpoulton/k8sbook:latest
    imagePullPolicy: Always
    name: hello-ctr
    ports:
status:
  conditions:
  - lastProbeTime: null
    lastTransitionTime: 2018

-10-19T15:24:24Z
    state:
      running:
        startedAt: 2018

-10-19T15:26:04Z
...

请注意,输出包含的值比我们最初在 13 行的 YAML 文件中设置的要多。这些额外的信息是从哪里来的?

两个主要来源:

  • Kubernetes Pod 对象包含许多属性 - 远远超过我们在清单中定义的属性。我们没有指定的属性将由 Kubernetes 自动扩展为默认值。

  • 当您运行带有-o yamlkubectl get pods时,您将获得 Pods 的当前观察状态以及其期望状态。此观察状态列在.status部分中。

另一个很棒的 Kubernetes 内省命令是kubectl describe。它提供了一个格式良好的、多行的对象概述。它甚至包括一些重要的对象生命周期事件。以下命令描述了 hello-pod Pod 的状态,并显示了一个剪辑输出。

$

 kubectl

 describe

 pods

 hello

-

pod

Name

:

         hello

-

pod

Namespace

:

    default

Node

:

         docker

-

for

-

desktop

/

192.168

.

65.3

Start

 Time

:

   Fri

,

 19

 Oct

 2018

 16

:

24

:

24

 +

0100

Labels

:

       version

=

v1

              zone

=

prod

Status

:

       Running

IP

:

           10.1

.

0.21

Containers

:

  hello

-

ctr

:

    Image

:

          nigelpoulton

/

k8sbook

:

latest

    Port

:

           8080

/

TCP

    Host

 Port

:

      0

/

TCP

    State

:

          Running

Conditions

:

  Type

           Status

  Initialized

    True

  Ready

          True

  PodScheduled

   True

...

Events

:

  Type

    Reason

     Age

   Message

  ----

    ------

     ----

  -------

  Normal

  Scheduled

  2

m

   Successfully

 assigned

...

  Normal

  Pulling

    2

m

   pulling

 image

 "nigelpoulton/k8sbook:latest"

  Normal

  Pulled

     2

m

   Successfully

 pulled

 image

  Normal

  Created

    2

m

   Created

 container

  Normal

  Started

    2

m

   Started

 container

输出已经被剪辑以使其适合页面。

内省运行中的 Pod 的另一种方法是登录到其中或在其中执行命令。我们使用kubectl exec命令来实现这一点。以下示例显示了如何在hello-pod Pod 中的第一个容器中执行ps aux命令。

$ kubectl exec

 hello-pod ps aux
PID   USER     TIME   COMMAND
  1

   root     0

:00   node ./app.js
 40

   root     0

:00   ps aux

您可以使用以下命令登录到 Pod 中的第一个容器。一旦进入容器,您可以执行正常的命令(只要命令二进制文件安装在容器中)。

kubectl exec命令将登录到 Pod 中的第一个容器并创建一个新的 shell 会话。一旦进入容器,curl命令将从在端口8080上监听的进程传输数据。

$ kubectl exec -it hello-pod sh

sh-4.1 # curl localhost:8080
<html><head><title>

Pluralsight Rocks</title><link

 rel=

"stylesheet"

 href=

"http:/\

/netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"

/></head><body>

<

\
div class="container"><div

 class=

"jumbotron"

><h1>

Yo Pluralsighters!!!</h1><p>

Cl\
ick the button below to head over to my podcast...</p><p>

 <a

 href=

"http://intec\

hwetrustpodcast.com"

 class=

"btn btn-primary"

>

Podcast</a></p><p></p></div></div>

\
</body></html>

-it标志使exec会话变得交互,并将您的终端窗口上的 STDIN 和 STDOUT 连接到 Pod 中第一个容器内的 STDIN 和 STDOUT。当命令完成时,您的 shell 提示符将更改,表示您的 shell 现在已连接到容器。

如果您正在运行多容器 Pods,您将需要传递kubectl exec命令--container标志,并给出要在其中创建 exec 会话的 Pod 中容器的名称。如果您不指定此标志,该命令将针对 Pod 中的第一个容器执行。您可以使用kubectl describe pods <pod>命令查看 Pod 中容器的顺序和名称。

另一个用于内省 Pod 的命令是kubectl logs命令。与其他与 Pod 相关的命令一样,如果您没有按名称指定容器,它将针对 Pod 中的第一个容器执行。命令的格式是kubectl logs <pod>

显然,Pods 还有很多内容我们没有涉及到。但是,我们已经学到了足够的知识来开始。

使用以下命令清理您的实验室。

$ kubectl delete -f pod.yml
pod "hello-pod"

 deleted

章节总结

在本章中,我们了解到 Kubernetes 世界中部署的原子单位是Pod。每个 Pod 由一个或多个容器组成,并部署到集群中的单个节点。部署操作是一个全有或全无的原子事务

使用 YAML 清单文件以声明方式部署 Pod 是最佳方式。我们使用kubectl命令将清单POST到 API 服务器,它将存储在集群存储中,并转换为一个 PodSpec,然后被调度到具有足够可用资源的健康集群节点上。

接受 PodSpec 的工作节点上的进程是kubelet。这是在集群中每个节点上运行的主要 Kubernetes 代理。它接受 PodSpec 并负责拉取所有镜像并启动 Pod 中的所有容器。

如果 Pod 失败,它不会自动重新调度。因此,我们通常通过更高级别的对象(如部署和守护进程)来部署它们。这些对象添加了诸如自愈和回滚之类的功能,是使 Kubernetes 如此强大的核心。

第六章:Kubernetes 部署

在本章中,我们将看到部署如何为 Kubernetes 带来自愈、可伸缩、滚动更新和回滚。

我们将按以下方式拆分本章:

  • 部署理论

  • 如何创建部署

  • 如何执行滚动更新

  • 如何执行回滚

部署理论

在高层次上,我们从应用程序代码开始。将其打包为容器,并包装在 Pod 中,以便在 Kubernetes 上运行。但是,Pod 不会自愈,它们不会扩展,也不会允许轻松更新。

部署可以做所有这些事情- 自愈、扩展和滚动更新。因此,我们几乎总是通过部署部署 Pod。见图 5.1。

![图 5.1](Image00030.gif)

图 5.1

重要的是要知道,部署只管理一组相同的 Pod。例如,如果您有一个应用程序,其中一个 Pod 用于前端,另一个 Pod 用于后端,您将需要两个部署。

接下来要知道的是,部署是 Kubernetes API 中的完整对象。这意味着我们在清单文件中定义它们,然后将它们POST到 API 服务器。

最后要注意的是,幕后,部署利用了另一个称为副本集的对象。我们不直接管理副本集,但了解它们很重要,因为这将有助于解释我们即将描述的一些操作的机制。

保持高层次,部署使用副本集来提供自愈和可伸缩性。见图 5.2。

![图 5.2](Image00031.gif)

图 5.2

总之;部署管理副本集,而副本集管理Pod。把它们放在一起,我们有了一个在 Kubernetes 上部署和管理应用程序的好方法!

自愈和可伸缩性

Pod 很棒。它们通过允许容器共存、共享卷、共享内存、简化网络等方式增强了容器。但是它们在自愈和可伸缩方面没有任何作用。

进入部署。

部署通过添加自愈和可伸缩等功能来增强 Pod。这意味着:

  • 如果由部署管理的 Pod 失败,它将被替换- 自愈

  • 如果由部署管理的 Pod 看到负载增加,您可以轻松地添加更多相同的 Pod 来处理负载- 扩展

然而,在幕后,部署使用一个称为 ReplicaSet 的对象来实现自愈和可伸缩性。但是,ReplicaSets 在后台运行,我们总是通过部署来管理它们。因此,我们将主要关注部署方面的事情。

这一切都与状态有关。

在继续之前,了解三个对 Kubernetes 的一切都至关重要的概念是至关重要的:

  • 期望状态

  • 当前状态(有时称为实际状态观察状态

  • 声明性模型

期望状态是您想要的。当前状态是您拥有的。如果两者匹配,每个人都很高兴。

声明性模型是告诉 Kubernetes 我们的期望状态是什么,而不涉及如何实现它的细节。

声明性模型

有两种竞争模型。声明性模型命令模型

声明性模型是关于描述最终目标的 - 告诉 Kubernetes 你想要什么。命令模型是关于实现最终目标的命令列表 - 告诉 Kubernetes如何做某事。

让我们看一个例子。

假设您有一个具有两个服务 - 前端和后端的应用程序。您已经配置好了,这样您就有了一个用于前端服务的 Pod,以及一个用于后端服务的单独的 Pod。为了满足预期的需求,您总是需要 5 个前端 Pod 的实例和 2 个后端 Pod 的实例。

采用声明性方法,您创建一个配置文件,告诉 Kubernetes 您的前端和后端 Pod 应该是什么样子 - 例如要使用什么镜像和要暴露什么端口。在同一个文件中,您还告诉 Kubernetes 您想要 5 个前端 Pod 的副本和 2 个后端 Pod 的副本。这就是您的期望状态。然后将该文件交给 Kubernetes,然后坐下来,让 Kubernetes 来实现它的艰苦工作。但事情并不止于此... Kubernetes 实现了不断检查集群上的内容是否与您要求的内容匹配的监视循环(当前状态是否与期望状态匹配)。

太棒了!

声明性模型的相反是命令式模型。在命令式模型中,没有期望状态的概念。相反,您需要编写一堆脚本,其中包含构建所需的所有命令。而且你必须关心实现细节。例如,启动containerd容器的命令与启动rkt容器的命令不同。这最终会导致更多的工作,更容易出错,并且因为它没有声明期望状态,所以没有自我修复。

这不太好: -(

Kubernetes 支持两种模型,但强烈倾向于声明性模型。

调和循环

期望状态的基础是后台调和循环的概念。

例如,ReplicaSets 实现了一个后台调和循环,不断检查集群上是否存在正确数量的 Pod 副本。如果不够,它会添加更多。如果太多,它会终止一些。

要非常清楚- Kubernetes 不断检查当前状态是否与期望状态匹配!*

如果它们不匹配-可能期望状态是 10 个副本,但只有 8 个在运行-Kubernetes 会切换到红色警报,命令控制平面进入战斗状态,并启动另外两个副本。最好的部分是...它在清晨 4:20 不会给你打电话!

但这不仅仅是故障场景。这些完全相同的调和循环也实现了扩展!

例如,如果您将应用程序配置的更新发送到POST,将副本计数从 3 增加到 5。新值 5 将被注册为应用程序的新期望状态,并且在下一次调和循环运行时,它将注意到差异并遵循相同的过程-发出红色警报的警报声,并启动另外两个副本。

这是一件美好的事情!

使用部署进行滚动更新

除了自我修复和扩展,部署还为我们提供了零停机滚动更新。

如前所述。部署使用 ReplicaSets 进行一些后台工作。实际上,每次创建部署时,我们都会自动获得一个管理部署 Pod 的 ReplicaSet。

注意:您不应直接管理作为部署的一部分创建的 ReplicaSets。您应该对部署对象执行所有操作,并让部署对象管理其自己的 ReplicaSets。

它的工作原理是这样的。我们将我们的应用程序设计为每个独立的服务作为一个 Pod。为了方便 - 自愈、扩展、滚动更新等 - 我们将 Pod 包装在一个部署中。这意味着创建一个描述以下所有内容的 YAML 配置文件:

  • 有多少个 Pod 副本

  • 用于 Pod 容器的镜像

  • 使用哪些网络端口

  • 关于如何执行滚动更新的详细信息

您将该 YAML 文件发布到 API 服务器,Kubernetes 会完成所有的艰苦工作来实施它。

一旦实施,Kubernetes 设置了一个监视循环,以确保观察到的状态与期望的状态相匹配。

到目前为止一切顺利。

现在,假设您想要更新 Pod 使用的镜像版本。为此,您使用新的镜像版本更新相同的部署 YAML 文件,并将其重新发布到 API 服务器。这在集群上注册了一个新的期望状态,请求相同数量的 Pod,但都运行新版本的镜像。为了实现这一点,Kubernetes 为具有新镜像的 Pod 创建了一个新的 ReplicaSet。现在我们有两个 ReplicaSets - 一个用于具有旧版本镜像的 Pod,另一个用于具有新版本的 Pod。当 Kubernetes 增加新 ReplicaSet 中的 Pod 数量(具有新版本的镜像)时,它会减少旧 ReplicaSet 中的 Pod 数量(具有旧版本的镜像)。最终结果是,我们可以实现零停机的平滑滚动更新。而且我们可以为将来的更新重复这个过程 - 只需不断更新那个清单文件(应该存储在版本控制系统中)。

太棒了!

图 5.3 显示了一个已经更新了一次的部署。初始部署在左侧创建了 ReplicaSet,更新在右侧创建了 ReplicaSet。我们可以看到初始部署的 ReplicaSet 已经被逐渐停止,不再拥有任何 Pod。与更新相关的 ReplicaSet 是活动的,并拥有所有的 Pod。

图 5.3

图 5.3

回滚

正如我们在图 5.3 中看到的,旧的 ReplicaSets 仍然存在,不会被删除。它们已经被逐渐停止,因此不再管理任何 Pod,但它们仍然存在。这使它们成为恢复到先前版本的一个很好的选项。

回滚的过程本质上是滚动更新的相反过程 - 将旧的 ReplicaSet 逐渐启动,将当前的 ReplicaSet 逐渐停止。简单!

图 5.4 显示了同一应用程序回滚到初始修订版。

图 5.4

图 5.4

但这还不是结束!内置的智能让我们能够说出像“在每个 Pod 启动后等待 X 秒再将其标记为健康…” 这样的话。还有就绪探针和各种各样的东西。总的来说,部署非常适合执行滚动更新和版本回滚。

考虑到所有这些,让我们动手创建一个部署。

如何创建部署

在本节中,我们将从 YAML 文件创建一个全新的 Kubernetes 部署。我们可以使用 kubectl run 命令以命令方式执行相同的操作,但我们不应该这样做!正确的方式是声明式的方式!

以下代码片段是我们将使用的部署清单文件,示例假设它被称为 deploy.yml

如果您正在使用较旧版本的 Kubernetes,应该使用 apps/v1beta1 API。

apiVersion

:

 apps

/

v1

kind

:

 Deployment

metadata

:

  name

:

 hello

-

deploy

spec

:

  replicas

:

 10

  selector

:

    matchLabels

:

      app

:

 hello

-

world

  minReadySeconds

:

 10

  strategy

:

    type

:

 RollingUpdate

    rollingUpdate

:

      maxUnavailable

:

 1

      maxSurge

:

 1

  template

:

    metadata

:

      labels

:

        app

:

 hello

-

world

    spec

:

      containers

:

      -

 name

:

 hello

-

pod

        image

:

 nigelpoulton

/

k8sbook

:

latest

        ports

:

        -

 containerPort

:

 8080

警告: 本书中使用的图像未经维护,将充满漏洞和其他安全问题。

让我们逐步浏览文件并解释一些重要部分。

就在最顶部,我们正在指定要使用的 API 版本。假设您正在使用最新版本的 Kubernetes,部署对象位于 apps/v1 API 组中。如果您使用的是旧版本,可以尝试 apps/v1beta1extensions/v1beta2

接下来,.kind 字段告诉 Kubernetes 我们正在定义一个部署 - 这是 Kubernetes 知道将其发送到控制平面上的部署控制器的方式。

.metadata 部分是我们为部署指定名称和标签的地方。

.spec 部分是大部分操作发生的地方。.spec.replicas 告诉 Kubernetes 为这个部署创建多少个 Pod 副本。spec.selector 是 Pod 必须具有的标签列表,以便部署管理它们。而 .spec.strategy 告诉 Kubernetes 如何执行对部署的更新。

使用 kubectl apply 在集群上实现它。

注意: kubectl apply 将 YAML 文件发送到 Kubernetes API 服务器。

$ kubectl apply deployment -f deploy.yml
deployment.apps "hello-deploy"

 created

部署在集群上实例化。

检查部署

我们可以使用通常的 kubectl getkubectl describe 命令来查看部署的详细信息。

$

 kubectl

 get

 deploy

 hello

-

deploy

NAME

          DESIRED

   CURRENT

  UP

-

TO

-

DATE

  AVAILABLE

   AGE

hello

-

deploy

  10

        10

       10

          10

          1

m

$

 kubectl

 describe

 deploy

 hello

-

deploy

Name

:

         hello

-

deploy

Namespace

:

    default

Selector

:

     app

=

hello

-

world

Replicas

:

               10

 desired

 |

 10

 updated

 |

 10

 total

 ...

StrategyType

:

           RollingUpdate

MinReadySeconds

:

        10

RollingUpdateStrategy

:

  1

 max

 unavailable

,

 1

 max

 surge

Pod

 Template

:

  Labels

:

               app

=

hello

-

world

  Containers

:

        hello

-

pod

:

          Image

:

        nigelpoulton

/

k8sbook

:

latest

          Port

:

         8080

/

TCP

<SNIP>

为了便于阅读,命令输出已被修剪。您的输出将显示更多信息。

正如我们之前提到的,部署会自动创建关联的 ReplicaSets。使用以下 kubectl 命令来确认这一点。

$ kubectl get rs
NAME                  DESIRED   CURRENT  READY   AGE
hello-deploy-7bbd...  10

        10

       10

      5m

现在,我们只有一个 ReplicaSet。这是因为我们只执行了部署的初始推出。然而,我们可以看到它与部署的名称相同,后面跟着 YAML 清单文件的 Pod 模板部分的哈希值。

我们可以使用通常的kubectl describe命令获取有关 ReplicaSet 的更详细信息。

访问应用

为了从稳定的名称或 IP 地址访问应用,甚至从集群外部访问,我们需要一个 Kubernetes Service 对象(关于这些内容将在下一章中详细介绍)。现在,你只需要知道 Kubernetes Services 为一组 Pods 提供了稳定的 DNS 名称和 IP 地址。

以下的 YAML 定义了一个将与先前部署的 Pod 一起工作的 Service。

  apiVersion: v1
  kind: Service
  metadata:
    name: hello-svc
    labels:
      app: hello-world
  spec:
    type: NodePort
    ports:
    - port: 8080
      nodePort: 30001
      protocol: TCP
    selector:
      app: hello-world

使用以下命令部署它(该命令假设清单文件名为svc.yml)。

  $ kubectl apply -f svc.yml
  service "hello-svc" created

现在 Service 已经部署,你可以通过以下任一方式访问它:

  1. 从集群内部使用 DNS 名称hello-svc在端口8080上。

  2. 从集群外部,通过命中端口30001上的任何集群节点

图 5.5 显示了通过名为node1的节点在端口30001上从集群外部访问 Service。它假设node1是可解析的,并且端口30001被任何中间防火墙允许。

如果你正在使用 Minikube,你应该在 Minikube IP 地址的末尾添加端口30001。使用minikube ip命令获取你的 Minikube 的 IP 地址。

图 5.5

图 5.5

执行滚动更新

在本节中,我们将看到如何对我们刚刚部署的应用执行滚动更新。我们将假设应用的新版本已经被创建并作为带有edge标签的 Docker 镜像容器化。现在只需要使用 Kubernetes 将更新推送到生产环境。在本例中,我们将忽略真实的 CI/CD 工作流和版本控制工具。

我们需要做的第一件事是更新部署清单文件中使用的镜像标签。我们部署的应用的初始版本使用了标记为nigelpoulton/k8sbook:latest的镜像。我们将更新部署清单的.spec.template.spec.containers部分,以引用新的nigelpoulton/k8sbook:edge镜像。这将确保下次清单被 POST 到 API 服务器时,部署中的所有 Pod 将被更新为运行新的edge镜像。

以下是更新后的 deploy.yml 清单文件 - 唯一的更改是由注释行指示的 .spec.template.spec.containers.image

apiVersion

:

 apps

/

v1

kind

:

 Deployment

metadata

:

  name

:

 hello

-

deploy

spec

:

  replicas

:

 10

  selector

:

    matchLabels

:

      app

:

 hello

-

world

  minReadySeconds

:

 10

  strategy

:

    type

:

 RollingUpdate

    rollingUpdate

:

      maxUnavailable

:

 1

      maxSurge

:

 1

  template

:

    metadata

:

      labels

:

        app

:

 hello

-

world

    spec

:

      containers

:

      -

 name

:

 hello

-

pod

        image

:

 nigelpoulton

/

k8sbook

:

edge

   #

 This

 line

 changed

        ports

:

        -

 containerPort

:

 8080

警告:本书中使用的图像未经维护,将充满漏洞和其他安全问题。

让我们来看看管理部署更新的设置。

清单的 .spec 部分包含了所有与更新执行相关的设置。感兴趣的第一个值是 .spec.minReadySeconds。我们将其设置为 10,告诉 Kubernetes 在更新每个 Pod 后等待 10 秒再继续更新下一个。这对于限制更新发生的速率很有用 - 较长的等待时间给我们发现问题的机会,并避免将所有 Pod 更新为有问题的 Pod 的情况。

我们还有一个嵌套的 .spec.strategy 映射,告诉 Kubernetes 我们希望这个部署:

  • 使用 RollingUpdate 策略进行更新

  • 永远不要低于期望状态的一个 Pod(maxUnavailable: 1

  • 永远不要超过期望状态的一个 Pod(maxSurge: 1

由于应用的期望状态要求有 10 个副本,maxSurge: 1 意味着在更新过程中我们永远不会有超过 11 个 Pod,而 maxUnavailable: 1 意味着我们永远不会少于 9 个。

准备好更新的清单后,我们可以通过重新将更新后的 YAML 文件发送到 API 服务器来启动更新。

$ kubectl apply -f deploy.yml --record
deployment.apps "hello-deploy"

 configured

更新可能需要一些时间才能完成。这是因为它将逐个 Pod 迭代,每个节点下载新的图像,启动新的 Pod,并在移动到下一个 Pod 之前等待 10 秒。

我们可以使用 kubectl rollout status 监控更新的进度。

$ kubectl rollout status deployment hello-deploy
Waiting for

 rollout to finish: 4

 out of 10

 new replicas...
Waiting for

 rollout to finish: 4

 out of 10

 new replicas...
Waiting for

 rollout to finish: 5

 out of 10

 new replicas...
^C

如果按下 Ctrl+C 停止观察更新的进度,您可以在更新过程中运行 kubectl get deploy 命令。这样我们就可以看到清单中一些与更新相关的设置的效果。例如,以下命令显示有 5 个副本已经更新,当前有 11 个。11 比期望的 10 多了 1 个。这是清单中 maxSurge=1 值的结果。

$ kubectl get deploy
NAME           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-deploy   10

        11

        5

            9

           28m

更新完成后,我们可以使用 kubectl get deploy 进行验证。

$ kubectl get deploy hello-deploy
NAME          DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-deploy  10

        10

        10

           10

          39m

输出显示更新已完成 - 10 个 Pod 已经是最新的。您可以使用 kubectl describe deploy 命令获取有关部署状态的更详细信息 - 这将包括输出的 Pod 模板 部分中的新图像版本。

如果您一直在关注示例,您可以在浏览器中点击“刷新”并查看更新后的应用程序(图 5.6)。

图 5.6

图 5.6

应用程序的旧版本显示“Kubernetes Rocks!”,新版本显示“The Kubernetes Book!!!”。

如何执行回滚

刚才,我们使用kubectl apply对部署执行了滚动更新。我们使用了--record标志,以便 Kubernetes 会维护部署的修订历史。以下kubectl rollout history命令显示了具有两个修订的部署。

$ kubectl rollout history

 deployment hello-deploy
deployments "hello-deploy"

REVISION  CHANGE-CAUSE
1

         <none>
2

         kubectl apply -filename-deploy.yml --record=

true

修订版1是使用latest图像标记的初始部署。修订版2是我们刚刚执行的滚动更新,我们可以看到我们用来调用更新的命令已记录在对象的历史记录中。这仅因为我们在调用更新命令时使用了--record标志。这可能是您使用--record标志的一个很好的理由。

在本章的前面,我们说更新部署会创建一个新的 ReplicaSet,并且以前的 ReplicaSets 不会被删除。我们可以使用kubectl get rs来验证这一点。

$ kubectl get rs
NAME                  DESIRED  CURRENT  READY  AGE
hello-deploy-6bc8...  10

       10

       10

     10m
hello-deploy-7bbd...  0

        0

        0

      52m

输出显示初始修订的 ReplicaSet 仍然存在(hello-deploy-7bbd...),但已被关闭,并且不再管理任何副本。hello-deploy-6bc8... ReplicaSet 是最新修订的 ReplicaSet,并且在管理下有 10 个副本。然而,以前的版本仍然存在使得回滚变得非常简单。

值得运行kubectl describe rs来证明旧的 ReplicaSet 的配置仍然存在。

以下示例使用kubectl rollout命令将应用程序回滚到修订版 1。这是一个命令式操作,不建议使用。但是,对于快速回滚来说可能很方便,只需记住更新源 YAML 文件以反映您对集群所做的命令式更改。

$ kubectl rollout undo deployment hello-deploy --to-revision=

1

deployment.apps "hello-deploy"

 rolled back

尽管回滚操作看起来可能是瞬时的,但实际上并非如此。回滚遵循部署清单中规定的相同规则-minReadySeconds: 10maxUnavailable: 1maxSurge: 1。您可以使用以下kubectl get deploykubectl rollout命令来验证这一点并跟踪进度。

$ kubectl get deploy hello-deploy
NAME          DESIRED  CURRNET  UP-TO-DATE  AVAILABE  AGE
hello-deploy  10

       11

       4

           9

         45m

$ kubectl rollout status deployment hello-deploy
Waiting for

 rollout to finish: 6

 out of 10

 new replicas have been updated...
Waiting for

 rollout to finish: 7

 out of 10

 new replicas have been updated...
Waiting for

 rollout to finish: 8

 out of 10

 new replicas have been updated...
Waiting for

 rollout to finish: 1

 old replicas are pending termination...
Waiting for

 rollout to finish: 9

 of 10

 updated replicas are available...
^C

恭喜。您已执行了滚动更新和成功的回滚。

使用kubectl delete -f deploy.yml来删除示例中使用的部署。

章节总结

在这一章中,我们了解到部署是管理 Kubernetes 应用程序的一种很好的方式。它们在 Pods 的基础上添加了自愈、可伸缩性、滚动更新和回滚功能。在幕后,它们利用 ReplicaSets 来实现自愈和可伸缩性。

与 Pods 一样,部署是 Kubernetes API 中的对象,我们应该以声明性的方式与它们一起工作。

当我们使用kubectl apply命令进行更新时,旧版本的 ReplicaSets 会被逐渐关闭,但它们仍然存在,这样就可以轻松进行回滚操作。

第七章:Kubernetes Services

在之前的章节中,我们已经启动了 Pods 并使用 Deployments 来添加自愈、可伸缩性和滚动更新。然而,尽管所有这些,我们仍然不能依赖 Pod IPs!在本章中,我们将看到 Kubernetes Services如何给我们提供可靠的网络。

我们将把本章分成以下几部分:

  • 设置场景

  • 理论

  • 实践操作

  • 现实世界的例子

设置场景

在深入之前,我们需要提醒自己Pod IPs 是不可靠的。当 Pods 失败时,它们会被具有新 IP 的新 Pods 替换。扩展 Deployment 会引入具有新 IP 地址的新 Pods。缩减 Deployment 会移除 Pods。所有这些都会产生大量的 IP 变动,并且会导致无法依赖 Pod IPs 的情况。

我们还需要了解 Kubernetes Services 的 3 个基本要点。

首先,我们需要澄清一些术语。在本章中,当谈到Service时,我们指的是 Kubernetes API 中的 Service REST 对象。就像PodReplicaSetDeployment一样,Kubernetes Service是 API 中的一个对象,我们在清单中定义并 POST 到 API 服务器中。

其次,我们需要知道每个 Service 都有自己的稳定 IP 地址,自己的稳定 DNS 名称和自己的稳定端口

第三,我们需要知道 Services 使用标签来动态选择集群中要发送流量的 Pods。

最后两点是允许 Services 为动态的一组 Pods 提供稳定网络的关键。

理论

图 6.1 显示了通过 Kubernetes Deployment 部署的一个简单的基于 Pod 的应用程序。它显示了一个客户端(可能是应用程序的另一个组件),它没有可靠的网络端点来访问 Pods - 请记住 Pod IPs 是不可靠的。

图 6.1

图 6.1

图 6.2 显示了相同的应用程序,其中添加了一个 Service。该 Service 与 Pods 关联,并为它们提供稳定的 IP、DNS 和端口。它还在 Pods 之间负载均衡请求。

图 6.2

图 6.2

有了一个 Service 在一组 Pods 的前面,Pods 可以扩展和缩减,它们可以失败,它们可以被更新...当这些事情发生时,Service 会注意到这些变化并更新对 Pods 的了解。但它永远不会改变它暴露的稳定 IP、DNS 和端口!

标签和松耦合

通过标签标签选择器,Pod 和服务松散耦合。这与将部署与 Pod 链接的技术相同。图 6.3 显示了一个示例,其中 3 个 Pod 被标记为zone=prodversion=1,而 Service 具有一个标签选择器与之匹配。

图 6.3

图 6.3

在图 6.3 中,服务为所有三个 Pod 提供稳定的网络 - 您可以向服务发送请求,它将代理它们到 Pod。它还提供简单的负载平衡。

为了使服务匹配一组 Pod,从而提供稳定的网络和负载平衡,它只需要匹配 Pod 上的一些标签。然而,为了使 Pod 匹配服务,它必须具有服务正在寻找的所有标签。如果这听起来令人困惑,图 6.4 和 6.5 中的示例应该有所帮助。

图 6.4 显示了一个示例,其中 Service 与任何 Pod 都不匹配。这是因为 Service 正在寻找具有两个标签的 Pod,但 Pod 只拥有其中一个。这背后的逻辑是布尔AND操作。

图 6.4

图 6.4

图 6.5 显示了一个确实有效的示例。这是因为服务正在选择两个标签,并且图中的 Pod 都具有这两个标签。并不重要 Pod 具有服务不在寻找的额外标签。服务正在寻找具有两个标签的 Pod,它找到了它们,并忽略了 Pod 具有额外标签的事实 - 重要的是 Pod 具有服务正在寻找的标签。

图 6.5

图 6.5

以下摘录来自 Service YAML 和 Deployment YAML,展示了选择器标签的实现方式。我们已经在我们感兴趣的行上添加了注释。

svc.yml

apiVersion

:

 v1

kind

:

 Service

metadata

:

  name

:

 hello

-

svc

  labels

:

    app

:

 hello

-

world

spec

:

  type

:

 NodePort

  ports

:

  -

 port

:

 8080

    nodePort

:

 30001

    protocol

:

 TCP

  selector

:

    app

:

 hello

-

world

   #

 Label

 selector

    #

 Service

 is

 looking

 for

 Pods

 with

 the

 label

 `

app

=

hello

-

world

`

deploy.yml

apiVersion

:

 apps

/

v1

kind

:

 Deployment

metadata

:

  name

:

 hello

-

deploy

spec

:

  replicas

:

 10

  selector

:

    matchLabels

:

      app

:

 hello

-

world

  template

:

    metadata

:

      labels

:

        app

:

 hello

-

world

   #

 Pod

 labels

        #

 The

 label

 above

 matches

 what

 the

 svc

.

yml

 is

 looking

 for

    spec

:

      containers

:

      -

 name

:

 hello

-

ctr

        image

:

 nigelpoulton

/

k8sbook

:

latest

        ports

:

        -

 containerPort

:

 8080

在示例文件中,服务具有一个标签选择器(.spec.selector),其具有单个值app=hello-world。这是服务在查询匹配的 Pod 时寻找的标签。部署指定了具有相同app=hello-world标签的 Pod 模板(.spec.template.metadata.labels)。这意味着它部署的任何 Pod 都将具有app=hello-world标签。这两个属性松散地将服务与部署的 Pod 绑定在一起。

当部署和服务部署时,服务将选择所有 10 个 Pod 副本,并为它们提供稳定的网络端点并执行负载平衡。

服务和端点对象

随着 Pod 的出现和消失(扩展和缩减,故障,滚动更新等),Service 动态更新其健康匹配 Pod 的列表。它通过标签选择器和一个称为Endpoint对象的构造来实现这一点。

每个创建的 Service 都会自动获得一个关联的Endpoint对象。这个 Endpoint 对象只是一个动态列表,列出了集群上与 Service 的标签选择器匹配的所有健康 Pod。

它的工作原理是这样的…

Kubernetes 不断评估 Service 的标签选择器与集群中当前健康 Pod 列表的匹配情况。任何新的匹配选择器的 Pod 都会被添加到 Endpoint 对象中,任何消失的 Pod 都会被移除。这意味着 Endpoint 始终是最新的。当 Service 向 Pod 发送流量时,它会查询其 Endpoint 以获取最新的健康匹配 Pod 列表-这确保了 Service 随着 Pod 的出现和消失而保持最新。

Endpoint 对象有自己的 API 端点,Kubernetes 本地应用程序可以查询匹配 Pod 的最新列表(就像 Service 对象一样)。非本地的 Kubernetes 应用程序可以直接使用 Service 的稳定 IP(VIP)。

现在我们知道了 Service 工作原理的基础,让我们来看一些用例。

从集群内部访问服务

Kubernetes 支持几种类型的 Service。默认类型是ClusterIP

ClusterIP Service 执行以下操作。它为 Service 获取一个稳定的 IP 地址(ClusterIP)和端口,只能从集群内部访问。然后将它们注册到集群的 DNS 服务的名称下。

集群中的所有 Pod 都知道集群的 DNS 服务,这意味着所有 Pod 都能解析 Service 的名称。

让我们看一个简单的例子。

创建一个名为“hellcat-svc”的新 Service 将触发以下操作。Kubernetes 将使用集群的 DNS 服务注册名称“hellcat-svc”,以及一个 IP 地址和端口。名称、IP 和端口保证是长期稳定的,集群中的所有 Pod 都能将“hellcat-svc”解析为 Service 的 ClusterIP。

网络网络…只要一个 Pod(应用微服务)知道一个 Service 的名称,它就可以将其解析为其 ClusterIP 地址并连接到它。

这仅适用于集群中的 Pod 和其他对象,因为它需要访问集群的 DNS 服务。它在集群外部无法工作。

从集群外部访问

Kubernetes 还有另一种称为NodePort 服务的服务类型。这建立在 ClusterIP 之上,并允许从集群外部访问。

我们已经知道默认的服务类型是 ClusterIP,这会在集群的 DNS 中注册一个 DNS 名称、虚拟 IP 和端口。NodePort 服务通过添加另一个端口来扩展这一功能,该端口可用于从集群外部访问服务。这个额外的端口称为 NodePort。

以下示例代表一个 NodePort 服务:

  • 名称:hellcat-svc

  • ClusterIP:172.12.5.17

  • 端口:8080

  • NodePort:30050

这个服务可以通过前三个值(名称、ClusterIP、端口)之一直接从集群内部访问。也可以通过在端口30050上访问任何集群节点来从集群外部访问。

在最低级别,我们有集群中托管 Pod 的节点。然后我们创建一个服务,并使用标签将其与 Pod 关联起来。服务对象在集群中的每个节点上都有一个可靠的 NodePort 映射 - 每个节点上的 NodePort 都是相同的。这意味着来自集群外部的流量可以在集群中的任何节点上通过 NodePort 到达应用程序(Pod)。

图 6.6 显示了一个 NodePort 服务,其中 3 个 Pod 在集群中的每个节点上都在端口30050上对外开放。在第 1 步,外部客户端在端口30050上访问 Node2。在第 2 步,它被重定向到服务对象(即使 Node2 没有运行来自服务的 Pod,也会发生这种情况)。第 3 步显示服务有一个关联的 Endpoint 对象,其中包含一个始终保持最新的与标签选择器匹配的 Pod 列表。第 4 步显示客户端被引导到 Node1 上的 pod1。

图 6.6

图 6.6

服务也可以轻松地将客户端引导到 pod2 或 pod3。事实上,未来的请求可能会在 Pod 之间进行负载均衡。

还有其他类型的服务,比如负载均衡器服务。这些服务与云提供商(如 AWS、Azure 和 GCP)的负载均衡器集成。它们建立在 NodePort 服务的基础上(NodePort 服务又建立在 ClusterIP 服务的基础上),允许互联网上的客户端通过云的负载均衡器之一访问您的 Pod。

负载均衡服务非常容易设置。但是,它们只在您在受支持的云平台上运行 Kubernetes 集群时才起作用。例如,如果您的 Kubernetes 集群是本地集群,则无法利用 AWS 上的 ELB 负载均衡器。

服务发现

Kubernetes 以几种方式实现服务发现:

  • DNS(推荐)

  • 环境变量(绝对不推荐)

基于 DNS 的服务发现需要 DNS cluster-add-on - 这只是本地 Kubernetes DNS 服务的一个花哨的名称。如果您按照“安装 Kubernetes”章节中的安装方法进行安装,您已经拥有了这个服务。它在集群中实现了基于 Pod 的 DNS 服务,并配置所有 kubelet(节点)以用于 DNS。

DNS 插件不断监视 API 服务器以获取新的服务,并自动在 DNS 中注册它们。这意味着每个服务都有一个可以在整个集群中解析的 DNS 名称。

另一种服务发现的形式是通过环境变量。每个 Pod 都会得到一组环境变量,解析出集群中当前的每个服务。但是,这是一种备用方法,以防您的集群中没有使用 DNS。

环境变量的问题在于它们只在 Pod 创建时插入。这意味着 Pod 在创建后无法了解添加到集群中的新服务的方式 - 这远非理想!这就是为什么 DNS 是首选方法。

服务理论总结

服务主要提供 Pod 的稳定网络。它们还提供负载均衡和从集群外部访问的方式。它们使用标签和标签选择器动态与 Pod 相关联。

服务实践

我们将要动手实践并将理论付诸实践。

我们将使用 Kubernetes 服务来增强一个简单的单 Pod 应用程序。我们将展示两种方法:

  • 命令式方式(仅在紧急情况下使用)

  • 声明式方式

命令式方式

警告! 命令式方式不是Kubernetes 的方式!它引入了一种风险,即通过命令方式进行的更改永远不会出现在声明式清单中,使得清单变得陈旧。这会导致陈旧的清单被用来在以后的某个日期更新集群,无意中覆盖了通过命令方式进行的重要更改。

使用kubectl以声明方式部署以下部署(后续步骤将以命令方式完成)。该命令假定部署在名为deploy.yml的文件中,并具有以下内容。

apiVersion

:

 apps

/

v1

kind

:

 Deployment

metadata

:

  name

:

 web

-

deploy

spec

:

  replicas

:

 10

  selector

:

    matchLabels

:

      app

:

 hello

-

world

  template

:

    metadata

:

      labels

:

        app

:

 hello

-

world

    spec

:

      containers

:

      -

 name

:

 hello

-

ctr

        image

:

 nigelpoulton

/

k8sbook

:

latest

        ports

:

        -

 containerPort

:

 8080

$ kubectl apply -f deploy.yml
deployment "web-deploy"

 created

现在部署正在运行,是时候为其部署一个服务了。

使用以下kubectl命令创建一个新的服务,为先前步骤部署的 Pod 提供网络和负载平衡。

$ kubectl expose deployment web-deploy \

  --name=

hello-svc \

  --target-port=

8080

 \

  --type=

NodePort

service "hello-svc"

 exposed

让我们解释一下这个命令在做什么。kubectl expose是创建一个新的Service对象的命令方式。deployment web-deploy告诉 Kubernetes 暴露先前创建的名为web-deploy的部署。--name=hello-svc告诉 Kubernetes 我们要将此服务称为“hello-svc”,--target-port=8080告诉它应用程序正在侦听的端口(这不是我们将访问服务的整个集群 NodePort)。最后,--type=NodePort告诉 Kubernetes 我们需要一个服务的整个集群端口。

创建服务后,您可以使用kubectl describe svc hello-svc命令检查它。

$

 kubectl

 describe

 svc

 hello

-

svc

Name

:

               hello

-

svc

Namespace

:

          default

Labels

:

             app

=

hello

-

world

Annotations

:

        <

none

>

Selector

:

           app

=

hello

-

world

Type

:

               NodePort

IP

:

                 100.70

.

80.47

Port

:

               <

unset

>

 8080

/

TCP

NodePort

:

           <

unset

>

 30175

/

TCP

Endpoints

:

          100.96

.

1.10

:

8080

,

 100.96

.

1.11

:

8080

,

 +

 more

...

Session

 Affinity

:

   None

Events

:

             <

none

>

输出中一些有趣的值包括:

  • Selector 是 Pod 必须具有的标签列表,以便服务将流量发送到它们

  • IP 是服务的永久 ClusterIP(VIP)

  • Port是应用程序和服务侦听的端口

  • NodePort 是整个集群可以用来外部访问的端口

  • Endpoints 是当前与服务标签选择器匹配的健康 Pod 的动态列表。

现在我们知道了服务可访问的整个集群端口,我们可以打开一个网页浏览器并访问该应用程序。为了做到这一点,您需要知道集群中至少一个节点的 IP 地址,并且需要能够从浏览器访问它 - 例如,如果您通过互联网访问,则需要一个公共可路由的 IP。

图 6.7 显示了一个网页浏览器访问具有 IP 地址54.246.255.52的集群节点,该节点使用整个集群 NodePort30175

图 6.7

图 6.7

我们部署的应用程序是一个简单的 Web 应用程序。它构建为侦听端口 8080,并且我们已经配置了一个 Kubernetes Service,将每个集群节点上的端口30175映射回应用程序上的端口 8080。默认情况下,整个集群端口(NodePort 值)在 30,000 - 32,767 之间。

接下来,我们将看到如何以正确的方式进行相同的操作 - 声明式的方式!为了做到这一点,我们需要通过删除刚刚创建的服务来进行清理。我们可以使用kubectl delete svc命令来做到这一点

$ kubectl delete svc hello-svc
service "hello-svc"

 deleted

声明式方式

是时候按照正确的方式来做事了... Kubernetes 的方式!

服务清单文件

我们将使用以下服务清单文件来部署与上一节中部署的相同的服务。只是这一次我们将为整个集群端口指定一个值。

apiVersion

:

 v1

kind

:

 Service

metadata

:

  name

:

 hello

-

svc

  labels

:

    app

:

 hello

-

world

spec

:

  type

:

 NodePort

  ports

:

  -

 port

:

 8080

    nodePort

:

 30001

    protocol

:

 TCP

  selector

:

    app

:

 hello

-

world

让我们逐行解释一些内容。

服务是成熟的对象,并且在v1 API(.apiVersion)中完全定义。

.kind字段告诉 Kubernetes 将清单传递给服务控制器以部署为服务。

.metadata 部分定义了服务的名称和标签。这里的标签是服务本身的标签。它不是服务用来选择 Pod 的标签。

.spec 部分是我们实际定义服务的地方。在这个例子中,我们告诉 Kubernetes 部署一个NodePort服务(其他类型如ClusterIPLoadBalancer也存在),并将端口8080映射到集群中每个节点的端口30001。然后我们明确告诉它使用 TCP(默认)。

最后,.spec.selector 告诉服务将流量发送到集群中具有app=hello-world标签的所有 Pod。这意味着它将为具有该标签的所有 Pod 提供稳定的网络和负载均衡。

常见的服务类型

三种常见的ServiceTypes是:

  • ClusterIP. 这是默认选项,并在集群内部为服务提供稳定的 IP 地址。它不会使服务在集群外部可用。

  • NodePort. 这是建立在ClusterIP之上,并添加了一个集群范围的 TCP 或 UDP 端口。它使服务在该端口在集群外部可用。

  • LoadBalancer. 这是建立在NodePort之上,并与基于云的负载均衡器集成。

清单需要通过 POST 发送到 API 服务器。最简单的方法是使用kubectl apply来做到这一点。

$ kubectl apply -f svc.yml
service "hello-svc"

 created

这个命令告诉 Kubernetes 从名为svc.yml的文件部署一个新对象。-f标志让您告诉 Kubernetes 使用哪个清单文件。Kubernetes 知道根据清单中.kind字段的值来部署服务对象。

服务内省

现在服务已经部署,您可以使用通常的kubectl getkubectl describe命令来检查它。

$

 kubectl

 get

 svc

 hello

-

svc

NAME

        CLUSTER

-

IP

      EXTERNAL

-

IP

   PORT

(

S

)

         AGE

hello

-

svc

   100.70

.

40.2

     <

nodes

>

       8080

:

30001

/

TCP

  8s

$

 kubectl

 describe

 svc

 hello

-

svc

Name

:

               hello

-

svc

Namespace

:

          default

Labels

:

             app

=

hello

-

world

Annotations

:

        <

none

>

Selector

:

           app

=

hello

-

world

Type

:

               NodePort

IP

:

                 100.70

.

40.2

Port

:

               <

unset

>

 8080

/

TCP

NodePort

:

           <

unset

>

 30001

/

TCP

Endpoints

:

          100.96

.

1.10

:

8080

,

 100.96

.

1.11

:

8080

,

 +

 more

...

Session

 Affinity

:

   None

Events

:

             <

none

>

在前面的例子中,我们已将 Service 暴露为整个集群上端口为30001NodePort。这意味着我们可以将 Web 浏览器指向任何节点上的该端口并访问该服务。您需要使用可以访问的节点 IP,并确保任何防火墙和安全规则允许流量通过。

图 6.8 显示了一个 Web 浏览器通过集群节点的 IP 地址为54.246.255.52的集群范围端口30001访问应用程序。

图 6.8

图 6.8

端点对象

在本章的前面,我们说每个服务都有一个与服务同名的 Endpoint 对象。这个对象包含服务匹配的所有 Pod 的列表,并且随着 Pod 的出现和消失而动态更新。我们可以使用普通的kubectl命令查看 Endpoints。

在以下命令中,我们将 Endpoint 缩写为ep

$

 kubectl

 get

 ep

 hello

-

svc

NAME

        ENDPOINTS

                           AGE

hello

-

svc

   100.96

.

1.10

:

8080

,

 100.96

.

1.11

:

8080

  1

m

kubernetes

  172.20

.

32.78

:

443

$

 Kubectl

 describe

 ep

 hello

-

svc

Name

:

         hello

-

svc

Namespace

:

    default

Labels

:

       app

=

hello

-

world

Annotations

:

  <

none

>

Subsets

:

  Addresses

:

  100.96

.

1.10

,

100.96

.

1.11

,

100.96

.

1.12

...

  NotReadyAddresses

:

   <

none

>

  Ports

:

    Name

      Port

     Protocol

    ----

      ----

     --------

    <

unset

>

   8080

     TCP

Events

:

 <

none

>

部署服务的总结

与所有 Kubernetes 对象一样,部署和管理服务的首选方式是声明式的方式。利用标签使它们具有动态性。这意味着您可以部署新服务,这些服务将与集群中已经运行并正在使用的 Pod 和 Deployment 一起工作。每个服务都有自己的 Endpoint 对象,该对象维护与匹配的 Pod 的最新列表。

现实世界的例子

尽管我们到目前为止学到的一切都很酷和有趣,但重要的问题是:它如何带来价值?以及它如何保持业务运行并使其更具敏捷性和弹性?

让我们花一分钟来运行一个常见的现实世界的例子-更新应用程序。

我们都知道更新应用程序是生活中的一个事实-错误修复,新功能等。

图 6.9 显示了一个简单的应用程序部署在一个由 Deployment 管理的一堆 Pod 组成的 Kubernetes 集群上。作为其中的一部分,我们有一个 Service 选择了具有与app=biz1zone=prod匹配的标签的 Pod(注意 Pod 具有标签选择器中列出的两个标签)。应用程序正在运行。

图 6.9

图 6.9

假设我们需要推送一个新版本。但我们需要在不产生停机时间的情况下进行。

为此,我们可以像图 6.10 所示添加运行新版本应用程序的 Pod。

图 6.10

图 6.10

在幕后,更新后的Pods通过它们自己的 ReplicaSet 部署,并被标记,以便它们与现有的标签选择器匹配。服务现在正在跨应用程序的两个版本version=4.1version=4.2)进行负载均衡请求。

这是因为服务的标签选择器正在不断地进行评估,并且它的端点对象和 ClusterIP 正在不断地更新以匹配新的 Pods。

一旦您满意更新后的版本,强制所有流量使用它就像更新服务的标签选择器以包含标签version=4.2一样简单。突然之间,旧版本不再匹配,服务只转发流量到新版本(图 6.11)。

图 6.11

图 6.11

然而,旧版本仍然存在 - 我们只是不再向其发送流量。这意味着如果我们遇到新版本的问题,我们可以通过简单地将服务的标签选择器更改为包含version=4.1而不是version=4.2来切换回先前的版本。参见图 6.12。

图 6.12

图 6.12

现在每个人都在使用旧版本。

这种功能可以用于各种事情 - 蓝绿部署,金丝雀发布,你想到的都可以。如此简单,却如此强大!

使用以下命令清理实验室。这些命令将删除示例中使用的部署和服务。

$ kubectl delete -f deploy.yml
$ kubectl delete -f svc.yml

章节总结

在本章中,我们了解到服务为部署在 Kubernetes 上的应用程序带来了稳定可靠的网络连接。它们还执行负载均衡,并允许我们将应用程序的元素暴露给外部世界(超出 Kubernetes 集群之外)。

服务是 Kubernetes API 中的一流对象,并可以在标准 YAML 清单文件中定义。它们使用标签选择器动态匹配 Pods,并且最好的工作方式是声明性地与它们一起工作。

第八章:其他重要的 Kubernetes 内容

Kubernetes 还有很多内容无法在一本书中涵盖。如果我们尝试,将填满整整一套书!

在本章中,我们将简要提及 Kubernetes 的以下领域,这将带您进入下一个级别:

  • DaemonSets

  • StatefulSets

  • 作业

  • 定时作业

  • 自动缩放

  • RBAC

  • 存储

  • Helm

其中许多内容将成为未来版本书籍中的独立章节。现在,让我们先尝尝每个领域。

显然,还有更多内容,但就像我们已经说过的 - 它可以填满整整一套书!

DaemonSets

DaemonSets 是apps API 组中的一种资源,它们管理 Pods。它们的用例是当您需要在集群中的每个节点上运行特定 Pod 的副本时。一些例子包括;监控 Pods日志 Pods,您需要在集群中的每个节点上运行它们。

正如您所期望的,它实现了一个控制器和一个监视循环。这意味着您可以动态地向集群中添加和删除节点,而 DaemonSet 将确保您始终在每个节点上有一个 Pod 副本。

以下命令显示了kube-system命名空间中存在的两个 DaemonSets,在新安装的 3 节点集群上。

输出被修剪以适应页面。

kubectl get ds -n kube-system
NAME         DESIRED  CURRENT  READY  NODE SELECTOR
kube-proxy   3        3        3      beta.kubernetes.io/arch=amd64
weave-net    3        3        3      <none>

请注意,每个 DaemonSet 的期望状态为 3 个副本。您不需要在 DaemonSet YAML 文件中指定这一点,因为它是根据集群中的节点数自动暗示的。

DaemonSets 在apps/v1 API 组中是稳定的,并且可以通过通常的kubectl getkubectl describe命令等进行管理。如果您已经了解 Pods 和部署,您会发现 DaemonSets 非常简单。

StatefulSets

StatefulSets 是apps/v1 API 组中的稳定资源。它们的用例是有状态的 Pods - 即不打算是短暂的 Pods。

微服务应用程序的有状态组件通常是最难实现的,而像 Kubernetes 这样的平台在处理它们的功能方面进展缓慢。StatefulSets 是改进这一点的一步。

将它们视为类似于部署是有用的。例如,我们在 YAML 文件中定义它们,然后将其作为期望状态POST到 API 服务器。控制器在集群上实现工作,后台监视循环确保当前状态与期望状态匹配。然而,StatefulSet 和 Deployment 之间有一个主要区别 - 通过 StatefulSet 部署的 Pod 是不可互换的。这意味着当 StatefulSet 管理的 Pod 失败时,会被具有相同 ID 和 IP 等的另一个 Pod 替换。

StatefulSets 的潜在用例是应用程序中维护状态的任何服务。这些可以包括:

  • 需要访问特定命名卷的 Pod

  • 需要持久网络标识的 Pod

  • 必须按特定顺序上线 Pod 的情况

StatefulSet 保证所有这些在 Pod 失败和后续重新调度操作中都会被维护。

由于有状态应用程序的更复杂性,StatefulSets 的配置可能会很复杂。

作业和 CronJobs

作业,又称批处理作业,是batch/v1 API 组中的稳定资源。当您需要运行特定数量的特定 Pod,并且需要保证它们都能成功完成时,它们就会很有用。

值得注意的一些微妙之处:

  1. 作业没有期望状态的概念

  2. 作业中的 Pod 是短暂的

这两个概念将作业与其他对象(如部署、守护进程集和 StatefulSets)分开。而那些对象会持续运行指定数量的某个 Pod,作业管理指定数量的某个 Pod,并确保它们完成并成功退出。

作业对象实现了通常的控制器和监视循环。如果作业对象生成的 Pod 失败,作业将在其位置创建另一个。作业本身直到所需数量的 Pod 成功完成才会完成。

用例包括典型的批处理工作负载。

有趣的是,作业即使只需要运行一个 Pod 完成也是有用的。基本上,每当您需要运行一个或多个短暂的 Pod,并且需要保证它们成功完成时,作业对象就是您的朋友!

CronJobs只是根据时间表运行的作业

自动缩放

部署章节向我们展示了如何手动扩展 Pod 副本的数量。然而,手动扩展一组 Pod 并不会扩展(原谅双关语)。例如,如果您的应用程序在凌晨 4:20 需求激增,如果您需要呼叫操作员,然后登录到集群并手动增加副本数量,这远非理想。如果您需要扩展集群中的节点数量,情况也是一样。

考虑到这些挑战,Kubernetes 提供了几种自动扩展技术。

水平 Pod 自动缩放器(HPA)根据需求动态增加和减少部署中的Pod数量。

集群自动缩放器(CA)根据需求动态增加和减少集群中的节点数量。

垂直 Pod 自动缩放器(VPA)试图调整 Pod 的大小。目前是一个alpha产品。

水平 Pod 自动缩放器(HPA)

HPA 是autoscaling/v1 API 组中的稳定资源,它的工作是根据观察到的 CPU 指标来扩展部署中副本的数量。在撰写本文时,v2 API 正在开发中,将允许根据不仅仅是 CPU 来进行扩展。

它的工作方式是这样的……您定义一个使用 Pod 资源请求的部署 - 其中 Pod 中的每个容器请求一定数量的 CPU。您将其部署到集群中。您还创建一个目标该部署的 HPA 对象,并设置一个规则,比如:如果该部署中的任何 Pod 使用超过其请求的 CPU 的 60%,则增加一个额外的 Pod。

一旦部署和 HPA 部署到集群中,扩展操作就会变得自动化。

值得注意的一点是,HPA 会更新目标部署的.spec.replicas字段。虽然此更新记录在集群存储中的部署对象中,但可能会导致您在外部版本控制系统中的部署 YAML 文件与当前在集群中观察到的内容不同步的情况。

集群自动缩放器(CA)

CA 的目标是调整您的 Kubernetes 集群大小。在高层次上,它们根据需求增加和减少集群中的节点数量。

稍微深入一点……CA 定期检查 Kubernetes 中由于节点资源不足而处于挂起状态的 Pod。如果发现任何问题,它会向集群添加节点,以便可以安排挂起的 Pod。

这需要与集群的基础基础设施平台集成 - 一个公共 API,允许 Kubernetes 添加和删除节点。主要的云平台实现了具有不同支持级别的集群自动缩放器。查看您的云提供商文档以获取最新的支持信息。

基于角色的访问控制(RBAC)

Kubernetes 实现了最小特权 RBAC 子系统。启用后,它会锁定集群,并允许您基于特定用户和组授予权限。

该模型基于三个主要组件:

  • 主体

  • 操作

  • 资源

主体是用户和组,它们必须在 Kubernetes 之外进行管理。操作是主体被允许执行的操作(创建、列出、删除等)。资源是集群上的对象,如 Pod。将这三者结合起来,就形成了一个 RBAC 规则。例如,Abi(主体)被允许创建(操作)Pods(资源)。

自 Kubernetes 1.8 以来,RBAC 一直稳定(v1),并利用在authorization.rbac.k8s.io API 组中定义的两个对象。这两个对象是RolesRoleBindingsRole是您定义要允许的资源和操作的地方,而RoleBinding将其与主体连接起来。

存储

存储是大多数生产应用程序的重要组成部分。幸运的是,Kubernetes 拥有全面的存储子系统。

该模型的高级架构包括存储提供程序、插件接口和 Kubernetes 持久卷子系统。

存储提供程序负责创建实际的存储,可以是企业级存储阵列和云存储服务等。将它们连接到 Kubernetes 的首选方式是通过容器存储接口(CSI)插件。Kubernetes 持久卷子系统将存储暴露给集群,并提供了消费方式。参见图 7.1。

图 7.1

图 7.1

存储提供程序的示例包括:企业级存储阵列,如 EMC 和 NetApp,以及云存储服务,如 AWS Elastic Block Store(EBS)。这些通过 CSI 插件连接到 Kubernetes,Kubernetes 提供了允许 Pod 访问和使用存储的对象。

存储资源通过PersistentVolume(PV)对象在 Kubernetes 中表示,Pod 可以使用PersistentVolumeClaim(PVC)对象访问它们。这两者都是核心 API 组的v1中的资源。

StorageClass对象允许动态创建 PV,并位于storage.k8s.io/v1 API 组中。

Helm

Helm 是事实上的 Kubernetes 包管理器,极大地简化了 Kubernetes 应用的安装和管理。

Helm 于 2018 年被接纳为云原生计算基金会(CNCF)的官方顶级项目。因此,它与 Kubernetes、Prometheus、gRPC 等并列。

作为包管理器,它就像 Ubuntu 的apt和 Mac 的brew。在 Helm 的情况下,它隐藏了诸如部署、Pod 和持久卷之类的复杂性,放在一个叫做chart的构造中。把 chart 想象成 Helm 版的 YUM、DEB 或 homebrew 包。因此,您可以通过应用的 Helm chart 安装、更新和删除 Kubernetes 应用。

您还可以与社区分享您的 chart,并重复使用现有的 chart。

章节总结

本章的目的是让您了解一些其他重要的 Kubernetes 技术,以便您知道下一步可能要去哪里。但是,Kubernetes 非常庞大,我们还没有涵盖所有内容。

未来的计划是将其中一些主题作为书的未来版本中的独立章节。如果您等不及,我已经在 acloud.guru 的Kubernetes 深入探讨视频课程中涵盖了自动扩展RBAC存储

https://acloud.guru/learn/kubernetes-deep-dive

读累了记得休息一会哦~

公众号:古德猫宁李

  • 电子书搜索下载

  • 书单分享

  • 书友学习交流

网站:沉金书屋 https://www.chenjin5.com

  • 电子书搜索下载

  • 电子书打包资源分享

  • 学习资源分享

读累了记得休息一会哦~

公众号:古德猫宁李

  • 电子书搜索下载

  • 书单分享

  • 书友学习交流

网站:沉金书屋 https://www.chenjin5.com

  • 电子书搜索下载

  • 电子书打包资源分享

  • 学习资源分享

第九章:接下来做什么

有很多方法可以让你的 Kubernetes 之旅更上一层楼,而且大多数方法都很容易!

熟能生巧

亲自动手是无法替代的。幸运的是,现在从未有过如此容易建立一个 Kubernetes 游乐场,在那里你可以玩到你成为世界权威!

我非常喜欢 Play with Kubernetes(https://labs.play-with-k8s.com/)。我喜欢 Docker Desktop,并且我经常在 Google 的 GKE 上建立测试集群。

还有其他选择,它们都比以前简单多了!我记得我曾经为了我的 Windows NT 的 MSCE 考试而苦苦学习,每次我搞垮了实验室,就要花费无数个小时从光盘安装重建 NT 域。现在真的没有理由不动手了!

更多书籍

我有一本关于 Docker 的书,得到了极好的评价。Docker 和容器对于 Kubernetes 至关重要,所以如果你需要了解 Docker,去看看吧——它叫做 Docker 深入挖掘,你可以在亚马逊和 Leanpub 上买到。

视频培训

如果你喜欢这本书,你会喜欢我的视频课程!

我在 Pluralsight 上有一个入门 Kubernetes课程,还在 A Cloud Guru 上有一个Kubernetes 深入课程。如果你已经读完了所有的书,你可能想直接去深入挖掘课程。

https://acloud.guru/learn/kubernetes-deep-dive

我在 Pluralsight 上还有很多 Docker 课程。

如果你不是 Pluralsight 或 A Cloud Guru 的会员,我建议你成为其中一个!是的,它们是收费的,但它们可能是你职业生涯中做的最好的事情之一!每个平台的月度订阅都可以让你访问该平台图书馆中的每门课程——从开发人员到 IT 运维的所有课程。如果你不确定是否要花钱,通常会有一个免费试用期,你可以在有限的时间内免费访问。

活动和聚会

你应该参加 KubeCon 和你当地的 Kubernetes 聚会。那里有很多优秀的人,也是学习的好地方!

就这样了。继续学习吧!

反馈

谢谢你读我的书。希望你喜欢它。

现在是我请求一个忠告的时候(这是我们在英国拼写的方式)……

写一本书需要荒谬的时间和奉献精神。所以,我真的很感激在亚马逊上快速写一篇评论。只需要几分钟,如果你在其他地方买了这本书,你甚至可以在亚马逊上发表评论!欢迎各种类型的评论!

另外……随时可以在Twitter上找我。

就是这样。祝你驾驭职业生涯一帆风顺!

posted @ 2024-05-20 12:00  绝不原创的飞龙  阅读(11)  评论(0编辑  收藏  举报