利用容器和协调器

提示

此内容摘自电子书《为 Azure 构建云原生 .NET 应用程序》,可在 .NET 文档上获取,也可作为免费可下载的 PDF 脱机阅读。

Cloud Native .NET apps for Azure eBook cover thumbnail.

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

一体化部署难点

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

Monolithic architecture.

图 3-1。 一体化体系结构。

尽管它们具有简洁的优点,但一体化体系结构存在许多难点:

部署

此外,它们需要重新启动应用程序,如果在部署时没有应用零停机方法,这可能会暂时影响可用性。

扩展

一体化应用程序整个承载在一个计算机实例上,通常需要高容量的硬件。 如果一体化体系结构的任何部分需要缩放,就需要在另一台计算机上部署整个应用程序的另一个副本。 使用一体化体系结构时,不能单独缩放应用程序的某个组件 - 要么全部缩放,要么不缩放。 如果缩放无需缩放的个别组件,会导致资源利用率低下且成本高昂。

环境

一体化应用程序通常部署到配备有预安装的操作系统、运行时和库依赖项的承载环境。 此环境有可能与开发或测试应用程序时的环境不一致。 应用程序环境之间的不一致是导致一体化部署出问题的一个常见原因。

耦合

对于一体化应用程序,其功能组件之间产生高度耦合的可能性较大。 如果没有硬边界,系统更改通常会导致意外的、代价高昂的副作用。 新功能/修补的实现会变得棘手、耗时且成本高昂。 更新需要广泛测试。 耦合还导致难以重构组件或转换为替代实现。 即使在构建时考虑了严格的隔离设计,一体化代码基也会因为不断发生的“特殊事例”而发生退化,从而导致体系结构变弱。

平台锁定

一体化应用程序是使用单个技术堆栈构造的。 虽然提供了统一性,这种模式却可能会成为创新的障碍。 新功能和组件需要使用应用程序当前的堆栈来构建 - 即使更好的选择是使用更新的技术。 更长期的风险是技术堆栈会过时和被淘汰。 将整个应用程序重新架构到新的、更新式的平台上会很昂贵且存在风险。

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

我们在第 1 章介绍了容器。 我们重点介绍了云原生计算基金会 (CNCF) 在其云原生轨迹图(企业云原生之旅启程指南)的第一步中是如何对容器化进行排序的。 在本部分中,我们将探讨容器的优点。

Docker 是最常用的容器管理平台。 它可与 Linux 或 Windows 上的容器协同工作。 容器提供独立但可复制的应用程序环境,这些环境在所有系统上以相同的方式运行。 这一点使其非常适合用于开发和承载云原生服务。 容器彼此间相互隔离。 同一主机硬件上的两个容器可以具有不同版本的软件,而不会发生冲突。

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

容器是不可变的。 定义容器后,可采用完全相同的方式重新创建和运行容器。 这种不可变性使其适合基于组件的设计。 如果应用程序某些部分的演化不同于其他部分,那么当能够只部署最常发生变化的部分时,何须重新部署整个应用? 应用的不同功能和整合需求可以分解为独立的单元。 图 3-2 显示了一体化应用可以如何通过委托某些特性和功能来利用容器和微服务。 应用中的其余功能也被容器化。

Breaking up a monolithic app to use microservices in the back end.

图 3-2。 分解一体化应用,全面采用微服务。

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

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

  • 如何在多台计算机的群集中预配容器实例?
  • 部署完成后,容器如何发现彼此以及彼此进行通信?
  • 容器如何按需进行缩放?
  • 如何监视每个容器的运行状况?
  • 如何针对硬件和软件故障保护容器?
  • 如何将实时应用程序的容器升级为零停机时间?

容器业务流程协调程序可解决这些问题以及更多问题并提供自动化解决方案。

在云原生生态系统中,Kubernetes 成为了实际上的容器业务流程协调程序。 它是由云原生计算基金会 (CNCF) 管理的开源平台。 Kubernetes 自动执行计算机群集上容器化工作负载的部署、缩放和操作。 但是,已知安装和管理 Kubernetes 是比较复杂的。

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

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

缩放的优点是什么?

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

Kubernetes cluster components.图 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 群集这些前期工作主要是固定成本。 部署、维护和更新单个应用程序的成本因应用程序数量而异。 除少数应用程序外,手动维护自定义应用程序的复杂性这一劣势大过了使用容器和业务流程协调程序实现解决方案的成本。

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

如果无法按照“十二因素应用”原则来构建应用程序,应考虑避免使用容器和业务流程协调程序。 在这些情况下,请考虑使用基于 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
  • NodePort
  • ConfigMap 和机密
  • 仪表板
  • 容器运行时:Docker、rkt、CRI-O 和容器化
  • 启用容器网络接口 (CNI)
  • 流入量

安装 Minikube 后,可以通过运行 minikube start 命令快速开始使用它,该命令将下载一个映像并启动本地 Kubernetes 集群。 一旦集群启动,就可以使用标准的 Kubernetes kubectl 命令与之交互。

Docker Desktop

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

Configuring Kubernetes in Docker Desktop

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

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

Visual Studio Docker 工具

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

Visual Studio Enable Docker Support

图 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 Run Options

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

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

Visual Studio Add Docker Support

图 3-8。 将 Docker 支持添加到 Visual Studio

Visual Studio Code Docker 工具

有许多可用于 Visual Studio Code 的支持 Docker 开发的扩展。

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