本文是“ 持续集成,交付和部署”系列的一部分。
上一篇文章介绍了连续部署 。 在这一篇文章中,我们将继续我们离开的地方,并探索部署软件的不同策略。 本文绝不是详尽的部署应用程序的方法列表,而是试图提供当今使用的几种常见方法。
可变怪物服务器
构建和部署应用程序的常用方法是通过“可变怪物服务器” 。 我们创建了一个包含整个应用程序的Web服务器,并在每次发布新版本时进行更改。 更改可以是配置或代码(JAR,WAR,静态文件等)。 由于我们在每个发行版上都对其进行了更改,因此它是可变的 。
对于可变服务器,我们无法确定开发,测试和生产环境是否相同。 生产中甚至不同的节点也可能会有不希望的差异。 代码,配置或静态文件可能未在所有实例中都进行过更新。
它是一个怪物服务器,因为它在单个实例中包含了我们所需的一切。 后端,前端,API等。而且,它随着时间的推移而增长。 一段时间后,没有人能确定生产中所有部件的确切配置是什么并不少见,并且要在其他地方(新生产节点,测试环境等)准确地复制它的唯一方法是将VM复制并驻留在其中。开始摆弄配置(例如IP,主机文件,数据库连接等)。 我们只是不断添加它,直到我们失去对它的了解。
这样的服务器的简化图像如下。
它是与数据库(DB)和文件系统(FS)通信的单个大型怪兽服务器。
它看起来很简单,但通常不是。 通过将所有内容耦合到一个位置,我们隐藏了复杂性,从而增加了不同实例之间出现差异的机会。
当服务器收到新版本时,重新启动服务器的时间可能很长。 在此期间,服务器通常不运行。 新版本引发的停机时间是金钱和信任的损失。 当今的业务要求我们在不停机的情况下进行24/7全天候运营,正式投产意味着团队夜间工作,而在此期间我们无法提供服务,这并不罕见。
测试也是一个问题。 无论我们在开发和测试环境上对发行版进行了多少测试,首次在生产环境中进行试用都是在我们对其进行部署时,不仅使其对我们的测试人员而且对所有用户都可用。
而且,在这样的服务器上快速回滚几乎是不可能的。 由于它是可变的,因此没有以前版本的“照片”。
通过拥有这样的体系结构,我们无法满足上一篇文章中描述的所有要求。 由于无法产生零停机时间和容易回滚,我们无法经常部署 。 完全自动化由于其体系结构的可变性而具有风险,因此妨碍了我们的快速发展 。
通过不经常部署,我们积累了将要发布的变更,从而增加了失败的可能性。
为了解决这些问题,我们应该是一成不变的,并由小型,独立和自给自足的应用程序组成。 请记住,我们的目标是经常部署,停机时间为零,能够回滚任何发行版,实现自动化且快速。 此外,我们应该能够在实际用户看到生产版本之前对其进行测试。
不可变的服务器和反向代理
每个“传统”部署都会带来与需要在服务器上执行的更改相关的风险。 如果我们将体系结构更改为不可变的部署,那么我们将立即受益。 由于无需考虑应用程序(它们是不可更改的),因此环境的配置变得更加简单。 每当我们将映像或容器部署到生产服务器时,我们都知道它与我们构建和测试的映像或容器完全相同 。 不变的部署减少了与未知相关的风险。 我们知道,每个部署的实例都与另一个完全相同 。
反向代理可用于完成零停机时间。 不可变的服务器以及简化形式的反向代理可以紧随其后。
首先,我们从指向我们服务器的反向代理开始。 代理没有什么特别之处,除了所有流量都通过它路由而不是直接暴露服务器。
一旦决定部署新版本,我们将通过部署服务器的单独实例来完成。 目前,我们有两个实例。 一个旧的(以前的版本)和一个新的(最新版本)。 所有流量仍然通过反向代理到达旧服务器,因此我们应用程序的用户仍然不会注意到任何更改。 对于他们来说,我们仍在运行经过验证的旧软件。 这是运行最后一组测试的好时机。 优选地,那些测试是自动的并且是部署过程的一部分,但是不排除手动验证。 例如,如果对前端进行了更改,我们可能要进行最后一轮的用户体验测试。 无论执行哪种类型的测试,它们都应绕过反向代理“攻击”新版本。 这些测试的好处是我们正在使用驻留在生产硬件上的软件的未来生产版本。 我们正在测试生产软件和硬件,而不会影响我们的用户(它们仍被重定向到旧版本)。 我们甚至可以通过A / B测试的形式仅对有限数量的用户启用我们的新版本。
总而言之,在此阶段,我们有2个服务器实例,一个实例(以前的版本)供用户使用,另一个实例(最新版本)用于测试。
一旦完成测试并确信新版本可以按预期工作,我们要做的就是更改反向代理以指向新版本。 旧版本可以保留一段时间,以防我们需要回滚更改。 但是,对于我们的用户而言,它不存在。 所有流量都路由到新版本。 由于最新版本是在更改路由之前运行的,因此交换机本身不会中断我们的服务(例如,与在可变部署的情况下需要重新启动服务器不同)。 更改路由后,我们需要重新加载反向代理。 例如, NGINX会维持旧的连接,直到所有连接都切换到新的路由为止。
最后,当我们不需要旧版本时,可以将其删除。 更好的是,我们可以让下一个版本为我们删除它。 时间到了,发布过程将删除较旧的版本,然后重新开始该过程。
上述技术被称为蓝绿色部署 ,并且已经使用了很长时间。
不变的微服务
我们可以做得更好。 通过不可变的部署,我们可以轻松实现流程的自动化。 反向代理使我们的停机时间为零,并且有两个版本可以运行,这使我们可以轻松回滚。 但是,由于我们仍在处理一台大型服务器,因此部署和测试可能需要很长时间才能运行。 这本身可能会阻止我们快速发展,从而无法根据需要进行频繁部署。 此外,将所有内容都作为一台大服务器会增加开发,测试和部署的复杂性。 如果可以将事情分成较小的部分,我们可以将复杂性分为易于管理的部分。 另外,拥有小的独立服务将使我们更容易扩展。 可以将它们部署到同一台计算机上,在整个网络上进行扩展,如果其中之一的性能成为瓶颈,则可以成倍增加。 微服务营救!
微服务是一种架构方法,可将单个应用程序开发为一组小型且可能的话独立的服务。 当我们的微服务之一更新时,我们可以对其进行部署,并保持系统的其余部分不变。
对于“怪物应用”,我们倾向于将层分离。 前端代码应与后端分离,业务层与数据访问层等分离。使用微服务,我们应该开始朝着不同的方向思考。 虽然后端和前端应该分开,但是后端本身可以垂直切成薄片。 与其将业务层与数据访问层分开,我们将服务分开。 例如,用户管理可以与销售服务分开。 另一个区别是物理上的。 尽管传统架构在包和类的级别上分开,但仍将所有内容部署在一起,但微服务在物理上是分开的。 用户管理和销售服务的先前示例将在单独的项目中开发,作为单独的实例和流程进行部署和测试。 它们甚至可能不在同一台物理计算机上。
微服务的部署遵循与前述相同的模式。
我们将微服务部署为任何其他软件。
当发布某个微服务的新版本时,我们将其与旧版本一起部署。
在正确测试了该微服务版本之后,我们会更改路由。
最后,我们删除了旧版本的微服务。
现在,我们可以真正真正地经常自动地进行部署,零停机时间和发生故障时可以快速回滚以防万一。
从技术上讲,这种体系结构可能会带来某些问题,这将成为下一篇文章的主题。 我们将亲自实践持续部署的实际实现。
翻译自: https://www.javacodegeeks.com/2014/12/continuous-deployment-strategies.html