第 6 章:走向生产
本章内容概览:
- 部署微服务到 Kubernetes 集群
- 在本地 Kubernetes 实例上进行开发、测试和学习
- 通过 Azure 门户创建托管 Kubernetes 集群
本章是全书中最激动人心的部分之一!我们将在接下来的三章详细介绍部署应用到生产环境所需的三项关键技术。这几章或许是本书中最具挑战性的,但只要你遵循步骤操作,实际部署应用到生产环境将大大增强你的实战能力。
本章将引导你部署首个微服务至 Kubernetes。你将会发现,在本地 Kubernetes 实例上进行试验和学习是多么便捷。
接下来,我们将通过 Azure 门户创建一个托管的集群,这是进入生产级 Kubernetes 集群的最简单方法。在后续章节中,你还将学习如何使用 Terraform 通过代码来搭建 Kubernetes 集群,以及如何利用 GitHub Actions 实现部署流程的自动化。
6.1 新工具介绍
本章将详细介绍 Kubernetes、Kubernetes 命令行工具(kubectl)和 Azure 命令行工具(Azure CLI)。Kubernetes 是本书封面的关键词,其重要性毋庸置疑。kubectl 是我们从本地计算机与 Kubernetes 集群进行交互的主要工具。而 Azure CLI 则是一个极为实用的工具,可以帮助我们轻松地将 kubectl 配置至 Azure 上的 Kubernetes 集群。通过这些工具,我们能够有效部署微服务并管理整个集群。
表 6.1:第 6 章介绍的新工具
| 工具 | 版本 | 用途 |
|---|---|---|
| Kubernetes | 1.25.12 | 托管生产环境中微服务的平台。 |
| Kubectl | 1.27.2 | 与 Kubernetes 集群交互的命令行工具。 |
| Azure CLI | 2.51.0 | 配置 kubectl 以连接到 Azure 上的 Kubernetes 集群的工具。 |
6.2 代码获取
为了跟进本章内容,请下载或克隆相关代码。
- 下载代码压缩文件请访问: http://mng.bz/467D
- 使用 Git 克隆代码库的命令如下:
git clone https://github.com/bootstrapping-microservices-2nd-edition/chapter-6.git
如需安装和使用 Git 的详细帮助,请参考第 2 章。遇到代码问题可在 GitHub 仓库中提出。
6.3 进入生产环境
将应用部署到面向客户的生产环境的时刻终于到来。所谓“进入生产环境”,意味着应用被部署至一个用户可见并可互动的环境。尽早在开发过程中进入生产环境是我所推崇的一种做法。在应用规模较小之际开始部署,不仅易于管理,而且是获取用户反馈、调整需求和增强功能的最佳时机。
随着应用的扩展,部署到生产环境的复杂性会逐步提高,因此,早期部署是一种明智的策略,它能让应用自然而然地发展成一个更为庞大且复杂的系统。
6.4 在 Kubernetes 上托管微服务
本章末尾,我们将演示如何将单一微服务部署至 Kubernetes。通过一个示例微服务,你将学习在 Kubernetes 上进行部署的步骤。尽管整个应用尚未上线,但本章将帮助你从部署单个微服务开始,逐步掌握 Kubernetes 的使用方法。在第 10 章,我们将全面讨论如何将完整的 FlixTube 应用部署至 Kubernetes。
本章我们将以循序渐进的方式,逐步构建我们的应用。虽然最终我们的集群将托管多个微服务,但一切始于这里。我们将回顾第 3 章的内容,即首次将视频流微服务发布至容器仓库的过程。
Kubernetes 最初由 Google 开发,现由 Cloud Native Computing Foundation(CNCF)管理,是一个得到广泛支持的行业组织。Kubernetes 不仅仅是一个容器编排平台,它还是一个极其重要的微服务平台。
图 6.1 和 6.2 将展示我们本章的主要任务。首先,我们将使用 Docker Desktop 内置的本地 Kubernetes 实例(见图 6.1),部署我们的视频流微服务。利用这个本地实例学习 Kubernetes 是一个良好的开始,因为它简单且易于操作。你可能已经在电脑上安装了 Docker Desktop,只需在其设置中启用 Kubernetes 功能即可。

随着你对 Kubernetes 的熟悉程度提高,我们将在 Microsoft Azure 上创建一个托管的 Kubernetes 集群(见图 6.2),并将我们的视频流微服务部署到那里。

是的,到本章的后半部分,你将会创建你自己的 Kubernetes 集群!这听起来可能很复杂,但实际上非常简单;通过几次点击 Azure UI,你可以在几分钟内拥有一个运行中的集群。在下一章,我们将详细讨论通过代码创建集群的更复杂的任务。
6.4.1 为何选择 Kubernetes?
选择采用 Kubernetes 的原因有很多,其最明显的优势之一便是避免对单一供应商的依赖。尽管主要的云服务提供商都提供各自的容器编排服务,并且这些服务本身品质优良,但它们同样提供托管 Kubernetes 服务。既然有了这种选择,我们为何还需依赖特定供应商的专属服务呢?使用 Kubernetes 使我们的应用能够在几乎任何云平台上运行,实现真正的云端迁移灵活性。
掌握 Kubernetes 的基础知识是有益的,因为这些技能具有很强的可迁移性。虽然本书主要讨论的是在 Azure 上部署 Kubernetes 集群,但你完全可以将所学的 Kubernetes 技能应用于任何你选择的云平台。
此外,Kubernetes 正快速成为分布式应用程序的托管标准。我们可以利用它来托管各类分布式应用,不限于微服务。
尽管 Kubernetes 的复杂性众所周知,尤其是当你需要在自己的数据中心直接管理它或深入其专业领域时。幸运的是,对于大多数人来说,通过云平台构建托管的 Kubernetes 集群要简单得多;事实上,在像 Azure 这样的平台上,我们可以通过几次点击通过图形用户界面轻松创建集群。自从本书第一版发布以来,Kubernetes 已经开始与 Docker Desktop 集成,使学习 Kubernetes 比以往任何时候都更为简单。因此,如果你已经安装了 Docker Desktop(从第 3 章开始使用),你应该已经准备好开始使用 Kubernetes(尽管你需要在 Docker Desktop 设置中启用它)。
Kubernetes 起源于 Google 的丰富经验,并后由社区接管和发展。这意味着你可以参与到 Kubernetes 代码的开发中去——如果你有兴趣深入探索这个领域的话!
Kubernetes 允许我们构建在多方面可扩展的应用程序,这将在第 11 章和第 12 章中进行讨论。在本章,你将学习如何将单个微服务部署到生产级 Kubernetes 集群。
最重要的是,Kubernetes 拥有可自动化的 API,这使我们能在第 8 章中构建自动化的持续部署流程。随着 Kubernetes 成为微服务的行业标准,这一趋势预计将持续。它得到了广泛的支持,并且拥有强大的社区和庞大的工具生态系统。
Kubernetes 是一种通用计算平台,得到了所有主要云服务提供商的支持。无论我们的应用最终部署在何处,我们都可以携带 Kubernetes 的优势。Kubernetes 是开源的,你可以在其 GitHub 页面 https://github.com/kubernetes/kubernetes 上查看源代码。
6.4.2 Pod、节点和容器
Kubernetes 集群通常包括多个被称为 节点 的计算单元。在我们的案例中,每个节点都是一台虚拟机(VM),尽管你也可以在物理硬件上运行 Kubernetes。我们可以根据需要向集群添加更多节点,从而提升应用的计算能力。每个节点都能托管多个 Pod(Pod 是 Kubernetes 中的基本计算单元)。
图 6.3 展示了一个典型的节点和 Pod 的配置。虽然图中的集群由三台虚拟机支持,并包含三个节点,但我们在本章中创建的集群将只有一个节点,因为我们的简单应用不需要更多的计算资源。此外,这还意味着我们只需要为所需的虚拟机支付费用。不过,扩展到更多节点是非常简单的,你将在第 12 章看到如何操作。

如图 6.4 所示,每个 Pod 可以托管多个容器。这为实现许多有趣的架构模式提供了基础,如著名的代理和身份验证的 Sidecar 模式。在本书中,我们将保持架构的简单性:每个 Pod 通常只托管一个容器或微服务。为简化理解,你可以将 Pod 和容器视为同一概念,尽管这在技术上不完全准确,但鉴于我们的用例较为简单,这种理解是合理的。

6.4.3 Pod、部署和服务
虽然我们可以简单地将微服务作为 Pod 单独部署到集群中,这种方法对于大多数 Kubernetes 教程来说是一个常见的起点。然而,单独部署 Pod 在生产环境中通常不足以提供足够的支持。当微服务在 Pod 中出现故障或挂起时,如果只使用 Pod,我们没有便捷的方式来监控微服务的状态。
因此,本书将直接引入使用 Kubernetes“部署”(Deployment)来管理生产环境中微服务的概念。Kubernetes 部署会持续监视 Pod,如果检测到微服务崩溃或挂起,它会自动重启微服务的新实例。

通过图 6.5,你可以看到我们的第一个微服务是如何在 Kubernetes 上运行的。注意,微服务由部署管理,并且通过服务为 Pod 创建了 DNS 记录。Pod、部署和服务是 Kubernetes 中的核心概念,我们需要理解这些概念以便在生产环境中有效地实现我们的微服务。
在本书中,我们将从简单入手:运行一个微服务,由一个 Pod 托管,通过 Kubernetes 的部署管理,并通过 Kubernetes 服务进行暴露。然而,正如图 6.6 所示,我们未来可能探索的方向是实现更广泛的可扩展性和冗余性。

通过增加 Pod 的数量,我们能够实现冗余和负载均衡。Kubernetes 部署确保我们的微服务的多个副本稳定运行。如果任何副本出现故障或挂起,部署将自动启动新的微服务副本来替换失败的副本。我们将在第 11 章和第 12 章中更详细地探讨扩展和冗余的话题。
6.5 启用你的本地 Kubernetes 实例
自本书第一版以来,Kubernetes 现已与 Docker Desktop 集成是一大改进,因此你只需简单地启用它即可。现在,你可以在本地 Kubernetes 实例上进行实验和学习,无需额外安装(假设你从第 3 章开始已经安装了 Docker Desktop)或投入任何配置或管理时间。这是学习 Kubernetes 的最佳起点,因为你可以在自己的计算机上免费开始使用它,而且不需要担心认证问题。
图 6.7 展示了如何启用 Docker Desktop 自带的本地 Kubernetes 实例。打开 Docker Desktop,点击顶部的设置按钮,选择 Kubernetes 标签,勾选启用 Kubernetes,然后点击应用并重启。启用 Kubernetes 时,系统可能需要安装当前版本的 Kubernetes,因此可能需要几分钟时间才能准备就绪。

如图 6.8 所示,在启用本地 Kubernetes 实例后,将出现一个重置 Kubernetes 集群的选项。使用此按钮是清理本地集群的最快方法,适用于完成一段实验或学习后。
此按钮可快速清除你在集群中部署的任何内容,为你的下一个会话提供一个全新的集群环境。如果你的 Kubernetes 实例响应缓慢或似乎已崩溃,或者你需要更新 Kubernetes 版本(如果你很久以前安装了 Docker Desktop,这可能是必要的),重置 Kubernetes 集群按钮也是解决问题的最佳途径。只需返回设置页面并点击重置 Kubernetes 集群按钮即可。
当你不再需要使用本地 Kubernetes 实例时,建议返回 Docker Desktop 设置并禁用 Kubernetes。这样做可以避免它持续运行,特别是在性能较低的计算机上,因为这会消耗系统资源(以及你的笔记本电池)。

注意 要了解更多关于 Docker Desktop 下运行的 Kubernetes 的信息,请参阅它们的文档: https://docs.docker.com/desktop/kubernetes/ 。
6.6 安装 Kubernetes 命令行工具
为了与我们的 Kubernetes 集群互动并将微服务部署到其中,我们需要使用 Kubernetes 命令行工具,称为 kubectl。如果你好奇它的发音,kubectl 可以读作“kube-cuddle”或“kube-CTL”,但常见的读法是“kube-control”。
幸运的是,kubectl 通常会随 Docker Desktop 一起提供,所以如果你已经启用了 Kubernetes,你应该已经安装了它。为了使用它,你可能需要在 Docker Desktop 设置中启用 Kubernetes,正如我们在前一节中所操作的。
如果你在 Linux 上工作,需要注意的是 Docker Desktop 不会在 Linux 版本中捆绑 kubectl。在这种情况下,你需要根据 Kubernetes 官方文档的指示来安装 kubectl:
http://mng.bz/QR5R
。
要检查你是否已正确安装并可以访问 kubectl,请运行以下命令:
kubectl version
如果希望输出更加简洁,你可以添加 --short 参数:
kubectl version --short
命令的输出应类似于以下内容(已简化以便阅读):
Client Version: v1.27.2
Kustomize Version: v5.0.1
Server Version: v1.25.12-eks-2d98532
从输出中,我们可以看到正在使用的 kubectl 客户端版本(v1.27.2)和 Kubernetes 服务器版本(v1.25.12)。
默认情况下,当你在 Docker Desktop 中启用 Kubernetes 时(如前一节所述),kubectl 应自动连接到它。然而,如果你以前安装或配置过 kubectl,或曾连接到其他 Kubernetes 集群,现在可能连接的不是你的本地 Kubernetes 实例。如果遇到此情况,你可能会看到以下连接错误:
Unable to connect to the server: dial tcp: lookup <some cluster name> on <resolver IP>: no such host
如果遇到此类错误,请不要担心;我们很快就会介绍如何确保你连接到正确的 Kubernetes 集群。这一步是管理 Kubernetes 实例的基础,无论是本地还是云端,确保你可以通过 kubectl 顺畅管理是关键。
6.7 项目结构详解
在我们尝试将微服务部署到 Kubernetes 之前,让我们先了解一下微服务项目的结构以及它与 Kubernetes 部署的关系。图 6.9 显示了第 6 章示例 1 的项目结构。目前为止,这种结构对你来说应该已经很熟悉了:包括 JavaScript 的源代码(index.js)、Node.js 项目文件(package.json,第 2 章已经介绍过)以及用于生产环境的 Dockerfile(Dockerfile-prod,第 3 章介绍过)。
正如第 3 章所讨论的,我们将视频文件直接嵌入到 Docker 镜像中。虽然这在生产环境中并不是最佳实践,但为了简化学习过程,我们采取了这种做法。进入第 10 章,你将看到实际的 FlixTube 应用是如何使用云存储服务存储视频文件和使用 MongoDB 数据库存储元数据的(这在第 4 章中已经设置)。
此外,图 6.9 还引入了一个新的元素——deploy.yaml 文件,该文件定义了微服务在 Kubernetes 上的部署方式。我们将在后面详细讨论这个文件。

6.8 部署到本地 Kubernetes 实例
尽管我们的主要目标是将微服务部署到云端 Kubernetes 集群,目前我们还没有讨论如何在云端创建集群。这将在后续章节中详细介绍。
作为开始,我们首先尝试将视频流微服务部署到本地 Kubernetes 实例。由于我们已经进行了必要的设置,所以无需进行额外的安装;我们可以直接开始部署。
6.8.1 构建微服务镜像
在部署微服务之前,我们需要先构建其镜像。尽管我们在第 3 章已经进行过此步骤,但让我们再次复习一遍。使用第 6 章的代码库中的示例 1 来构建这个镜像。
打开终端,按照第 6.2 节的指示克隆代码库,切换到示例 1 的目录,然后开始构建镜像:
cd chapter-6/example-1
docker build -t video-streaming:1 --file Dockerfile-prod .
我们将镜像标记为 video-streaming:1。这里的版本号位于冒号之后,从版本 1 开始,标记着视频流微服务的首次部署。未来每次代码更新后,应递增新部署的版本号。
注意 有关 Docker 构建命令的更详细解释,请参阅第 3 章 3.8 节。
6.8.2 暂时无需容器仓库
回想一下第 3 章中我们首次发布微服务时的步骤,我们使用了 Docker tag 命令为镜像打上标签,随后通过 Docker push 命令将其推送到私有容器仓库。然而,目前我们不需要进行标记或推送操作就可以将镜像部署到本地 Kubernetes 实例。因为 Kubernetes 在我们的电脑上本地运行,它可以直接访问我们本地构建的 Docker 镜像,无需通过容器仓库来共享镜像。这意味着我们在开发机上构建的任何镜像都已准备就绪,可以直接部署到本地 Kubernetes 实例。
随着本章后续内容的展开,当我们开始使用云中的 Kubernetes 集群时,我们将需要先将镜像推送到容器仓库再进行部署。但现在,由于使用的是本地集群,这一步骤尚未必需。这也是为什么在本地 Kubernetes 实例上学习和实验比直接上手云托管集群要简单和方便得多的原因。
6.8.3 创建部署到本地 Kubernetes 实例的配置
现在让我们首次深入了解 Kubernetes 部署配置文件。清单 6.1 展示了示例 1(chapter-6/example-1/scripts/deploy.yaml)中的 deploy.yaml 文件,我们之前在图 6.9 中见到过这个文件。此配置文件将用于创建微服务的部署、服务和 pod 结构,这些结构之前已在图 6.5 中展示。
值得一提的是,脚本目录仅是我用来存放项目部署脚本的文件夹名,你可以根据自己的偏好来命名这个目录。
清单 6.1 部署我们的微服务到 Kubernetes
apiVersion: apps/v1
kind: Deployment # 创建一个 Kubernetes 部署,维持我们的微服务运行(如果它崩溃会自动重启)
metadata:
name: video-streaming # 为部署设置一个名称
spec:
replicas: 1 # 此部署应只维持一个微服务副本运行。你可以增加此数值,以提升处理能力(应对更多请求)或增强冗余(提高容错能力)。
selector:
matchLabels:
app: video-streaming
template: # 定义托管我们微服务的 pod 的模板
metadata:
labels:
app: video-streaming
spec:
containers:
- name: video-streaming
image: video-streaming:1 # 指定使用 video-streaming 镜像(版本 1)来实例化此微服务的容器
imagePullPolicy: Never # 由于我们在本地部署,不需要从容器仓库拉取镜像。
env:
- name: PORT
value: "4000" # 设置微服务的端口为 4000
---
apiVersion: v1
kind: Service # 配置文件的两大部分之一
metadata:
name: video-streaming # 为服务设置一个名称
spec:
selector:
app: video-streaming
type: NodePort # 创建一个 NodePort 服务,从本地暴露微服务端口,以便我们可以发起 HTTP 请求
ports:
- protocol: TCP
port: 80
targetPort: 4000
nodePort: 30000 # 将容器内的端口 4000 映射到主机的端口 30000 上。这样我们就能从开发机发起 HTTP 请求到微服务。
清单 6.1 中的 YAML 配置分为两大部分,通过三个短划线(—)进行分隔。第一部分创建一个 Kubernetes 部署,它负责保持我们的微服务运行(如果微服务崩溃则自动重启)。
第二部分创建一个 Kubernetes 服务,通过 DNS 将我们的微服务暴露以接收 HTTP 请求。你可以选择将这两部分配置放在同一文件中,也可以分别存放在不同的文件中。但把它们放在一起方便管理,因为它们共同构成了单个微服务的完整配置。
注意在配置的第一部分中,我们指定了 pod 的模板。部署会使用这个模板来实例化 pod 和其容器,从而运行我们的微服务。每当微服务出现故障或停止响应时,部署都会使用这个模板来替换它。我们使用的是之前标记为 video-streaming:1 的镜像,并包括了版本号。当你构建新版本的微服务镜像时,你需要递增这个版本号并更新清单 6.1 中的配置以匹配新版本(这可能听起来有些繁琐,但在第 8 章我们将讨论如何模板化配置以自动插入新的版本号)。
Deployment、service 和 pod 通过标签相互关联。在清单 6.1 中,我们使用了 label、matchLabels 和 selector 将配置的各个部分通过 app 标签设置为 video-streaming 来联系起来。这里的 app 标签或 video-streaming 名称并没有特殊含义,你可以自定义这些标签。

在清单的末尾,你会注意到服务的类型被设置为 NodePort。这是为了从集群外部访问服务(以及我们的微服务)最简单的方法之一。在这种情况下,它是一个本地 Kubernetes 实例,所以我们实际上是在讨论如何从我们的本地计算机访问服务(和微服务)。
Kubernetes 允许我们选择一个位于 30000 到 32767 范围内的端口,如果我们不指定特定端口,它将随机选择一个。在清单 6.1 中,我们选择了 30000 端口来访问我们的微服务——这只是在允许范围内的第一个端口。如果你发现 30000 端口有问题(比如在你的计算机上不可用),可以选择一个更高的端口号,或者简单地去掉 nodePort:30000 这一行让系统为你自动选择一个端口。
注意 更多关于 NodePort 配置的信息可以在 Kubernetes 文档中找到: http://mng.bz/XqX1 。
稍后,当我们开始使用托管于云的 Kubernetes 集群时,我们将需要更加谨慎地将我们的微服务暴露给外部世界,因为这可能会使我们面临外部的攻击和滥用风险。但现在这不是问题,因为我们使用的是本地计算机上的 Kubernetes 集群,而这个集群并没有对外公开。
6.8.4 配置 kubectl 连接到本地 Kubernetes
在部署之前,确保 kubectl 正确连接到了本地 Kubernetes 实例。如果你是 Kubernetes 新手,并且已在第 6.5 节中启用了 Docker Desktop 的 Kubernetes,那么它通常会自动配置好连接。
可以通过以下命令确认当前连接到的 Kubernetes 集群:
kubectl config current-context
如果连接设置正确,你将看到输出为:
docker-desktop
如果你发现自己连接到了其他集群,或者如第 6.6 节所述未连接到任何集群,你需要切换回本地集群:
kubectl config use-context docker-desktop
查看所有配置的上下文可以通过以下命令:
kubectl config get-contexts
启动并激活 Kubernetes 后,你应该在列表中看到 “docker-desktop” 项。
连接确认无误后,执行一个简单的测试,列出所有在集群中的 pods 来验证一切是否正常:
kubectl get pods
对于新的 Kubernetes 实例,应显示一个空列表,因为还未部署任何 pods。如果之前有进行过测试,可能会显示一些旧的 pods。如果需要,可以重置集群以准备新的测试(参见第 6.5 节)。
另一个有用的测试是检查集群系统命名空间中的系统级 pods:
kubectl get pods --namespace kube-system
这将显示集群系统命名空间中运行的 Kubernetes 系统 pods。这些 pods 通常是隐藏的,但可以通过指定命名空间来查看。
注意 有关 Docker Desktop 上 Kubernetes 的使用,请参阅 Docker 文档: https://docs.docker.com/desktop/kubernetes/ 。
要了解更多关于 kubectl 的使用,可以运行 kubectl --help 或查阅 Kubernetes 的官方文档中 kubectl 的参考部分:
https://kubernetes.io/docs/reference/kubectl/
。
6.8.5 部署微服务到本地 Kubernetes
现在我们可以开始将视频流微服务部署到本地 Kubernetes 集群了。确保按照之前的步骤连接到本地 Kubernetes 集群。然后,在终端中导航到示例 1 的目录,并使用 kubectl 应用部署配置:
cd chapter-6/example-1
kubectl apply -f scripts/deploy.yaml
这里的 -f 参数指定了部署配置文件,apply 子命令在 Kubernetes 集群中创建指定的资源。部署成功后,你将看到如下输出:
deployment.apps/video-streaming created
service/video-streaming created
接下来,检查本地 Kubernetes 实例中正在运行的 pods:
kubectl get pods
你应该看到我们的视频流微服务作为一个 pod 正在运行的输出:
NAME READY STATUS RESTARTS AGE
video-streaming-56d66b75c7-fp44x 1/1 Running 0 92s
这里 pod 的名称以 “video-streaming” 开头,后跟一个唯一的标识符,表明 Kubernetes 为这个 pod 生成了一个独特的标识符。我们的配置只创建了一个副本,所以列表中应该只看到一个 pod。
检查当前运行的部署:
kubectl get deployments
输出应显示 video-streaming 部署的状态:
NAME READY UP-TO-DATE AVAILABLE AGE
video-streaming 1/1 1 1 5m25s
同样,检查当前运行的服务:
kubectl get services
输出中,你会看到我们的 video-streaming 服务以及 Kubernetes 的默认 API 服务:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11m
video-streaming NodePort 10.98.29.135 <none> 80:30000/TCP 6m16s
这表明我们的微服务已成功部署,并在端口 30000 上可访问。这个端口号提供了一种方式来检查我们的服务是通过哪个端口对外提供服务。
如果在部署过程中遇到任何问题,请参考第 11 章,那里提供了调试部署问题的详细帮助。
6.8.6 测试已部署的微服务
部署微服务后,下一步是测试其运行情况。我们设置的服务类型为 NodePort,端口设定为 30000(如清单 6.1 所示),因此,通过在浏览器地址栏输入 http://localhost:30000/video,我们可以测试微服务并查看视频流。如果视频成功播放,恭喜你—你的视频流微服务已在 Kubernetes 上顺利运行。
如果发现微服务无法正常运作,常见的问题之一可能是本地机器无法访问指定端口。检查你的端口配置是否正确,并通过运行 kubectl get services 命令确认服务的端口设置。如果 30000 端口不可用,可以尝试使用 Kubernetes 允许的 30000-32767 端围内的其他端口,或者移除配置文件中的 nodePort 行,让系统自动选择一个可用端口。关于如何调试微服务的更多信息将在第 11 章详细介绍。
这个阶段,你可以通过修改代码和更新部署来进行实验。更新视频流微服务的代码后,重新执行 docker build 来构建新的镜像版本(确保为每次新构建更新镜像版本号),然后使用 kubectl apply 命令重新部署到你的本地集群。
6.8.7 删除部署
完成微服务的测试后,你可以清理集群,移除部署:
kubectl delete -f scripts/deploy.yaml
此命令会删除部署、Pod 和服务——通过该配置文件创建的所有资源都将被清除。你可以执行 kubectl get pods、kubectl get deployments 和 kubectl get services 来确认所有资源都已被删除。频繁地部署和删除微服务有助于积累实践经验。
此外,如果你进行了多次部署,使用 Docker Desktop 的 Kubernetes 设置中的 Reset Kubernetes Cluster 功能来重置整个集群可能更为便捷(参见第 6.5 节)。
6.8.8 为什么在开发中不使用本地 Kubernetes?
尽管我们有一个方便的本地 Kubernetes 集群,但为什么我们不在开发期间使用它,而是选择 Docker Compose?在开发阶段使用 Docker Compose,而在生产环境使用 Kubernetes,主要是为了简化和加速开发过程。
虽然你完全可以在开发中使用本地 Kubernetes,这对于某些情况下可能是合适的,尤其是当它在你的开发环境中运行良好时。但是,使用 Docker Compose 的主要原因是减少启动应用所需的步骤。
个人更倾向于在开发和测试中使用 Docker Compose 的理由包括:
- 在 Kubernetes 中启动涉及多个微服务的应用程序比较复杂。你需要为每个微服务编写和运行部署脚本。
- 在不同项目之间切换比较麻烦。你需要重置本地实例然后重新部署所有微服务。
- 本地 Kubernetes 配置可能与生产环境配置不同,这意味着你需要为开发和生产编写不同的部署脚本。
- 本地 Kubernetes 实例相对较重,特别是在性能较低的笔记本电脑上,它可能会消耗大量资源。
基于上述原因,在开发阶段更喜欢使用 Docker Compose 而不是 Kubernetes。不过,拥有一个本地 Kubernetes 实例对于学习和实验非常有用。你可以根据个人偏好选择使用方式。完成实验后,可以在 Docker Desktop 设置中禁用 Kubernetes,以节省资源。
6.8.9 我们已经完成了什么?
至此,我们已为微服务构建了 Docker 镜像,并在 Docker Desktop 绑定的本地 Kubernetes 实例中部署了它。通过 kubectl apply 命令,在类似生产环境的设置中创建了部署、Pod 和服务,实例化了视频流微服务。
尽管我们模拟了生产环境中微服务的运行,但要真正将微服务投入生产,还需完成更多步骤。接下来的内容就是这些步骤,我们将详细介绍如何将微服务部署到实际的生产环境中。
6.9 在 Azure 中创建托管 Kubernetes 集群
现在是时候在云环境中创建一个真正适用于生产的 Kubernetes 集群,并部署我们的视频流微服务了。虽然云环境中部署 Kubernetes 集群的流程与在本地环境中相似,但仍有一些差别。例如,我们首先需要构建微服务并将其上传到容器仓库,这在第 3 章已有详细介绍。但在开始部署之前,我们需要先创建一个容器仓库和 Kubernetes 集群,并配置 kubectl 以连接它们。
如果你尚未在第 3 章中注册 Azure 账户,现在是一个好时机。请参考第 3 章的 3.9.1 节,完成 Azure 的注册并创建容器仓库。如果你仍然保留着第 3 章创建的容器仓库,你可以继续使用。
接下来,让我们开始创建 Kubernetes 集群的过程。访问 Azure 门户( https://portal.azure.com ),在搜索栏中输入“Kubernetes”,如图 6.11 所示。选择“创建”选项后,点击“Kubernetes 服务”。

现在开始填写 Kubernetes 集群的详细配置信息,如图 6.12 所示。确保选择你的免费试用订阅(如果你有多个订阅的话),以便使用试用额度来支付费用。你可能需要向 Azure 提供信用卡信息以创建集群;尽管如此,费用应由试用额度覆盖,但请留意,一旦额度用完,Microsoft 将开始向你收费。无论如何,一旦不再需要,你应该及时删除集群以避免产生额外费用。

选择或新建一个资源组来包含你的 Kubernetes 集群。在 Azure 中,资源组用于组织和管理云资源。接着为集群选择一个名称,并记录下资源组和集群的名称,因为你很快将需要使用这些信息。选择集群的托管位置。虽然位置对实验和学习并不重要,可以使用默认设置,但如果默认位置不可用,你可能需要选择其他位置来创建集群。
继续向下滚动以完成 Kubernetes 集群的配置,如图 6.13 所示。在此,你可以为每个虚拟机选择大小。建议浏览选项并等待每个虚拟机的预估成本计算出来后,选择最经济的选项,以避免试用额度过快耗尽。

选择手动扩展方式并设置节点数为一个(除非你要实验可扩展性;如果是这样,可以尝试使用自动扩展和更多节点,但请注意这将更快消耗额度)。
当你对集群的配置感到满意时,点击“审核 + 创建”。创建集群需要一段时间。完成后,Azure 门户会通知你,你可以点击通知查看新 Kubernetes 集群的详细信息。你也可以随时在 Azure 门户的所有资源列表中找到你的集群,就像在第 3.9.1 节中找到容器仓库那样(参见那里以获取操作提示)。
现在,查看集群的连接详情。在集群的概览页面中,点击连接按钮,如图 6.14 所示。这会弹出一个侧边窗口,显示你需要在本地计算机上执行的 Azure CLI 命令,以下载 Azure 凭证并连接到 Azure 上运行的新集群。因此,接下来你需要安装 Azure CLI 工具。

6.10 使用 Azure CLI
尽管 Azure 门户界面提供了便捷的操作界面,但此时我们需要转向命令行并开始使用 Azure CLI,这是连接到云上 Kubernetes 集群的最直接的方法。在本章的后续内容及下一章中,我们还将需要 Azure CLI 来执行其他任务。下面是开始安装 Azure CLI 的步骤。
6.10.1 安装 Azure CLI
你可以在以下链接找到 Azure CLI 的安装指南: http://mng.bz/yZeo 。请选择适合你操作系统的版本,并按照指南步骤进行安装。安装完成后,可以在终端通过以下命令验证安装:
az --version
我当前使用的版本是 2.51.0。未来的版本应保持向后兼容。
6.10.2 认证 Azure CLI
在开始使用 Azure CLI 前,你需要通过以下命令进行认证:
az login
执行此命令将会打开一个浏览器窗口,供你登录到你的 Azure 账户。如果浏览器未自动打开,需按照终端中显示的指示进行操作:
A web browser has been opened at ...
Please continue the login in the web browser.
If no web browser is available or if the web browser fails to open,
use device code flow with `az login --use-device-code`.
登录成功后,终端将显示一个包含 Azure 订阅信息的 JSON 格式列表。新注册 Azure 的用户通常只有一个订阅,而老用户可能会看到多个。
认证信息将保存在本地,你现在可以在不再次登录的情况下执行其他 Azure 命令。查看当前订阅信息,使用:
az account show
此命令将显示当前激活的默认订阅。若要查看所有订阅列表,运行:
az account list
输出是一个 JSON 格式的订阅列表。每个订阅都有一个 ID 字段,这是订阅的唯一 ID。当前默认订阅通过其 isDefault 字段标记为 true。其他订阅的 isDefault 字段为 false。
你应该验证自己正在使用正确的订阅来跟随本书中的示例。例如,如果你可以访问雇主的订阅,你可能不应该使用这些订阅进行自己的学习和实验(或者至少,先询问你的老板)。如果需要,可以切换到其他订阅:
az account set --subscription=<subscription-id>
更换 <subscription-id> 为你希望设为默认的订阅 ID。更改后,确认是否切换到了正确的订阅:
az account show
6.10.3 将 kubectl 连接至 Kubernetes
完成 Azure CLI 的安装和认证后,你可以使用 aks get-credentials 命令来下载凭证,并将 kubectl 连接到位于 Azure 的 Kubernetes 集群。此命令的操作细节可在 Azure 门户的 Kubernetes 集群页面通过点击连接按钮获得,具体位置如图 6.14 所示。
示例命令:
az aks get-credentials --resource-group myResourceGroup --name myCluster
此处需要将 myResourceGroup 和 myCluster 替换为你在创建集群时指定的资源组名称和集群名称(见第 6.9 节)。
常规命令格式如下:
az aks get-credentials --resource-group <resource-group> --name <cluster-name>
你可以在 AKS get-credentials 的官方文档中查找详细的命令说明: http://mng.bz/yZeo 。
此外,使用 aks 命令可以实现与 Kubernetes 集群的交互。你可以在以下链接查看更多可用的子命令: https://learn.microsoft.com/en-us/cli/azure/aks 。
配置好 kubectl 后,你就能向 Azure 上的 Kubernetes 集群发送命令。首先验证连接是否正确:
kubectl config current-context
这将显示你当前连接的集群名称。例如,我的输出为 bmdk1。根据你在第 6.9 节中设置的集群名称,显示的结果可能不同。
查看与集群的连接上下文列表:
kubectl config get-contexts
可以通过以下命令切换上下文:
kubectl config use-context <context-name>
连接成功后,试着测试与集群的通信。以下命令用于列出集群中运行的所有 pod:
kubectl get pods
由于是新集群,这通常会显示一个空列表,表示还没有 pod 在运行。另外,也可以查看系统级别的 pod:
kubectl get pods --namespace kube-system
这将列出集群中运行的 Kubernetes 系统级 pod,有助于确认系统是否正常运行。与你之前在本地 Kubernetes 实例中看到的系统 pod 列表可能略有不同。
6.11 部署到生产集群
现在我们已经建立好了 Kubernetes 集群,接下来的步骤是准备将微服务部署至此。
6.11.1 设置容器注册中心
为了在云集群中部署,我们需要一个能存储微服务镜像的云容器注册中心。如果你在第 3 章已经创建了容器注册中心且它仍在服务,可以继续使用。如果还没有,返回第 3 章的 3.9.1 节,按照指引创建一个。
6.11.2 发布镜像到容器注册中心
首先,需要构建微服务的镜像。打开终端,进入 example-2 目录,执行以下构建命令:
cd chapter-6/example-2
docker build -t video-streaming:1 --file Dockerfile-prod .
确保命令行末尾的点(.)存在,它告诉 Docker 在当前目录查找 Dockerfile。
接下来,将镜像标记为准备推送到你的容器注册中心:
docker tag video-streaming:1 <registry-url>/video-streaming:1
发布新版本时,确保更新镜像的版本号,例如 video-streaming:2、video-streaming:3 等。
推送镜像之前,你需要登录到容器注册中心:
docker login <registry-url>
完成认证后,就可以推送镜像:
docker push <registry-url>/video-streaming:1
如果推送成功,镜像就已经上传至容器注册中心,准备从 Kubernetes 进行部署。
如果在推送过程中遇到任何问题,请检查镜像是否已正确标记并符合容器注册中心的要求。
想要了解更多关于构建、标记和推送镜像的信息,请参考第 3 章的 3.8 节和 3.9 节。
6.11.3 将容器注册中心与 Kubernetes 集群关联
在开始部署微服务之前,必须确保 Kubernetes 集群能够从容器注册中心拉取镜像,这需要两者之间建立连接。使用以下命令将容器注册中心与你的 Kubernetes 集群关联起来:
az aks update --resource-group myResourceGroup --name myCluster --attach-acr myRegistry
其中,aks update 子命令用于更新运行在 Azure 上的 Kubernetes 集群的设置。
用你的资源组名称、集群名称和容器注册中心名称替换相应的占位符:
az aks update --resource-group <resource-group> --name <cluster> --attach-acr <registry>
此方法将容器注册中心直接与集群关联,避免了在 Kubernetes 配置中手动输入认证信息的需求,提高了安全性的同时简化了部署流程。尽管这种方法适合我们目前的基本使用场景,但在某些高安全需求的生产环境中,可能还需进行额外的配置和安全措施。这些高级安全设置将在第 12 章进行讨论。
6.11.4 创建部署到生产 Kubernetes 的配置
在示例 2 中,我们有一个 Kubernetes 生产部署配置文件(见清单 6.2,位于 chapter-6/example-2/scripts/deploy.yaml),该配置用于在 Azure 的 Kubernetes 服务上创建部署、Pod 和服务。此配置文件与我们之前用于本地 Kubernetes 实例的配置(清单 6.1)大致相同,但进行了针对生产环境的特定调整。
清单 6.2 将微服务部署到 Azure 上的 Kubernetes
apiVersion: apps/v1
kind: Deployment # 创建 Kubernetes 部署,保持微服务持续运行并在必要时自动重启
metadata:
name: video-streaming # 为部署指定名称
spec:
replicas: 1 # 该部署将维持一个微服务副本运行,根据需求可增加副本数以提升性能或冗余
selector:
matchLabels:
app: video-streaming
template: # 定义托管微服务的 Pod 的模板
metadata:
labels:
app: video-streaming
spec:
containers:
- name: video-streaming
image: <registry-url>/video-streaming:1 # 从容器注册中心拉取镜像,替换 <registry-url> 为你的容器注册中心 URL
imagePullPolicy: IfNotPresent # 当本地不存在时才从容器注册中心拉取镜像
env:
- name: PORT
value: "4000" # 设置微服务的运行端口为 4000
---
apiVersion: v1
kind: Service # 配置部署和服务
metadata:
name: video-streaming # 为服务指定名称
spec:
selector:
app: video-streaming
type: LoadBalancer # 设置服务类型为 LoadBalancer,以创建负载均衡器允许外部访问
ports:
- protocol: TCP
port: 80
targetPort: 4000
清单 6.2 中的关键配置调整包括:
- 镜像来源:使用最新上传到容器注册中心的镜像。部署前需更新 URL 至你的容器注册中心地址。
- 镜像拉取策略:设为
IfNotPresent,意味着仅当本地不存在时才从容器注册中心拉取。这确保了镜像在首次需要时拉取,必要时更新,避免重复拉取已缓存的版本。 - 服务类型:设为
LoadBalancer,使得创建 Azure 负载均衡器以公开服务访问成为可能。这为访问和测试提供了便利,但也意味着服务对外开放,可能引入安全风险。虽然在实验和开发阶段这是可接受的,但在生产环境中需要谨慎使用。
这些部署策略上的调整解释了为何在开发阶段通常使用 Docker Compose 而非 Kubernetes,特别是当 Docker Compose 提供更直接、简便的配置选项时(详见第 4 章 4.3.6 节及本章 6.8.8 节讨论)。维护本地和生产环境的双重配置可能会增加系统的复杂性和管理负担。
6.11.5 部署微服务到 Kubernetes
现在镜像已发布且容器注册中心与集群已连接,我们可以开始部署视频流微服务到 Kubernetes 了。
部署过程与之前在本地 Kubernetes 实例中的操作相同:
cd chapter-6/example-2
kubectl apply -f scripts/deploy.yaml
此处的 -f 参数用于指定配置文件,定义了我们希望在集群中创建的 Kubernetes 对象。
部署完成后,使用以下命令检查新创建的 Kubernetes 资源:
kubectl get pods
kubectl get deployments
kubectl get services
你将能看到为视频流微服务新创建的部署、Pod 和服务。
如果部署过程中遇到任何问题,可以参考第 11 章,该章提供了解决部署问题的帮助。
6.11.6 测试已部署的微服务
微服务部署完毕后,下一步是验证其功能是否正常。在清单 6.2 的配置文件中,我们设置了服务类型为 LoadBalancer,以便分配一个可以从外部访问的 IP 地址。但怎样才能找到这个 IP 地址呢?
一般情况下,通过执行以下命令,可以在输出中查看外部 IP 地址:
kubectl get services
下面是一个可能的输出示例。注意,显示的 IP 地址将与你的实际情况不同:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP
video-streaming LoadBalancer 10.0.221.252 20.127.176.147 80:32545/TCP
我们可以从输出中找到 IP 地址,并使用该地址来测试微服务。在这个例子中,IP 地址是 20.127.176.147,因此你可以通过浏览器访问 http://20.127.176.147/video 来进行测试。如果视频成功播放,这意味着你的微服务已经在正常运行。请确保使用分配给你的微服务的实际 IP 地址进行测试。
图 6.15 展示了如何从 kubectl get services 的输出中查找外部 IP 地址:

kubectl get services 的输出中找到外部 IP 地址在生产环境中,通常不建议将微服务公开给外部网络,除非有明确的对外服务需求。本次将视频流微服务公开仅作为学习和试验 Kubernetes 的一个临时措施。在第 11 章中,我们将探索更多测试生产微服务的方法,无需将其完全暴露给外界。
6.11.7 删除部署
测试完成后,我们可以通过删除部署来清理集群。执行以下命令以移除部署:
kubectl delete -f scripts/deploy.yaml
这将删除配置文件中定义的所有资源,包括部署、Pod 和服务。为验证资源是否已完全删除,可以执行 kubectl get pods、kubectl get deployments 和 kubectl get services。多次部署和删除微服务可以帮助你积累更多经验。每次更新代码并重建微服务镜像时,别忘了更新镜像的版本号。
6.11.8 销毁基础设施
实验结束后,如果没有继续使用云上 Kubernetes 集群的需求,应考虑将其删除,避免消耗完所有免费试用额度。未来的章节将指导你如何使用 Terraform 代码重建容器注册中心和 Kubernetes 集群,因此保留特定于本书内容的容器注册中心或集群是不必要的。当然,如果你打算继续实验、学习或运行应用程序,可以选择保留这些资源。
要删除 Kubernetes 集群,登录到 Azure 门户,导航至你的集群页面,然后点击页面顶部的删除按钮。这将移除集群及其相关资源,例如节点等。确保在“所有资源”中检查以确认所有相关资源都已完全删除。采用相同的方法,你也可以删除容器注册中心。
6.11.9 我们取得的成就
至此,我们已经完成了一系列操作:为微服务构建并发布 Docker 镜像,通过 Azure 门户创建 Kubernetes 集群,并成功将微服务部署上去。这些操作非常接近真实的生产环境操作;主要的区别在于后续我们将实现基础设施创建和微服务部署的自动化。目前我们只部署了一个微服务,但每向前迈出一步,我们都离全面部署 FlixTube 微服务应用更近了一步。
6.12 Azure CLI 工具回顾
本章中,我们通过 Azure CLI 工具在终端创建和配置 Azure 云资源。使用该工具,我们连接到 Azure,下载了连接凭证,从而能够与 Kubernetes 集群建立连接。以下表格总结了我们使用的 CLI 命令。
表 6.2 Azure CLI 命令回顾
| 命令 | 描述 |
|---|---|
az --version | 显示 Azure CLI 工具的版本号。 |
az login | 登录到 Azure 帐户并连接 Azure CLI 工具。 |
az account show | 显示当前使用的 Azure 帐户详情。 |
az account list | 列出所有配置的 Azure 帐户。 |
az account set --subscription=<subscription-id> | 设置当前使用的 Azure 帐户订阅。 |
az aks get-credentials --resource-group <resource-group> --name <cluster> | 下载凭证并将 kubectl 连接到 Kubernetes 集群。 |
az aks update --name <cluster> --resource-group <resource-group> --attach-acr <registry> | 将容器注册中心附加到 Kubernetes 集群,允许集群无需额外认证即可从注册中心拉取镜像。 |
注意:有关 Azure CLI 的更多信息,请参考官方文档: https://learn.microsoft.com/en-us/cli/azure/ 。
6.13 Kubectl 回顾
Kubectl 是与 Kubernetes 集群互动、部署及管理微服务的关键命令行工具。本节我们首先在本地 Kubernetes 实例上部署视频流微服务,随后将其迁移到由 Azure 托管的 Kubernetes 集群。表 6.3 总结了我们在此过程中所应用的 kubectl 命令。
注意 获取更多关于 kubectl 的信息,请访问其文档页面: https://kubernetes.io/docs/reference/kubectl/ 。
表 6.3 Kubectl 命令回顾
| 命令 | 描述 |
|---|---|
kubectl version | 显示客户端和服务器端的 Kubernetes 版本。 |
kubectl config current-context | 显示当前连接的 Kubernetes 集群。 |
kubectl config use-context <cluster-name> | 切换到指定上下文的 Kubernetes 集群。 |
kubectl config use-context docker-desktop | 切换到在 Docker Desktop 上运行的本地 Kubernetes 集群。 |
kubectl config get-contexts | 列出所有配置的集群上下文。 |
kubectl apply -f <file> | 使用 YAML 文件在集群中部署 Kubernetes 资源。 |
kubectl delete -f <file> | 删除 YAML 文件中定义的 Kubernetes 资源。 |
kubectl get pods | 查询集群中所有 Pod 的信息。 |
kubectl get deployments | 查询集群中所有部署的状态。 |
kubectl get services | 查询集群中所有服务,以便获取外部服务的 IP 地址和端口。 |
6.14 继续你的学习
本章引导你开始在 Kubernetes 上构建适用于生产环境的应用。从使用 Docker Desktop 的本地 Kubernetes 实例起步,逐步过渡到在 Azure 上创建并管理托管 Kubernetes 集群。
作为微服务架构的行业标准,Kubernetes 是一个复杂且功能全面的容器编排平台。虽然本书仅涵盖了 Kubernetes 的基本概念,以下资源将助你更深入地理解并精通 Kubernetes:
- 《Core Kubernetes》 — 作者 Jay Vyas 与 Chris Love,详尽解析 Kubernetes 的核心概念及其高级功能。
- 《Kubernetes in Action, 第二版》 — 作者 Marko Lukša,深入探讨 Kubernetes 的操作和管理。
- 《Kubernetes for Developers》 — 作者 William Denniss,专注于开发者如何高效利用 Kubernetes。
- 《Learn Kubernetes in a Month of Lunches》 — 作者 Elton Stoneman,为初学者提供易于理解的 Kubernetes 学习途径。
推荐的在线资源包括:
- Docker 文档,了解在 Docker Desktop 下的 Kubernetes: https://docs.docker.com/desktop/kubernetes/
- 官方 Kubernetes 文档,获取更多相关知识: https://kubernetes.io/docs/home/
- 从此链接开始学习 Kubernetes 中的 YAML 配置应用: http://mng.bz/g7W8
- 使用 Azure CLI 工具的详细指南: https://docs.microsoft.com/en-us/cli/azure/
- 了解 Azure 托管 Kubernetes 服务的详情: https://docs.microsoft.com/en-au/azure/aks
总结
- 尽早投入生产——将应用尽快展示给客户,以便获取反馈和改进。应用体积较小时,进入生产环境通常更简单。
- Kubernetes 是一个容器编排平台,已成为运行微服务的行业标准。
- Kubernetes 集群由节点(VM)、Pod 和容器构成。
- Pod 是 Kubernetes 的基本计算单元,可以托管多个容器。
- Kubernetes 部署负责维持微服务的 Pod 运行。如果 Pod 崩溃或无响应,部署会自动替换它。
- Kubernetes 服务创建 DNS 记录,使微服务在集群内部可见,并可选择暴露给外部世界。
- 使用 Docker Desktop 自带的本地 Kubernetes 实例是学习、实验和练习 Kubernetes 的理想选择。
- 我们使用 kubectl——Kubernetes 的命令行工具——来与 Kubernetes 集群交互和创建部署。
- Kubernetes 部署通过应用 YAML 配置文件到集群来创建。
- 在个人硬件上设置 Kubernetes 较为复杂和困难,但通过 Azure 门户 UI 创建托管 Kubernetes 集群则相对简单。
- 使用 Azure CLI 工具可以将容器注册中心与 Kubernetes 集群连接,预先认证集群从容器注册中心拉取镜像,简化部署过程。