Docker-Windows-教程(四)

171 阅读24分钟

Docker Windows 教程(四)

原文:zh.annas-archive.org/md5/51C8B846C280D9811810C638FA10FD64

译者:飞龙

协议:CC BY-NC-SA 4.0

第十二章:将您所知道的内容放入容器-实施 Docker 的指导

在本书中,我使用了较旧的.NET 技术来展示示例应用程序,以向您展示 Docker 与现代.NET Core 应用程序一样有效。您可以将十年前的 WebForms 应用程序放入 Docker,并获得与在容器中运行全新的 ASP.NET Core Web 应用程序相同的许多好处。

您已经看到了许多容器化应用程序的示例,并学会了如何使用 Docker 构建、部署和运行生产级应用程序。现在,您已经准备好在自己的项目中开始使用 Docker,并且本章将为您提供如何入门的建议。

我将介绍一些技术和工具,这些将帮助您运行一个概念验证项目,将应用程序迁移到 Docker。我还将通过一些案例研究向您展示我是如何将 Docker 引入现有项目的:

  • 一个小型的.NET 2.0 WebForms 应用程序

  • Windows Communication FoundationWCF)应用程序中的数据库集成服务

  • 在 Azure 中运行的分布式 IoT API 应用程序

你将看到如何解决典型问题以及 Docker 的应用如何帮助解决这些问题。

将您所知道的内容放入 Docker

当您迁移到新的应用程序平台时,您必须使用一组新的工件和新的操作流程。如果您目前使用 Windows 安装程序进行部署,您的工件是 Wix 文件和 MSI 文件。您的部署过程是将 MSI 复制到目标服务器,登录并运行安装程序。

迁移到 Docker 后,您将拥有 Dockerfiles 和镜像作为部署工件。您将镜像推送到注册表并运行容器或更新服务以部署应用程序。在 Docker 中资源和活动更简单,并且它们在项目之间是一致的,但是当您开始时仍然有一个学习曲线。

将您熟悉的应用程序放入容器是提供学习经验的一个很好的方法。当您首次在容器中运行应用程序时,可能会出现错误或不正确的行为,但这将是您自己应用程序的领域。当您追踪问题时,您将处理一个您很了解的领域,因此尽管平台是新的,问题应该很容易识别。

选择一个简单的概念验证应用程序

Docker 理想地适用于分布式应用程序,其中每个组件在轻量级容器中运行,有效地利用最小的硬件集。您可以选择一个分布式应用程序作为您的第一个 Docker 部署,但一个更简单的应用程序将更快地迁移,并且会给您更高的成功机会。

单体应用是一个不错的选择。它不一定要有一个小的代码库,但是与其他组件的集成越少,您就越快地将其在 Docker 中运行。将状态存储在 SQL Server 中的 ASP.NET 应用程序是一个直接的选择。您可以期望用一个简单的应用程序在一两天内运行一个概念验证PoC)。

从已编译的应用程序开始,而不是源代码,是证明该应用程序可以被 Docker 化而无需更改的好方法。在选择您的 PoC 应用程序时,有一些因素需要考虑:

  • 有状态性:如果您的目标应用程序在内存中存储状态,您将无法通过运行多个容器来扩展 PoC。每个容器将有自己的状态,并且除非您还运行具有粘性会话支持的反向代理,否则在不同容器处理请求时会得到不一致的行为。考虑无状态应用程序或可以使用共享状态的应用程序,比如使用 SQL Server 作为 ASP.NET 的会话状态提供程序。

  • 配置:.NET 应用程序通常在Web.configapp.config中使用 XML 配置文件。您可以设置您的 PoC 来使用现有的配置文件作为基础,然后替换任何不适用于容器化环境的值。最好通过 Docker 使用环境变量和秘密来读取配置设置,但对于 PoC 来说,保持配置文件更容易。

  • 弹性:较旧的应用程序通常假设可用性——Web 应用程序期望数据库始终可用,并且不会优雅地处理故障条件。如果您的应用程序对外部连接没有重试逻辑,那么当容器启动时出现瞬时连接故障时,您的 PoC 将面临错误。您可以在 Dockerfile 中通过启动时检查依赖项和持续的健康检查来减轻这种情况。

  • Windows 身份验证:容器未加入域。如果您在 AD 中创建了一个组托管服务帐户,您可以在容器中访问Active DirectoryAD)对象,但这会增加复杂性。对于 PoC,坚持使用更简单的身份验证方案,如基本身份验证。

这些都不是主要限制。您应该能够在容器化现有应用程序的基础上工作,而无需更改代码,但您需要意识到在 PoC 阶段功能可能不完美。

使用 Image2Docker 生成初始 Dockerfile

Image2Docker 是一个开源工具,您可以使用它为现有应用程序生成 Dockerfile。它是一个 PowerShell 模块,您可以在本地计算机上运行,也可以针对远程计算机或虚拟机磁盘文件运行(在 Hyper-V 中,文件以VHDVHDX格式存储)。

这是一个非常简单的开始使用 Docker 的方法-甚至您甚至不需要在本地计算机上安装 Docker 来尝试并查看 Dockerfile 对您的应用程序会是什么样子。Image2Docker 可以处理不同类型的应用程序(称为构件),但对于在 IIS 上运行的 ASP.NET 应用程序,功能是成熟的。

在我的开发计算机上,我有一个部署到Internet Information ServicesIIS)的 ASP.NET 应用程序。我可以通过从 PowerShell 库安装 Image2Docker 并导入模块来在 Docker 中迁移该应用程序。

Install-Module Image2Docker
Import-Module Image2Docker

PowerShell 5.0 是Image2Docker所需的最低版本,但该工具没有其他依赖关系。

我可以运行ConvertTo-Dockerfile cmdlet,指定 IIS 构件来构建一个包含我计算机上所有 IIS 网站的 Dockerfile:

ConvertTo-Dockerfile -Local -Artifact IIS -OutputPath C:\i2d\iis

这将在C:\i2d\iis创建一个目录,在文件夹内部,我将有一个 Dockerfile 和每个网站的子目录。Image2Docker将网站内容从源复制到输出位置。Dockerfile 使用最相关的基础映像来找到应用程序,即microsoft/iismicrosoft/aspnetmicrosoft/aspnet:3.5

如果源中有多个网站或 Web 应用程序,Image2Docker会提取它们所有并构建一个重复原始 IIS 设置的单个 Dockerfile,因此 Docker 镜像中将有多个应用程序。这不是我的目标,因为我希望我的 Docker 镜像中只有一个应用程序,所以我可以使用参数来提取单个网站:

ConvertTo-Dockerfile -Local -Artifact IIS -ArtifactParam SampleApi -OutputPath C:\i2d\api

这个过程是一样的,但这次,Image2Docker只从源中提取一个应用程序 - 在ArtifactParam参数中命名的应用程序。Dockerfile 包含部署应用程序的步骤,您可以运行docker image build来创建图像并运行应用程序。

这可能是 Docker 化应用程序的第一步,然后您将运行一个容器并检查应用程序的功能。可能需要额外的设置,Image2Docker不会为您完成,所以您可能会在生成的 Dockerfile 上进行迭代,但该工具是一个很好的开始。

Image2Docker是一个开源项目。源代码在 GitHub 上 - 使用以下短链接查看:github.com/docker/communitytools-image2docker-win。该工具最近没有更新,因为 Docker 现在有一个商业替代品叫做 Docker Application Convertor(DAC)。DAC 具有更强大的功能集,因为它支持 Linux 和 Windows 应用程序。您可以在 YouTube 上的 DockerCon 会议上看到演示:is.gd/sLMOa1

吸引其他利益相关者

一个成功的 PoC 应该在几天内就能实现。其输出将是在 Docker 中运行的示例应用程序,以及您需要将该 PoC 投入生产的一系列额外步骤。如果您在一个 DevOps 环境中工作,您的团队负责项目的交付,您可以同意投资转移到 Docker 用于生产。

对于更大的项目或更大的团队,您需要与其他利益相关者合作,以进一步进行您的 PoC。您进行的对话类型将取决于您的组织结构,但有一些主题侧重于您在 Docker 中获得的改进:

  • 在部署应用程序时,运维团队经常在从开发部门交接时遇到摩擦。Docker 工件、Dockerfiles 和 Docker Compose 文件是开发和运维可以共同努力的中心点。运维团队不会因为升级而无法部署,因为升级将是一个已经经过尝试和测试的 Docker 镜像。

  • 大公司的安全团队经常需要证明来源。他们需要证明在生产中运行的软件没有被篡改,并且实际上正在运行 SCM 中的代码。目前可能是基于流程的,但通过镜像签名和 Docker 内容信任,可以明确地证明。在某些情况下,安全团队还需要证明系统只能在经过认证的硬件上运行,而在 Docker Swarm 中使用安全标签和约束很容易实现。

  • 产品所有者经常试图在长期发布计划中平衡庞大的积压工作。企业.NET 项目通常难以部署——升级过程缓慢、手动且风险高。有一个部署阶段,然后是用户测试阶段,在此期间应用程序对普通用户不可用。相比之下,使用 Docker 进行部署快速、自动化且安全,这意味着您可以更频繁地部署,当功能准备就绪时添加功能,而不是等待下一个预定发布的几个月。

  • 管理团队将专注于产品和产品运行成本。Docker 通过更有效地利用计算资源和降低许可成本来帮助降低基础设施成本。它通过让团队更高效地工作,消除环境之间的差异以确保部署一致,帮助降低项目成本。它还有助于提高产品质量,因为自动打包和滚动更新意味着您可以更频繁地部署,更快地添加功能和修复缺陷。

您可以通过在 Windows 10 上使用 Docker 桌面获得 Docker 的社区版CE)来开始进行 PoC。您组织中的其他利益相关者将希望了解在容器中运行的应用程序可获得的支持。Docker 企业引擎包含在 Windows Server 2016 或 2019 的许可成本中,因此您可以在没有额外成本的情况下获得来自 Microsoft 和 Docker, Inc.的支持。运营和安全团队可能会在完整的 Docker 企业套件中看到很多好处,其中包括通用控制平面UCP)和Docker 受信任的注册表DTR)。

Docker 最近宣布他们将为 Mac 和 Windows 推出 Docker 桌面企业版。它将拥有与 Docker 桌面相同的出色用户体验,但支持 Windows 10,并能够在本地运行与您的组织在生产中运行的相同版本的 Docker 企业引擎。

您的 PoC 中的 Dockerfiles 和 Docker 镜像将在所有这些版本上以相同的方式工作。 Docker CE,Docker Enterprise Engine 和 Universal Control Plane 都共享相同的基础平台。

实施 Docker 的案例研究

我将通过查看三个真实案例研究来结束本章,这些案例研究中,我已经将 Docker 引入现有解决方案,或者准备了将 Docker 引入项目的路线图。这些都是生产场景,从一个有数十个用户的小公司项目到一个拥有超过一百万用户的大型企业项目。

案例研究 1 – 一个内部 WebForms 应用程序

多年前,我接手了一家汽车租赁公司的 WebForms 应用程序的支持工作。该应用程序由一个约 30 人的团队使用,是一个小规模部署——他们有一个托管数据库的服务器和一个运行 Web 应用程序的服务器。尽管规模小,但这是公司的核心应用程序,他们所有的业务都是通过这个应用程序运行的。

该应用程序的架构非常简单:只有一个 Web 应用程序和一个 SQL Server 数据库。最初,我做了很多工作来改善应用程序的性能和质量。之后,它变成了一个看护人的角色,我每年会管理两到三次发布,添加新功能或修复旧的错误。

这些发布总是比必要的更加困难和耗时。发布通常包括以下内容:

  • 带有更新应用程序的 Web 部署包

  • 一组带有模式和数据更改的 SQL 脚本

  • 一个手动测试指南,用于验证新功能并检查是否存在回归

部署是在办公时间之外进行的,以便我们有时间窗口来解决我们发现的任何问题。我会使用远程桌面协议(RDP)访问他们的服务,复制工件,并手动运行 Web 部署包和 SQL 脚本。通常发布之间相隔几个月,所以我会依赖我写的文档来提醒我这些步骤。然后,我会按照测试指南进行测试并检查主要功能。有时,会出现问题,因为我错过了一个 SQL 脚本或 Web 应用程序的依赖项,我需要尝试追踪之前未见过的问题。

直到最近,该应用程序一直在运行 Windows Server 2003,这个系统早已不再得到支持。当公司想要升级 Windows 时,我建议使用 Windows Server 2016 Core 和 Docker。我的建议是使用 Docker 来运行 Web 应用程序,并将 SQL Server 原生地运行在自己的服务器上,但使用 Docker 作为部署数据库升级的分发机制。

迁移到 Docker 非常简单。我使用 Image2Docker 对生产服务器进行操作,生成了一个初始的 Dockerfile,然后通过添加健康检查和环境变量进行迭代。我在 Visual Studio 中已经有了一个 SQL Server 项目用于架构,所以我添加了另一个 Dockerfile 来打包 Dacpac 和数据库的部署脚本。只用了两天就完成了 Docker 构件,并在测试环境中运行了新版本。这就是 Docker 的架构:

  • 1:Web 应用程序在 Windows Docker 容器中运行。在生产环境中,它连接到一个独立的 SQL Server 实例。在非生产环境中,它连接到在容器中运行的本地 SQL Server 实例。

  • 2:数据库被打包成基于 SQL Server Express 的 Docker 镜像,并且使用 Dacpac 中的数据库架构进行部署。在生产环境中,从该镜像中运行一个任务容器来将架构部署到现有数据库。在非生产环境中,运行一个后台容器来托管数据库。

从那时起,部署变得简单明了,并且总是遵循相同的步骤。我们在 Docker Hub 上有一组私有仓库,其中存储了版本化的应用程序和数据库镜像。我配置了我的本地 Docker CLI 来与他们的 Docker Engine 一起工作,然后我做了以下操作:

  1. 停止 Web 应用程序容器。

  2. 从新的数据库镜像中运行一个容器来升级 SQL Server。

  3. 使用 Docker Compose 来将 Web 应用程序更新为新的镜像。

迁移到 Docker 的最大好处是快速可靠的发布和减少了基础设施需求。公司目前正在考虑用更多的小型服务器来替换他们当前的大型服务器,以便能够运行 Docker Swarm 并实现零停机升级。

另一个好处是发布过程的简单性。因为部署已经经过尝试和测试,使用的是将在生产中使用的相同的 Docker 镜像,所以不需要有人了解该应用程序并跟踪问题。公司的 IT 支持人员现在负责发布,他们可以在没有我的帮助下完成。

我再次与同一家公司合作,管理他们升级到最新的 Windows Server 2019 上的 Docker Enterprise。计划非常简单 - 我已经在最新的 Windows Server 2019 Core 镜像上构建了他们的应用程序和数据库镜像,并验证它们可以通过一套端到端测试工作。现在,他们可以执行服务器升级并使用相同的工具部署新版本,并对成功发布感到自信。

案例研究 2 - 数据库集成服务

我曾为一家金融公司开发一个庞大而复杂的网络应用。这是一个面向内部的应用程序,管理着大量的交易。前端使用的是 ASP.NET MVC,但大部分逻辑都在服务层中,使用 WCF 编写。服务层还是许多第三方应用程序的外观,将集成逻辑隔离在 WCF 层中。

大多数第三方应用程序都有 XML Web 服务或 JSON REST API 可供我们使用,但其中一个较老的应用程序没有集成选项。我们只用它作为参考数据,因此外观是作为数据库级别的集成实现的。WCF 服务公开了封装良好的端点,但实现直接连接到外部应用程序数据库以提供数据。

数据库集成是脆弱的,因为你必须依赖私有数据库架构而不是公共服务契约,但有时别无选择。在这种情况下,架构变化不频繁,我们可以管理这种中断。不幸的是,发布过程是反向的。运营团队首先会在生产环境中发布数据库的新版本,因为该应用程序只在生产环境中得到供应商的支持。当一切正常时,他们会在开发和测试环境中复制发布。

一个发布中有一个数据库架构的变化破坏了我们的集成。任何使用第三方应用程序的参考数据的功能都停止工作了,我们必须尽快进行修复。修复很简单,但 WCF 应用程序是一个庞大的单体,需要大量的回归测试,才能确保这个变化不会影响其他领域。我被要求考虑 Docker 作为更好地管理数据库依赖的方法。

该提案很简单。我并不建议将整个应用程序移至 Docker——这已经在长期路线图上了——而只是将一个服务移至 Docker。该服务的 WCF 端点是数据库应用程序外观将在 Docker 中运行,与应用程序的其余部分隔离。Web 应用程序是该服务的唯一消费者,因此只需更改消费者中服务的 URL。这是拟议的架构:

  • 1:Web 应用程序在 IIS 中运行。代码没有更改,但配置已更新为使用在容器中运行的新集成组件的 URL。

  • 2:原始的 WCF 服务继续在 IIS 中运行,但之前的数据库集成组件已被移除。

  • 3:新的集成组件使用与之前相同的 WCF 合同,但现在它是在容器中托管的,隔离对第三方应用程序数据库的访问。

这种方法有很多好处:

  • 如果数据库架构发生变化,我们只需要更改 Docker 化的服务

  • 服务更改可以通过更新 Docker 镜像而无需进行完整的应用程序发布来发布

  • 这是一个关于 Docker 的沙盒介绍,因此开发和运维团队可以用它进行评估。

在这种情况下,最重要的好处是减少了测试工作量。对于完整的单片应用程序,发布需要数周的测试。通过将服务拆分为 Docker 容器,只有发生变化的服务需要进行发布的测试。这大大减少了所需的时间和精力,从而可以更频繁地发布,从而更快地将新功能推出到业务中。

案例研究 3 - Azure IoT 应用程序

我是一个项目的 API 架构师,负责提供移动应用程序消费的后端服务。有两个主要的 API。配置 API 是只读的,设备调用它来检查设置和软件的更新。事件 API 是只写的,设备发布关于用户行为的匿名事件,产品团队用这些事件来指导下一代设备的设计决策。

这些 API 支持超过 150 万台设备。配置 API 需要高可用性;它们必须快速响应设备调用,并能够扩展到每秒数千个并发请求。事件 API 从设备消费数据并将事件推送到消息队列。在队列上有两组处理程序:一组将所有事件数据存储在 Hadoop 中,用于长期分析,另一组将事件的子集存储以提供实时仪表板。

所有组件都在 Azure 上运行,在项目的高峰期,我们使用了云服务、事件中心、SQL Azure 和 HDInsight。架构如下:

  • 1:事件 API 托管在一个云服务中,有多个实例。设备将事件发布到 API,API 进行一些预处理,然后将它们批量发布到 Azure 事件中心。

  • 2:配置 API 也托管在一个云服务中,有多个实例。设备连接到 API 以检查软件更新和配置设置。

  • 3:实时分析数据,用于一些关键性能指标的子集。这些数据存储在 SQL Azure 中,以便快速访问,因为这些数据量是适度的。

  • 4:批处理分析数据,用于存储所有设备发布的事件。这些数据存储在 HDInsight 中,这是 Azure 上的托管 Hadoop 服务,用于长时间运行的大数据查询。

这个系统的运行成本很高,但它为产品团队提供了大量关于设备使用情况的信息,他们将这些信息输入到下一代设计过程中。每个人都很高兴,但后来产品路线被取消了,不会再有任何设备,所以我们不得不削减运行成本。

我的工作是将 Azure 账单从每月 5 万美元降低到每月不到 1 千美元。我可以放弃一些报告功能,但事件 API 和配置 API 必须保持高可用性。

在 Windows 上可用 Docker 之前发生了这件事,所以我对架构进行了第一次修订,使用在 Azure 中运行的 Docker Swarm 上的 Linux 容器。我用 Elasticsearch 和 Kibana 替换了系统的分析部分,并用 Nginx 提供了静态内容的配置 API。我将自定义的.NET 组件留在云服务中,用于从设备数据提供给 Azure 事件中心的事件 API 和将数据推送到 Elasticsearch 的消息处理程序。

  • 1:配置 API 现在作为 Nginx 中的静态网站运行。配置数据以 JSON 负载的形式提供,保持原始 API 契约。

  • 2:Kibana 用于实时和历史分析。通过减少存储的数据量,我们显著减少了数据存储需求,但代价是失去了详细的指标。

  • 3:Elasticsearch 被用来存储传入的事件数据。仍然使用.NET 云服务从事件中心读取数据,但这个版本将数据保存在 Elasticsearch 中。

这个第一个修订版为我们带来了我们需要的成本节约,主要是通过减少 API 所需的节点数量和从设备中存储的数据量。我将所有数据都集中存储在 Elasticsearch 中,而不是在 Hadoop 中存储所有数据和在 SQL Azure 中存储实时数据的做法。使用 Nginx 来提供配置 API,我们失去了产品团队为发布配置更新而拥有的用户友好功能,但我们可以使用更小的计算资源运行。

当 Windows Server 2016 推出并且 Windows 上的 Docker 得到支持时,我进行了第二次修订。我在 Docker Swarm 中添加了现有 Linux 节点的 Windows 节点,并将事件 API 和消息处理程序迁移到了 Windows Docker 容器中。同时,我还将消息系统迁移到了在 Linux 容器中运行的 NATS:

  • 1:事件 API 现在托管在 Docker 容器中,但代码没有改变;这仍然是一个在 Windows 容器中运行的 ASP.NET Web API 项目。

  • 2:消息组件使用 NATS 而不是事件中心。我们失去了存储和重新处理消息的能力,但消息队列现在具有与事件 API 相同的可用性。

  • 3:消息处理程序从 NATS 读取数据并将数据保存在 Elasticsearch 中。大部分代码保持不变,但现在它作为一个.NET 控制台应用在 Windows 容器中运行。

这第二次修订进一步降低了成本和复杂性:

  • 现在每个组件都在 Docker 中运行,所以我可以在开发中复制整个系统

  • 所有组件都使用 Dockerfiles 构建并打包为 Docker 镜像,因此一切都使用相同的构件

  • 整个解决方案具有相同级别的服务,在单个 Docker Swarm 上高效运行

在这种情况下,该项目注定要逐渐减少,并且很容易通过新解决方案进行适应。设备使用仍然记录并显示在 Kibana 仪表板上。随着时间的推移,使用的设备越来越少,服务需要的计算量也越来越少,我们可以从 Swarm 中删除节点。最终,该项目将在最小的基础设施上运行,可能只是一个双节点 Swarm,在 Azure 的小型 VM 上运行,或者它可以迁回公司的数据中心。

总结

全世界的大大小小公司都在 Windows 和 Linux 上转向 Docker。一些主要的驱动因素是效率、安全性和可移植性。许多新项目都是使用容器从头开始设计的,但还有许多现有项目可以从迁移到 Docker 中受益。

在本章中,我已经研究了将现有应用迁移到 Windows 上的 Docker,并建议您从您熟悉的应用程序开始。对该应用程序进行短期、限时的 Docker 化概念验证将迅速向您展示您的应用在 Docker 中的样子。该概念验证的结果将帮助您了解接下来需要做什么,以及需要谁参与将该概念验证移入生产环境。

我完成了一些非常不同的案例研究,向您展示了如何在现有项目中引入 Docker。在一个案例中,我主要利用 Docker 的打包优势来运行一个单片应用,而不对其进行更改,但为将来的发布提供干净的升级。在另一个案例中,我从单片应用中提取了一个组件并将其提取到容器中,以减少发布的测试负担。在最后一个案例中,我完全将现有解决方案迁移到 Docker,使其更便宜,更易于维护,并为我提供了在任何地方运行它的选项。

希望本章能帮助您思考如何将 Docker 引入您自己的项目中,也希望本书的其余部分能向您展示您可以用 Docker 做什么,以及为什么它是一项如此令人兴奋的技术。感谢阅读,请务必查看我的 Pluralsight 课程,并在 Twitter 上关注我,在 Windows 上使用 Docker 的旅程中祝您好运!