是否可以基于Docker和Kubernetes构建最酷的架构?本文将带你踏上一段架构之旅,并解释你一路上遇到的各种问题。现在,我们走吧!在Docker和Kubernetes时代,软件开发的世界发生了怎样的变化?是否有可能使用这些技术构建一个一次性的架构?一切都“打包”到容器中,是否可以统一开发和集成流程?这些决定的需求是什么?他们施加了什么限制?它们是否让开发人员的生活更轻松,或者相反,增加了不必要的复杂性?现在是时候在文本和原始插图中阐明这些问题和其他问题了!本文将带您踏上从现实生活到开发过程再到架构再回到现实生活的旅程,并回答您在沿途这些站点遇到的最重要的问题。我们将尝试确定一些应该成为架构一部分的组件和原则,并在不进入其实现领域的情况下演示一些示例。文章的结论可能让你心烦意乱,也可能让你很开心,这完全取决于你的经历,你对这三章故事的看法,甚至阅读本文时的心情。请在下方发表评论或提问,让我知道您的想法!从现实生活到开发工作流程在大多数情况下,我所见过或有幸构建的所有开发流程都只有一个简单的目标——缩短概念生成和交付到生产环境之间的时间间隔,同时保持一定的代码水平质量。这个想法是好是坏并不重要。因为坏主意来得快去得也快——你只需要尝试一下,然后把它们扔进一堆旧论文中。在这里值得一提的是,从一个坏主意中回滚可能落在自动化设施的肩上,它可以使您的工作流程自动化。持续集成和交付看起来像是软件开发领域的救星。什么可以更简单?如果您有想法并且有代码,那就去做吧!集成和交付流程相对难以从公司特定的技术和业务流程中分离出来。然而,尽管这项任务看起来很复杂,但生活中时不时地会提出绝妙的想法,这些想法可以使我们(当然我相信)更接近于构建一个完美无缺且可用的机制。对我来说,最接近这种机制的步骤是Docker和Kubernetes,它们的抽象层次和思维方式让我觉得现在80%的问题都可以用几乎相同的方式解决。剩下的20%的问题显然还在原地,但正因为如此,你可以将内在的创造力集中在有趣的工作上,而不是处理重复的例行公事。只需关注一次“架构框架”,您就会忘记大约80%的已经解决的问题。这是什么意思呢?而Docker又是如何解决开发工作流程的问题的呢?让我们看一个简单的过程,它足以满足大多数工作环境:通过适当的方法,您可以自动化和集成上面序列图中的所有内容,并在接下来的几个月内忘记它。设置开发环境一个项目应该包含一个docker-compose.yml文件,这样您就不必考虑在本地机器上运行您的应用程序/服务要做什么以及如何做。一个简单的命令docker-composeup应该启动你的应用程序及其所有依赖项,用固定装置填充数据库,上传容器内的本机代码,为即时编译启用代码跟踪,最后开始响应所需的请求港口。即使在设置新服务时,您也不必担心如何启动它、在哪里提交更改或使用哪个框架。所有这些都应该在标准规范中预先描述,并由针对不同设置的服务模板指定:前端、后端和工作者。自动化测试关于“黑匣子”(更多关于我为什么称呼容器,将在本文后面阐明)你想知道的是它里面的一切都完好无损,不是,1或0。你可以执行容器内的命令数量有限,虽然docker-compose.yml描述了它的所有依赖项,但您可以轻松地自动化和集成这些测试,而无需过多关注实现细节。像这样!在这里,测试不仅仅是单元测试,还包括功能测试、集成测试、(代码风格)测试和复制、检查过时的依赖和使用包的许可证等。重点是所有这些都应该封装在一个Docker中图像。系统交付何时何地安装您的项目并不重要。结果就像安装过程一样,应该是一致的。对于您正在安装整个生态系统的哪一部分或您将从哪个Git存储库获取代码,这也没有区别。这里最重要的组成部分是幂等性。应该指定的是控制安装过程的变量。这是我的算法,在解决这个问题方面效果很好:从所有Dockerfiles收集图像(例如这样)使用元项目,通过KubeAPI将这些图像交付给Kubernetes。启动交付通常需要几个输入参数:KubeAPI端点一个“秘密”对象,它因不同的环境(本地/测试/暂存/生产)而异公开的系统的名称和针对这些系统的Docker映像的标签(在上一步中获得)作为覆盖所有系统和服务的元项目的示例(换句话说,一个描述生态系统如何编排以及更新如何交付的项目),我更喜欢使用Ansible剧本,通过这个与集成的KubeAPI通信的模块。但是,复杂的自动化可以参考其他选项,稍后我将详细讨论我的选项。但是,您必须考虑集中/统一管理结构的方式。这种方式将使您能够方便、统一地管理所有服务/系统,并消除可能因即将出现的执行类似功能的技术和系统丛林而产生的任何复杂情况。通常,需要以下安装环境:测试环境集成和交付的连续性如果您有一个统一的方法来测试Docker镜像——或“黑盒”——您可以假设这些测试结果将允许您无缝地(并与一个问心无愧的)将功能分支集成到Git存储库的上游或主分支中。也许,这里的交易破坏者是集成和交付的顺序。如果没有发布,您如何防止具有一组并行功能分支的系统出现“竞争条件”?因此,只有在没有竞争条件的情况下才启动该过程,否则会想到“竞争条件”:尝试更新上游的功能分支(gitrebase/merge)从Dockerfiles构建图像从测试所有构建的图像开始,等到系统交付从步骤2构建的图像。如果上一步失败,生态系统将回滚到之前的状态。功能分支被合并到上游并发送到存储库。任何一步的失败都应该终止交付过程并将任务返回给开发人员以解决错误,无论是测试失败还是合并冲突。您可以使用此过程来处理多个存储库。只需对所有存储库执行一次每个步骤(代码库A和B的第1步,代码库A和B的第2步,等等)而不是为每个单独的存储库重复整个过程(代码库A的第1-6步,第1-步-6用于代码库B等)。此外,Kubernetes允许您批量推出更新以进行各种AB测试和风险分析。Kubernetes在内部是通过分离服务(访问点)和应用程序来实现的。您始终可以按所需比例平衡旧版本和新版本的组件,以促进问题分析并为潜在的回滚提供途径。系统回滚架构框架的强制性要求之一是能够回滚任何部署。反过来,这需要一些明确和隐含的细微差别。以下是其中一些最重要的:服务应该能够设置其环境并回滚更改。比如数据库迁移,RabbitMQschema等,如果环境不能回滚,服务应该是多态的,同时支持新旧版本的代码。例如:数据库迁移不应破坏旧版本(通常是2或3个以前的版本)向后兼容任何服务更新的服务。通常,这是API兼容性、消息格式等。在Kubernetes集群中回滚状态非常简单(运行kubectlrolloutundodeployment/some-deployment并且Kubernetes将恢复以前的“快照”),但要使其工作,您的元项目应该包含关于这个快照的信息。但更复杂的交付回滚算法令人望而生畏,尽管它们有时是必要的。以下是可以触发回滚机制的因素:发布后高比例的应用程序错误来自关键监控点的信号失败的冒烟测试手动模式-人为因素保护信息和审计没有工作流可以神奇地“构建”“无懈可击的安全性并保护您的生态系统免受外部和内部威胁,您需要确保您的架构框架在每个级别和所有子系统中都按照公司标准和安全策略实施。我将在后面有关监控和警报的章节中讨论的所有三个级别的解决方案本身都是至关重要的为了系统的完整性,Kubernetes内置了一套很好的访问控制、网络策略、事件审计等与信息安全相关的强大工具,可以用来构建良好的保护边界,抵御和防止数据泄露。将开发过程与生态系统紧密结合的想法应该认真考虑从开发过程到架构。将这种集成的需求添加到体系结构的传统要求集(弹性、可扩展性、可用性、可靠性、抵御威胁等)中可以大大增加体系结构框架的价值。这是一个至关重要的方面,导致了称为“DevOps”(开发运营)的概念,这是实现完全自动化和优化基础设施的合乎逻辑的一步。但是,借助设计良好的架构和可靠的子系统,可以最大限度地减少DevOps任务。微服务架构没有必要详细讨论面向服务的架构——SOA的好处,包括为什么服务应该是“微的”。我只想说,如果你决定使用Docker和Kubernetes,那么你可能会理解(并接受)单一应用程序架构是困难的,甚至是根本错误的。Docker旨在运行一个进程并使其持久化。Docker使我们能够专注于DDD框架(领域驱动开发)内的思考。在Docker中,打包代码被视为带有一些暴露端口的黑盒。生态系统的关键组件和解决方案根据我设计高可用性和可靠性系统的经验,有几个组件对微服务的运维至关重要,我将在后面列出和讨论这些组件,我将在Kubernetes环境,并将我的清单作为任何其他平台的清单。如果您(像我一样)得出这些组件作为常规Kubernetes服务进行管理的结论,那么我建议在与您的“生产环境”不同的集群中运行它们。就像一个“暂存”集群,因为当您的生产环境不稳定并且您迫切需要其图像、代码或监控工具的来源时,它可以节省您的时间。可以说,这解决了先有鸡还是先有蛋的问题。身份验证像往常一样,它从访问开始——服务器、虚拟机、应用程序、办公室电子邮件等。如果您是或希望成为主要企业平台之一(IBM、谷歌、微软)的客户,访问问题将是由提供商的一项服务处理。但是,如果您想拥有自己的解决方案,是否只能由您自己管理并在您的预算范围内?此列表可帮助您确定合适的解决方案并估算安装和维护所需的工作量。当然,你的选择必须符合公司的安全政策,并得到信息安全部门的批准。自动化服务配置虽然Kubernetes只需要物理机/云虚拟机上的少量组件(Docker、kubelet、kubeproxy、etcd集群),但对于新机器的加入和集群管理,仍然需要自动化。以下是一些简单的方法:KOPS-该工具允许您在两个云提供商(AWS或GCE)之一上安装集群Teraform-这允许您管理任何环境的基础设施并遵循IAC(基础设施设施即代码)理念Ansible——适用于任何类型的通用自动化工具就个人而言,我更喜欢第三种选择(带有Kubernetes集成模块),因为它允许我使用服务器和Kubernetes对象并执行任何类型的自动化。但是,没有什么能阻止您使用Teraform及其Kubernetes模块。KOPS在“裸机”上效果不佳,但它仍然是与AWS/GCE一起使用的工具!Git存储库和任务跟踪器对于任何Docker容器,使其日志可访问的方法是将它们写入容器中运行的根进程的STDOUT或STDERR。服务开发人员不关心日志数据旁边会发生什么,但主要是它们应该在必要时可用,并且包含过去某个时间点的记录。满足这些期望的所有责任都由Kubernetes和支持生态系统的工程师承担。在官方文档中,您可以找到有关处理日志的基本(和好的)策略的说明,这将帮助您选择用于聚合和存储大量文本数据的服务。在推荐的日志系统服务中,同一文档提到了用于收集数据的fluentd(当作为集群每个节点上的代理启动时)和用于存储和索引数据的Elasticsearch。尽管您可能不同意此解决方案的效率,但考虑到它的可靠性和易用性,我认为这至少是一个好的开始。Elasticsearch是一个资源密集型解决方案,但它的扩展性很好,并且有现成的Docker镜像,可以在单个节点上运行,也可以在所需大小的集群上运行。即使代码很好,跟踪系统也会崩溃,然后您想在生产中非常仔细地查看它们并尝试理解“如果在我的本地机器上一切正常,那么生产中发生了什么错误?”。诸如缓慢的数据库查询、不正确的缓存、缓慢的磁盘或与外部资源的连接、生态系统中的事务、瓶颈和规模不足的计算服务等都是您必须跟踪和估计实际负载下代码执行时间的原因。Opentracing和Zipkin足以胜任大多数现代编程语言的这项任务,并且不会在包装代码后增加额外的负担。当然,所有收集到的数据都应该存储到位并作为一个组件使用。上述开发标准和服务模板可以解决通过服务、消息队列、数据库等封装代码和转发“TraceID”时出现的复杂情况,后者还允许方法上的一致性。监控和告警Prometheus已经成为现代监控系统的事实标准,更重要的是,它在Kubernetes上具有开箱即用的支持。您可以参考Kubernetes官方文档了解更多关于监控和告警的信息。监控是集群内必须安装的少数辅助系统之一,集群是一个被监控的实体。但是监控系统的监控(抱歉冗长)只能在外部进行(例如,从相同的“暂存”环境)。在这种情况下,交叉检查可以作为任何分布式环境的便捷解决方案,而不会使高度统一的生态系统架构复杂化。整个监控范围在逻辑上可以分为三个完全隔离的层次。这是我认为每个级别最重要的跟踪点的示例:物理层:网络资源及其可用性-磁盘(I/O,可用空间)-单个节点的基本资源集群(CPU,RAM,LA)层:-每个节点上主集群系统的可用性(kubelet、kubeAPI、DNS、etcd等)-可用资源的数量及其均匀分布-监控允许的可用资源相对于服务消耗的实际资源-pods重新加载服务层:-任何类型的应用程序监控-从数据库内容到API调用频率-API网关上的HTTP错误数量-队列大小和工作人员利用率-数据库的多个指标(复制延迟、时间和事务数量,慢请求等)-非HTTP进程的错误分析-监控发送到日志系统的请求(可以将任何请求转换为指标)至于每个级别的警报通知,我想推荐一个我无数次使用过的那些可以发送通知电子邮件、短信或拨打手机号码的外部服务。我还会提到另一个系统-OpsGenie-它与Prometheus的alertmanaer紧密集成。OpsGenie是一种弹性警报工具,有助于升级、24/7工作、通知渠道选择等。在团队之间分发警报也很容易。例如,不同级别的监控应该向不同的团队/部门发送通知:物理-Infra+Devops,集群-Devops,应用程序-每个相关团队。API网关和单点登录要处理授权、身份验证、用户注册(外部用户-企业客户)和其他类型的访问控制等任务,您需要高度可靠的服务来保持与API网关的弹性集成。使用与身份服务相同的解决方案没有什么坏处,但您可能需要将这两种资源分开以获得不同级别的可用性和可靠性。内部服务的集成不应该很复杂,你的服务不应该担心用户和彼此的授权和认证。相反,架构和生态系统应该有一个代理服务来处理所有通信和HTTP流量。让我们考虑一下与APIGateway集成的最合适的方式,即整个生态系统-令牌。这种方法适用于所有三种访问场景:从UI、从服务到服务以及从外部系统。接下来,接收令牌(基于登录名和密码)的任务由用户界面本身或服务开发人员完成。区分UI中使用的令牌的生命周期(较短的TTL)和其他情况(较长和自定义TTL)也是有意义的。以下是API网关解决的一些问题:从外部和内部访问生态系统服务(服务之间不直接通信)与单点登录服务集成:令牌转换和额外的HTTPS请求,其标头包含所请求服务的用户身份数据(ID,role,andotherdetails)-根据从单点登录服务接收到的角色启用/禁用对请求服务的访问控制HTTP流量的单点监控不同服务的复合API文档(例如复合Swagger的json/yml文件)能够根据域和请求的URI管理整个生态系统的路由外部流量的单一入口点,以及与访问提供者的集成事件总线和企业集成/服务总线如果您的生态系统包含数据数百个服务可能在一个宏域中工作,您必须处理数千种可能的服务通信方式。为了简化数据流,您应该能够在特定事件发生时将信息分发给大量接收者,而不管事件的上下文如何。换句话说,您需要一个事件总线来发布基于标准协议的事件并订阅它们。作为事件总线,您可以使用任何可以运行所谓代理的系统:RabbitMQ、Kafka、ActiveMQ等。通常,数据的高可用性和一致性对于微服务至关重要,但由于CAP定理,您仍然必须为适当的总线分配和集群牺牲一些东西。自然地,一个事件总线应该能够解决各种服务到服务的通信问题,但是随着服务数量从几百个增长到几千甚至几万个,即使是基于事件总线的架构也变得望而却步,您将需要找到另一种解决方案。一个很好的例子是集成总线方法,它可以扩展上述“哑管道-智能消费”策略的功能。使用“企业集成/服务总线”方法有很多原因,该方法旨在降低面向服务架构的复杂性。以下是一些原因:聚合多个消息将一个事件拆分为多个事件协调系统响应事件的同步/事务分析接口,这对于与外部系统集成尤为重要事件路由的高级逻辑与多种服务集成(外部和内部)数据总线的不可扩展集中化作为企业集成总线的开源软件,您可能需要考虑ApacheServiceMix,它包含对此类SOA的设计和开发至关重要的几个成分。数据库和其他有状态服务与Kubernetes一样,Docker一次又一次地改变了所有需要数据持久化并与磁盘紧密绑定的服务的游戏规则。有人说服务应该以旧方式“存在”在物理服务器或虚拟机上。我尊重这个观点,不会谈论它的优缺点,但我相当肯定这个说法的存在只是因为暂时缺乏在Docker环境中管理有状态服务的知识、解决方案和经验。我还应该提到,数据库通常在存储领域占据中心位置,因此您选择的解决方案应该完全准备好在Kubernetes环境中工作。根据我的经验和市场情况,我可以区分以下几组有状态服务和最适合每种服务的Docker解决方案示例:Queues/MessageBroker-RabbitMQ是用于构建消息队列系统和路由消息的经典软件。RabbitMQ配置中的cluster_formation参数是集群设置必不可少的缓存服务——Redis被认为是最可靠和弹性的数据缓存解决方案之一全文搜索——我上面已经提到的Elasticsearch技术栈,最初用于全文搜索,但同样擅长存储日志和任何具有大量文本数据的工作文件存储服务-用于任何类型文件存储和传输(ftp、sftp等)的通用服务组。当您需要的包或依赖项具有已被删除或暂时不可用,不要假设这永远不会发生。为避免不必要的不??可用性并为内部系统提供安全性,请确保构建和交付服务都不需要Internet连接。配置镜像,将所有依赖复制到内网:Docker镜像、rpm包、源码仓库、python/go/js/php模块。这些和任何其他类型的依赖项都有自己的解决方案。最常见的可以用谷歌搜索查询“privatedependencymirrorfor...”。从结构到现实生活不管你喜不喜欢,你的整个结构迟早会变得不可持续。它总是会发生:技术很快就会过时(1-5年),方法和方法-有点慢(5-10年),设计原则和基础-偶尔(10-20年),但最终不可避免。考虑到技术过时,始终努力使您的生态系统保持在技术创新的顶峰,计划和推出新服务以满足开发人员、业务和最终用户的需求,向您的利益相关者推广新的实用程序提供知识以推动您的团队的计划和公司前进。通过与专业社区互动、阅读相关文献并与同事建立联系,让自己处于生态系统的顶端。留意项目中的新机会并正确使用新趋势。试验并应用科学方法来分析研究结果,或依赖您信任和尊重的其他人的结论。除非您是您所在领域的专家,否则很难为根本性的变革做好准备。在我们的整个职业生涯中,我们所有人只会见证一些重大的技术变革,但让我们登上顶峰的并不是我们头脑中的知识量,而是我们开放的心态和拥抱变革的能力。回到标题中的问题:“是否可以构建更好的架构?”。答案很明显:不,不是“一劳永逸”,而是一定要有进取心,在未来某个“很短的时间内”,你一定会成功!
