利用容器和协调器

小窍门

此内容摘自电子书《为 Azure 架构云原生 .NET 应用程序》,可在 .NET 文档 查阅或下载免费的 PDF 离线阅读。

Azure 平台的云原生 .NET 应用电子书封面缩略图。

容器和业务流程协调程序旨在解决整体部署方法常见的问题。

整体部署的挑战

传统上,大多数应用程序已部署为单个单元。 此类应用程序称为一体化应用。 这种将应用程序部署为单个单元的一般方法,即使它们由多个模块或程序集组成,也称为整体体系结构,如图 3-1 所示。

单体架构。

图 3-1. 单体架构。

尽管它们具有简单性的好处,但整体体系结构面临许多挑战:

部署

此外,它们需要重启应用程序,如果在部署时未应用零停机技术,则可能会暂时影响可用性。

规模化

整体式应用程序完全托管在单个计算机实例上,通常需要高功能硬件。 如果整体中的任何部分需要缩放,则必须将整个应用程序的另一个副本部署到另一台计算机。 使用单体应用时,无法单独扩展应用程序组件 —— 要么全部扩展,要么不扩展。 如果缩放无需缩放的个别组件,会导致资源利用率低下且成本高昂。

环境

整体式应用程序通常部署到具有预安装的作系统、运行时和库依赖项的托管环境。 此环境可能与开发或测试应用程序时所依据的环境不匹配。 跨应用程序环境不一致是整体部署的常见问题来源。

耦合

整体式应用程序可能在其功能组件上遇到高耦合度。 如果没有硬边界,系统更改通常会导致意外和昂贵的副作用。 新功能/修复变得棘手、耗时且实现成本高昂。 更新需要广泛的测试。 耦合还使得在替代实现中难以重构组件或交换。 即使严格遵循关注点分离原则,体系结构侵蚀也逐渐出现,因为整体代码库不断被永无止境的“特殊情况”所恶化。

平台锁定

单一式应用程序是使用单个技术堆栈构造的。 虽然提供统一性,但这种承诺可能会成为创新障碍。 新功能和组件将使用应用程序的当前堆栈生成-即使更现代的技术可能是更好的选择。 长期风险是你的技术堆栈变得过时和被淘汰。 将整个应用程序重新架构到一个新的、更现代的平台最昂贵且有风险。

容器和业务流程协调程序有什么优点?

我们在第 1 章中介绍了容器。 我们重点介绍了 Cloud Native Computing Foundation (CNCF) 如何将其容器化列为 其Cloud-Native 跟踪映射 中的第一步,指导企业开始其云原生旅程。 在本部分中,我们将讨论容器的优点。

Docker 是最受欢迎的容器管理平台。 它适用于 Linux 或 Windows 上的容器。 容器提供可在任何系统上以相同方式运行的独立但可重现的应用程序环境。 这一方面使它们非常适合开发和托管云原生服务。 容器彼此隔离。 同一主机硬件上的两个容器可以具有不同版本的软件,而不会造成冲突。

容器由简单的基于文本的文件定义,这些文件将转变为项目中的项目并签入到源代码管理中。 尽管完整服务器和虚拟机需要手动更新,但容器易于版本控制。 可以使用自动化工具作为生成管道的一部分开发、测试和部署在容器中运行的应用。

容器是不可变的。 定义容器后,可以重新创建并运行它的方式完全相同。 这种不可变性本身就适合基于组件的设计。 如果应用程序的某些部分发展方式与其他部分不同,那么当可以最频繁地部署更改的部分时,为什么要重新部署整个应用? 应用的不同功能和跨领域关注点可以分解为单独的单元。 图 3-2 显示了整体应用如何通过委托某些特性或功能来利用容器和微服务。 应用本身中的剩余功能也已容器化。

分解一体化应用,以在后端使用微服务。

图 3-2. 分解单体应用以采用微服务架构。

每个云原生服务都构建并部署在单独的容器中。 每个都可以根据需要进行更新。 单个服务可以托管在具有适合每个服务的资源的节点上。 每个服务运行的环境都是不可变的、跨开发、测试和生产环境共享的,并且易于版本控制。 应用程序不同区域之间的耦合以服务间的调用或消息(而不是以一体化应用中的编译时依赖关系)的形式显式发生。 还可以选择最适合给定功能的技术,而无需对应用的其余部分进行更改。

容器化服务需要自动化管理。 手动管理一组独立部署的容器是不可行的。 例如,请考虑以下任务:

  • 如何在多个计算机的群集中预配容器实例?
  • 部署后,容器如何发现并相互通信?
  • 容器如何按需进行缩放?
  • 如何监控每个容器的健康状况?
  • 如何保护容器免受硬件和软件故障的影响?
  • 如何在零停机的情况下升级实时应用程序的容器?

容器业务流程协调程序可解决并自动处理这些问题和其他问题。

在云原生生态系统中,Kubernetes 已成为事实上的容器业务流程协调程序。 它是由 Cloud Native Computing Foundation (CNCF) 管理的开源平台。 Kubernetes 自动化处理跨计算机群集的容器化工作负载的部署、扩展和运营问题。 但是,安装和管理 Kubernetes 非常复杂。

更好的方法是利用 Kubernetes 作为云供应商的托管服务。 Azure 云具有一个完全托管的 Kubernetes 平台,名为 Azure Kubernetes 服务(AKS)。 AKS 抽象化了管理 Kubernetes 的复杂性和运营开销。 您将 Kubernetes 作为云服务使用;Microsoft 负全责管理并支持该服务。 AKS 还与其他 Azure 服务和开发工具紧密集成。

AKS 是基于群集的技术。 联合虚拟机或节点池部署到 Azure 云。 它们共同构成了高度可用的环境或群集。 群集在云原生应用程序中呈现为一个无缝的单一实体。 在后台,AKS 按照一个均匀分布负载的预定义策略在这些节点上部署容器化服务。

扩展的好处是什么?

基于容器构建的服务可以利用 Kubernetes 等业务流程工具提供的缩放优势。 容器一开始就设计为仅了解自己的情况。 一旦有多个容器需要协同工作,则应在更高级别组织它们。 组织大量容器及其共享依赖项(如网络配置)是编排工具发挥重要作用的地方! Kubernetes 基于容器组创建抽象层,并将它们组织成 pods。 Pod 在称为节点的辅助角色计算机上运行。 这种有组织的结构称为 群集。 图 3-3 显示了 Kubernetes 群集的不同组件。

Kubernetes 群集组件。 图 3-3. Kubernetes 群集组件。

缩放容器化工作负荷是容器业务流程协调程序的关键功能。 AKS 支持跨两个维度自动缩放:容器实例和计算节点。 它们共同使 AKS 能够快速高效地响应需求高峰并添加其他资源。 本章稍后将讨论 AKS 中的缩放。

声明性与命令性

Kubernetes 支持声明性配置和命令性配置。 命令性方法涉及运行各种命令,告知 Kubernetes 如何执行每一步。 运行此映像。 删除此 Pod。 公开此端口。 使用声明性方法,您可以创建一个名为清单的配置文件,用于描述您想要的结果,而非具体的操作步骤。 Kubernetes 读取配置文件并将目标状态转换为实际目标状态。

命令式指令非常适合学习和交互式实验。 但是,需要以声明方式创建 Kubernetes 清单文件,以采用基础结构即代码方法,从而提供可靠且可重复的部署。 清单文件将成为项目中的项目,并在 CI/CD 管道中用于自动执行 Kubernetes 部署。

如果已使用命令配置群集,则可以使用 kubectl get svc SERVICENAME -o yaml > service.yaml 导出声明式清单。 此命令生成类似于如下所示的清单:

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2019-09-13T13:58:47Z"
  labels:
    component: apiserver
    provider: kubernetes
  name: kubernetes
  namespace: default
  resourceVersion: "153"
  selfLink: /api/v1/namespaces/default/services/kubernetes
  uid: 9b1fac62-d62e-11e9-8968-00155d38010d
spec:
  clusterIP: 10.96.0.1
  ports:
  - name: https
    port: 443
    protocol: TCP
    targetPort: 6443
  sessionAffinity: None
  type: ClusterIP
status:
  loadBalancer: {}

使用声明性配置时,可以在提交更改之前使用kubectl diff -f FOLDERNAME预览将要对配置文件所在的文件夹进行的更改。 确定要应用更改后,请运行 kubectl apply -f FOLDERNAME。 添加 -R 以递归方式处理文件夹层次结构。

还可以将声明性配置与其他 Kubernetes 功能一起使用,其中一项是部署。 声明性部署有助于管理发布、更新和缩放。 它们指示 Kubernetes 部署控制器如何部署新的更改、扩展负载、或者回滚到以前的版本。 如果群集不稳定,声明性部署将自动将群集返回回所需状态。 例如,如果节点发生崩溃,部署机制将重新部署替代节点以达到所需状态。

使用声明性配置可以将基础结构表示为代码,该代码可以与应用程序代码一起签入和版本控制。 它提供了改进的变更管理,并通过构建和部署流程更好地支持持续部署。

哪些方案非常适合容器和业务流程协调程序?

以下场景非常适合使用容器和编排工具。

需要高运行时间和可伸缩性的应用程序

具有高运行时间和可伸缩性要求的单个应用程序是使用微服务、容器和业务流程协调程序实现云原生体系结构的理想候选项。 可以在容器中开发它们,跨版本控制环境进行测试,并部署到生产环境,且无需停机。 使用 Kubernetes 群集可确保此类应用还可以按需缩放,并从节点故障中自动恢复。

大量应用程序

部署和维护大量应用程序的组织受益于容器和业务流程协调程序。 设置容器化环境和 Kubernetes 群集的前期工作主要是固定成本。 部署、维护和更新各个应用程序的成本因应用程序数量而异。 除了几个应用程序之外,手动维护自定义应用程序的复杂性超过了使用容器和业务流程协调程序实现解决方案的成本。

何时应避免使用容器和业务流程协调程序?

如果无法按照 Twelve-Factor 应用原则生成应用程序,应考虑避免容器和业务流程协调程序。 在这些情况下,请考虑基于 VM 的托管平台,或者可能考虑一些混合系统。 借助它,你始终可以将某些功能片段启动到单独的容器甚至无服务器函数中。

开发资源

本部分介绍一个简短的开发资源列表,可帮助你开始为下一个应用程序使用容器和业务流程协调程序。 若要查找有关如何设计云原生微服务体系结构应用的指南,请阅读本书的配套 .NET 微服务:容器化 .NET 应用程序的体系结构

本地 Kubernetes 开发

Kubernetes 部署在生产环境中提供出色的价值,但也可在开发计算机上本地运行。 虽然可以独立地处理单个微服务,但有时可能需要在本地运行整个系统,就像部署到生产环境时一样。 有几个工具可以帮助:Minikube 和 Docker Desktop。 Visual Studio 还提供用于 Docker 开发的工具。

Minikube

什么是 Minikube? Minikube 项目显示“Minikube 在 macOS、Linux 和 Windows 上实现本地 Kubernetes 群集。其主要目标是“成为本地 Kubernetes 应用程序开发的最佳工具,并支持适合的所有 Kubernetes 功能”。安装 Minikube 独立于 Docker,但 Minikube 支持不同于 Docker Desktop 支持的虚拟机监控程序。 Minikube 目前支持以下 Kubernetes 功能:

  • DNS(域名系统)
  • NodePorts
  • ConfigMap 和机密
  • 仪表板
  • 容器运行时:Docker、rkt、CRI-O 和 containerd
  • 启用容器网络接口 (CNI)
  • 流入量

安装 Minikube 后,可以通过运行 minikube start 命令(下载映像并启动本地 Kubernetes 群集)快速开始使用它。 启动群集后,可以使用标准 Kubernetes kubectl 命令与其交互。

Docker Desktop

还可以直接从 Windows 上的 Docker Desktop 使用 Kubernetes。 如果你使用的是 Windows 容器,这是唯一的选择,同时对于非 Windows 容器来说也是一个不错的选择。 图 3-4 显示了如何在运行 Docker Desktop 时启用本地 Kubernetes 支持。

在 Docker Desktop 中配置 Kubernetes

图 3-4. 在 Docker Desktop 中配置 Kubernetes。

Docker Desktop 是在本地配置和运行容器化应用的最常用工具。 使用 Docker Desktop 时,可以针对要部署到生产环境的同一组 Docker 容器映像在本地进行开发。 Docker Desktop 旨在在本地“生成、测试和交付”容器化应用。 它支持 Linux 和 Windows 容器。 将映像推送到映像注册表(如 Azure 容器注册表或 Docker 中心)后,AKS 可以拉取映像并将其部署到生产环境。

Visual Studio Docker 工具集

Visual Studio 支持基于 Web 的应用程序的 Docker 开发。 创建新的 ASP.NET Core 应用程序时,可以选择使用 Docker 支持配置它,如图 3-5 所示。

Visual Studio 启用 Docker 支持

图 3-5. Visual Studio 启用 Docker 支持

选择此选项后,项目将在其根目录中创建一个 Dockerfile,该目录可用于在 Docker 容器中构建和托管应用。 图 3-6 中显示了一个 Dockerfile 示例。

FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["eShopWeb/eShopWeb.csproj", "eShopWeb/"]
RUN dotnet restore "eShopWeb/eShopWeb.csproj"
COPY . .
WORKDIR "/src/eShopWeb"
RUN dotnet build "eShopWeb.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "eShopWeb.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "eShopWeb.dll"]

图 3-6. Visual Studio 生成的 Dockerfile

添加支持后,可以在 Visual Studio 的 Docker 容器中运行应用程序。 图 3-7 显示了使用 Docker 支持添加的新 ASP.NET Core 项目提供的不同运行选项。

Visual Studio Docker 运行选项

图 3-7. Visual Studio Docker 运行选项

此外,可以随时将 Docker 支持添加到现有 ASP.NET Core 应用程序。 在 Visual Studio 解决方案资源管理器中,右键单击项目并选择“ 添加>Docker 支持”,如图 3-8 所示。

Visual Studio 添加 Docker 支持

图 3-8. 向 Visual Studio 添加 Docker 支持

Visual Studio Code Docker 工具

Visual Studio Code 提供了许多支持 Docker 开发的扩展。

Microsoft提供 用于 Visual Studio Code 的 Docker 扩展。 此扩展简化了向应用程序添加容器支持的过程。 它为所需的文件搭建基架,生成 Docker 映像,并使你能够在容器中调试应用。 该扩展具有可视化资源管理器,可轻松地对容器和映像执行作,例如启动、停止、检查、删除等。 该扩展还支持 Docker Compose,使你可以将多个正在运行的容器作为单个单元进行管理。