在我看来,Kubernetes的优势在于它的声明性与控制循环相结合,通过这些控制循环持续监控集群的活跃状态,以确保它与etcd[2]保持一致,以保持所需的状态一致。这种方式非常强大,但同时它的数据库仅限于etcd(etcd只提供有限的可观察性),影响了集群变更的可追究性和可审计性。另一个缺点是,将etcd和代码仓库作为两个SOT(sourceoftruth)使用可能会导致配置漂移,造成管理困难。开发者使用代码仓库安全可追溯的方式来保存代码,并开发了Workflows[3]来高效管理中央仓库。不同的团队可以并行工作,不会有太多的冲突,同时确保所有的变更都经过审计,并支持追溯和回滚。如果我们可以从围绕Git存储库构建的流程中获取这些好处并将它们扩展到基础设施或kubernetes中,那不是很好吗?首先说说什么是GitOps以及它是如何应用于Kubernetes的,然后看看在kubernetes中实现的GitOps声明式工具,最后再回顾一些GitOps友好的工具,即以代码形式实现和声明的工具。什么是GitOps?GitOps的目的是将etcd的这种声明性质扩展到Git存储库(代码保存的地方)并充当SSOT(单一事实来源)。这样,我们就可以利用Git带来的代码监控、历史变更、快速回滚、可追溯等优势。GitOps的核心思想是使用包含当前所需(生产环境基础设施)的声明性描述的GIt存储库,并自动化流程以确保生产环境与存储库中的所需状态一致。如果你想部署一个新的应用程序或更新一个现有的应用程序,你只需要更新相应的存储库(自动化过程会处理剩下的)。这就像使用巡航控制来管理您在生产中的应用程序。GitOps不仅限于Kubernetes,事实上它还可以通过将基础架构作为代码[4]持久化到GIt存储库中来将应用程序代码扩展到基础架构中,这通常由Terraform[5]等工具普及。Declarativeinfrastructureascode[6]在实现GitOps中扮演着重要的角色,但不仅限于此。GitOps围绕Git构建整个生态系统和工具,并将其应用于基础设施。仅在Git中使用Terraform并不能保证基础设施的状态与生产环境保持一致。还需要持续运行Terraform命令(trrraformapply)实时监控版本变更,实现流水线中的人工审批等功能。GitOps的理念是持续监控集群的状态,并与Git仓库进行对比,当配置不一致时立即采取相应的动作,防止配置漂移。最重要的是,您可以获得Git的好处,例如通过代码监视进行手动批准。对我来说,这些概念是革命性的,如果使用得当,组织可以更专注于功能并减少自动化脚本。这个概念可以扩展到软件开发的其他领域,例如在代码中存储文档以跟踪历史变化并确保文档及时更新;或使用ADR[7]来跟踪架构决策。Kubernetes中的GitopsKubernetes从一开始就有控制循环的思想,也就是说Kubernetes会一直监控集群的状态,确保达到想要的状态。例如,将运行的副本数与预期的副本数相匹配。将GitOps的概念扩展到应用,让服务可以定义为代码,例如定义Helm[8]Charts,通过K8s提供的功能,使用一个监控Apps状态的工具,调整相应的集群状态,即更新了代码仓库,或者说更新了生产集群的helmchart。这才是真正的持续部署。其核心原则是应用程序部署和生命周期管理应该是自动化的、可审计的和可理解的。每个环境都应该有一个代码存储库,用于定义给定集群的所需状态。然后KubernetesOperators将继续监控特定分支(通常是master分支),当他们检测到Git中的变化时,他们会将变化传播到集群并更新etcd中的状态。这样,etcd只是作为数据库使用,而不是唯一的SOT。应用程序的Helm图表可以在包含声明性Kubernetes基础设施的Git存储库中定义。此外,可以链接存储库,以便一个人可以监视另一个存储库,等等。KubernetesGitOps工具可以监控其他仓库(比如HelmChart仓库)的状态,让你的集群环境仓库不需要包含HelmChart,你只需要连接到Helm仓库,使用这个链接进行监控它的变化,这样当你发布一个新的图表时,图表会在稍后自动部署到集群中。以这种方式自动化端到端声明式CI/CD管道。声明式GitOps工具如果考虑在Kubernetes上使用GitOps,则需要讨论在Kubernetes上实现GitOps原则的工具(负责监控Git的状态并将其同步到集群)。ArgoCD在我看来,Kubernetes上最好的GitOps工具是ArgoCD[9]。ArgoCD是Argo生态系统的一部分,其中包括许多很棒的工具,稍后将讨论。使用ArgoCD,每个环境的所有配置都可以在代码库中定义。ArgoCD在特定的目标环境中自动部署所需的应用程序状态。ArgoCD充当kubernetes控制器,持续监控正在运行的应用程序并将当前活动状态与所需目标状态进行比较(如Git存储库中所述)。ArgoCD将报告并呈现这种差异,并自动或手动将实时状态同步到所需的目标状态。**ArgoCD**具有出色的UI,支持SSO,安全、可扩展且易于使用。FluxFlux[10]是除了ArgoCD之外另一个非常有名的项目。最近的版本包含许多改进,并且在功能上与ArgoCD非常接近,Flux是一个CNCF孵化项目。GitOps工具在本节中,我回顾了一些我最喜欢的GitOps友好(即,基于CRD)的工具。helmHelm不用多说,是Kubernetes上最著名的包管理器。当然,你应该像在编程语言中使用包一样使用K8s中的包管理器。Helm允许使用Charts打包应用程序,将复杂的应用程序抽象为简单的、可重用的组件,以便于定义、安装和升级。它还提供了一个强大的模板引擎,Helm非常成熟,它包含很多预定义的图表,强大的支持,简单易用。Helm与A??rgoCD或Flux集成良好,可以监控Helm存储库的变化并在新图表发布时进行部署。这个想法是将ArgoCD或Flux指向Helm存储库并指定特定版本或通用版本。如果您使用通配符版本,则在发布新版本后将进行自动部署。您可以使用主要或次要版本名称。我通常倾向于将应用程序打包成图表,将其构建为CI/CD的一部分,并让ArgoCD监控特定的存储库。这种关注点分离允许开发人员在与环境无关的存储库中管理应用程序,并让ArgoCD选择在哪个环境中部署哪些图表。您可以使用多个Helm存储库并为不同的环境推送更改。例如,合并PR后,您可以执行“bronce”构建,将Helm图表发布到名为“bronce”的存储库。开发环境的ArgoCD存储库指向“bronce”存储库,并在可用时部署新版本。暂存环境的ArgoCD存储库将指向名为“silver”的存储库,而生产环境将指向名为“gold”的存储库。当需要将某些东西推送到暂存或生产环境时,CI/CD只需要将图表发布到下一个仓库即可。ArgoCD可以覆盖任何环境的特定Helm值。Kustomize[11]是一种新的helm替代品,它不需要模板引擎,而是使用带有基本定义和覆盖层的覆盖引擎。ArgoWorkflows和ArgoEvents在Kubernetes中,您可能需要运行批处理作业或复杂的工作流作为数据处理管道、异步处理或CI/CD的一部分。此外,您可能需要运行驱动程序微服务来响应特定事件,例如文件上传或向队列发送消息。为了实现这些功能,可以使用ArgoWorkflows[12]和ArgoEvents[13]。尽管它们是独立的项目,但它们往往会一起部署。ArgoWorkflows是一个类似于ApacheAirflow[14]的编排引擎,但原生适用于Kubernetes。它使用CRD来定义复杂的工作流(使用YAML来表示步骤或使用DAG[15]来表达工作流)。它还具有良好的UI,支持重试机制、计划任务、输入和输出跟踪等。您可以使用它来编排数据处理管道、批处理任务等。有时您可能希望将您的管道与Kafka等异步服务集成、队列、webhooks或底层存储服务。例如,您可能想要响应将文件上传到S3之类的事件,在这种情况下,您可以使用ArgoEvents。以上两个工具为需要CI/CD流水线的人提供了一个简单而强大的解决方案,可以在Kubernetes上运行CI/CD流水线。ArgoWorkflows与ArgoCD集成良好,因为所有工作流定义都可以打包到Helm图表中。对于ML管道,可以使用Kubeflow[16]来实现相同的目的。对于CI/CD管道,可以使用Tekton[17]。IstioIstio[18]是市场上最著名的服务网格[19],它是开源的并且非常流行。由于服务网格很大,我不会在这里讨论细节,但如果你正在构建微服务,你可能需要一个服务网格来管理通信、可观察性、错误处理、安全性和(作为微服务的一部分架构。)其他交叉方面。使用服务网格可以避免重复逻辑污染微服务代码。简而言之,服务网格是一个特定的基础设施层,您可以在其上添加允许透明地添加可观察性、流量管理和安全性的应用程序,而无需自己实现这些功能。Istio使用CRD来实现其所有功能,因此可以将虚拟服务、网关、策略等打包为Helm图表中的代码,并且可以使用ArgoCD或Flux使IstioGitOps友好(尽管功能不那么强大)。也可以使用Linkerd[20]或Consul[21]作为Istio的替代品。ArgoRollouts如上所述,您可以使用Kubernetes通过ArgoWorkflows或类似工具运行CI/CD管道。下一个合乎逻辑的步骤是执行持续部署,但实际上,由于其高风险,大多数公司只做持续交付,这意味着他们可以将其自动化,但仍然使用手动方法进行审批和验证,这种手动的根本原因步骤是这些团队不能完全信任他们的自动化。那么你如何建立这种信任级别来避免脚本并完全自动化从代码到生产。答案是:可观察性。您需要关注资源指标并收集所有数据以准确传达应用程序的状态,即使用一组指标来建立信任。如果Prometheus包含所有数据,那么你就可以自动化部署,因为此时你可以实现基于指标的滚动更新应用。简单的说,你可以使用K8s提供的开箱即用的高级部署技术——滚动升级。我们需要使用金丝雀部署来实现渐进式发布。目的是逐步将流量路由到新版本的应用程序,等待收集指标,然后根据预先定义的规则进行分析和匹配。如果检查正常,则增加流量;如果发现问题,请回滚部署。可以使用ArgoRollouts[22]在Kubernetes上实施Canaryrollouts。ArgoRollouts是一个Kubernetes控制器,它使用一组CRD提供高级部署能力,例如蓝绿、金丝雀、金丝雀分析、实验等,并向Kubernetes提供渐进式交付能力。虽然像Istio这样的服务网格可以提供金丝雀发布,但Argo发布简化了流程并且以开发人员为中心。除此之外,ArgoRollouts可以集成到任何服务网格中。ArgoRollouts对GitOps友好,并与ArgoWorkflows和ArgoCD很好地集成。使用这三个工具可以创建一个非常强大的声明式部署工具集。Flagger[23]与ArgoRollouts非常相似,并且与Flux[24]集成得很好,所以如果你正在使用Flux,可以考虑使用Flagger。CrossplaneCrossplane[25]是我最近最喜欢的K8s工具,它填补了Kubernetes中的一个关键空白:将第三方服务作为K8s资源进行管理。这意味着您可以使用YAML中定义的K8s资源来配置来自云提供商(例如AWSRDS或GCP云SQL)的数据库,就像在K8s中配置数据库一样。使用Crossplane,无需使用不同的工具和方法来分离基础架构和代码。您可以使用K8s资源定义所有内容。这样,您就不需要学习和保留单独的工具,例如Terraform[26]。Crossplane是一个开源Kubernetes扩展,它允许平台团队组合来自多个供应商的基础设施,并为应用程序团队提供更高级别的自助服务API(无需编写一行代码)。Crossplane使用CRD扩展Kubernetes集群以提供基础设施或管理云服务。此外,与Terraform等工具相比,它可以完全自动化部署。Crossplane使用开箱即用的K8s功能,例如使用控制循环持续监控集群并自动检测配置漂移。例如,如果定义了一个可管理的数据库实例,随后有人手动更改了它,Crossplane会自动检测到问题并将其设置回以前的值。它以代码的形式实现基础设施,并按照GitOps原则执行。Crossplane可以与ArgoCD一起监控源代码并确保代码库是唯一的信任源(SOT),代码的任何更改都将传递到集群和外部云服务。如果没有Crossplane,你可以在K8s服务中实现GitOps,但是你无法在不进行额外处理的情况下在云服务中实现GitOps。KyvernoKubernetes为敏捷自治团队提供了极大的灵活性,但能力越大,责任也越大。必须有一套最佳实践和规则来确保部署的一致性和连贯性,并使工作负载符合公司要求的策略和安全性。Kyverno[27]是为Kubernetes设计的策略引擎,它可以像管理Kubernetes资源一样管理策略,而无需使用新的语言来编写策略。Kyverno策略可以验证、修改和生成Kubernetes资源。Kyverno策略是一组规则,每个规则包含一个匹配子句、一个排除子句和一个验证、变异或生成子句。一个规则定义只能包含一个validate、mutate或generate子节点。您可以配置有关最佳实践、网络或安全性的任何策略。例如,可以强制所有包含标签的服务或所有容器以非root权限运行。策略可以应用于整个集群或特定的命名空间。您可以选择是要审核策略还是强制执行策略以防止用户部署资源。KubevelaKubernetes的一个问题是开发人员需要了解并了解平台和集群配置。许多开发者抱怨K8s的抽象层次太低,因此在那些只关心编写和交付应用程序的开发者中存在争议。开放应用模型(OAM[28])可以解决这个问题。它的想法是围绕应用程序创建一个更高级别的抽象,它独立于底层运行时。.通过专注于应用程序而不是容器或编排器。OAM带来了模块化、可扩展和可移植的设计,通过更高级别和一致的API对应用程序部署进行建模。Kubevela[29]是OMA模型的一个实现。KubeVela与运行时无关,可扩展,但最重要的是,它以应用程序为中心。在Kubevela中,应用程序是作为Kubernetes资源实现的一等公民。需要区分集群运维人员(平台团队)和开发人员(应用团队)。集群操作员通过定义组件(构成应用程序的可部署/可配置实体,例如helm图表)和特征来管理集群和不同的环境。开发人员通过组装组件和特征来定义应用程序。平台团队:将平台功能建模和管理为组件或特征以及目标环境规范。应用团队:选择一个环境,组装所需的组件和特征,并将其部署到目标环境。KubeVela是一个目前处于起步阶段的CNCF沙箱项目,在不久的将来,它可能会改变开发人员使用Kubernetes的方式,让他们更专注于应用程序本身。但我对OAM在现实世界中的适用性有些担忧,因为一些服务,如系统程序、ML或大数据处理,它们严重依赖底层细节,这种情况很难集成到OAM模型中。SchemaHero软件开发中的另一个常见过程是在使用关系数据库时需要管理模式演变。SchemaHero[30]是一个开源的数据库模式迁移工具,可以将模式定义转换为可以在任何环境中运行的迁移脚本。它使用Kubernetes的声明性功能来管理数据库架构迁移。您可以指定所需的状态,让SchemaHero管理其余部分。BitnamiSealedSecrets到目前为止,我们已经介绍了很多GitOps工具,我们的目标是将所有内容都保存在Git中,并使用Kubernetes的声明性功能来保持环境同步。我们可以(也应该)保证Git中的SOT,让自动化流程处理配置更改。通常难以保存到Git中的一种资源是机密,例如数据库密码或API密钥。一种常见的解决方案是使用外部“保险库”,例如AWSSecretManager[31]或HashiCorpVault[32]来存储这些秘密,但这也会产生冲突,您需要一个单独的过程来处理秘密。理想情况下,我们希望通过某种方式将秘密保存到Git中,就像保存任何其他资源一样安全。SealedSecrets[33]就是用来解决这个问题的。它允许您通过强加密将敏感数据存储在Git中。BitnamiSealedSecrets很自然地集成到Kubernetes中。您可以使用在Kubernetes中运行的Kubernetes控制器来解密密钥。不依赖其他组件。控制器可以解密数据并创建原生K8s秘密资源。这样,一切都可以作为代码保存在仓库中,不依赖外部资源就可以安全地进行持续部署。SealedSecrets由两部分组成:集群端controller客户端程序:kubesealkubeseal程序采用非对称加密方式对secret进行加密,只有controller才能解密。这些加密的秘密被编码到K8sSealedSecret资源中(可以保存到Git中)。Capsule许多公司使用多租户来管理不同的客户,这在软件开发中很常见,但在Kubernetes中很难实现。一种方式是通过命名空间将集群划分为独立的逻辑分区,但用户不能完全隔离,需要引入网络策略、配额等。您可以在每个命名空间中创建网络策略和规则,但这是一个无法扩展的繁琐过程,而且租户不能使用多个命名空间,这是一个很大的限制。分层命名空间[34]可用于解决这些问题。这是通过为每个租户分配一个父名称空间并为该租户配置通用网络策略和配额,并允许创建子名称空间来完成的。这是一个很大的改进,但缺乏对租户级别安全和治理的原生支持。此外,它尚未达到生产状态,但预计将在未来几个月内发布1.0版本。一种常见的方法是为每个客户创建一个集群,这种方法相对安全,可以为租户提供他们需要的一切,但管理起来既困难又昂贵。Capsule[35]是一种在单个集群中为Kubernetes提供多租户功能的工具。使用Capsule,您可以将所有租户放在一个集群中。Capsul将为租户提供“近乎”原生的体验(尽管有一些小限制),租户可以在其集群中创建多个命名空间。这种方法隐藏了多个租户共享底层集群的事实。在一个集群中,Capsulecontroller将多个命名空间聚合起来,抽象成一个轻量级的Kubernetes,称为租户,租户是一组Kubernetes命名空间。在每个租户中,用户可以创建自己的命名空间并共享分配的资源,策略引擎确保租户之间的隔离。租户级别定义的网络和安全策略、资源配额、LimitRanges、RBAC和其他策略会自动被租户中的所有命名空间继承,类似于分层命名空间。然后,用户可以在没有集群管理员干预的情况下自主操作租户。Capsel是GitOps,因为它是声明式的,所有配置都可以存储在Git中。
