1. 持续交付模型的三大基本原则(Gitops)

GitOps是一种实现持续交付的模型,它的核心思想是将应用系统的声明性基础架构和应用程序存放在的Git的版本控制库中。

目前比较有名的开源DevOps产品ArgoCD在构建持续交付流水线时参考了GitOps,并进行了实践。

应用GitOps最佳实践,应用系统的基础架构和应用程序代码都有“真实来源。” 其实是将基础架构和应用程序代码都存放在gitlab,或者github上等版本控制系统上这使开发团队可以提高开发和部署速度并提高应用系统可靠性。GitOps的好处有四:

◎ 更快速的开发,开发人员可以使用熟悉的 Git 工具,将应用部署到云环境,提高业务的敏捷度,快速地相应用户的需求,有助于增加企业市场的竞争力;

◎ 更好地进行运维, 借助 GitOps,可以实现一个完整的端到端的交付流水线。不仅可以实现拉式的持续集成流水线和持续部署流水线,而且系统的运维操作可以通过 Git 来完成;

◎ 更强大的安全保证, 几乎所有的 Git 库都提供角色和权限控制,与开发和运维无关的人员没有权限操作 Git 库。而不是直接把服务器或者集群的操作权限散发出去,这样特别容易引起安全泄露;

◎ 更容易合规的审计, 由于以安全的方式跟踪和记录更改,因此合规性和审计变得微不足道。

1.1 任何能够被描述的内容都必须存储在的Git库中

通过使用GIT中作为存储声明性基础架构和应用程序代码的存储仓库,可以方便地监控集群,以及检查比较实际环境的状态与代码库上的状态是否一致。所以,我们的目标是描述系统相关的所有内容:策略,代码,配置,甚至监控事件和版本控制等,并且将这些内容全部存储在版本库中。

在通过版本库中的内容构建系统的基础架构或者应用程序的时候,如果没有成功,则可以迅速的回滚,并且重新来过。现在在我们的Jenkins中,每个几分钟会对gitlab中的代码(应用代码、基础设置代码)做检查,发现有改变会立刻进行测试环境的部署,当然生产环境,你可以另当别论。

1.2 不应直接使用Kubectl

作为一般规则,不提倡在命令行中直接使用kubectl命令操作执行部署基础架构或应用程序到集群中。还有一些开发者使用CI工具驱动应用程序的部署,但如果这样做,可能会给生产环境带来潜在不可预测的风险,所以大家注意到,在生产系统中,我们使用spinnaker这个工具或其他CD工具。

1.3 调用Kubernetes的API的接口或者控制器应该遵循运营商模式

现在公有云使用很广泛,我们使用公有云上全托管的Kubernetes是个很好的选择,因为“钱”,公有云上全托管的Kubernetes的master节点是公有的,有很高的可用性,如果是你自建的Kubernetes集群,master节点起步3个,还不一定可靠,你说,是不是,光凭这点,全托管就是个不错的选择。作为运维人员在生产上首先考虑的是安全可靠,其次是尽可能的满足业务的需求,再次才是技术的创新自主。


2. 设计交付渠道

为了充分利用DevOps的敏捷性优势,需要实现带有容器的可插拔且适应性强的CI / CD管道。关于容器和CI / CD的讨论可能涉及以下一项或多项。

2.1 使用容器建立适应性强的CI / CD流水线

利用容器并获得所前面所讲的敏捷性优势需要CI工具提供的(1)自动化的功能,例如,构建服务器自动根据git中代码的更改,触发启动重新构建的任务。(2)在容器中运维CI服务器;(3)将容器作为代码包的“构建从属”,其实就是Jenkins中我们可以看到,我们可以以本Jenkins为master,重新启动一个docker作为slave。

2.2 持续集成和持续交付

CI的主要目的是更频繁地集成变更,以便快速向团队提供反馈。因此,CI的主要指令是软件系统必须始终编译,并且测试必须始终成功执行。CI克服了代码集成的挑战,同时提供了价值主张,可在软件开发生命周期的所有阶段将风险降至最低。

例如:通过频繁集成,有效的CI实践可以按计划和可重复的基础来生产功能性软件系统。Kubernetes通过滚动更新容器化服务来支持CD。通过其“部署”对象,Kubernetes通过声明运行服务的Pod的所需状态,帮助开发人员实现不同的更新模式。例如,将滚动升级声明为每个Pod版本的副本数所需状态的更改,如图

2.3 使用持续集成自动化和编排构建

应用程序开发和平台操作上的工作流程都应高度自动化。毕竟,大多数组织都在追求容器化,以提高敏捷性。为了更快地创建,更新,测试和部署应用程序,必须在流水线的每个阶段按需将所需的基础结构资源按需提供给工作负载。

开发发人员和平台运营将各自拥有一套自己的自动化流水线,分别用于交付应用程序和基础架构。开人员将使用多个流水线来交付不同的应用程序。还可以使用连续配置自动化(CCA)管道来供和更新支持CaaS平台所需的基础架构组件。这在Jenkins中,我们有多分支流水线提供给大家使用。

2.4 单元测试和功能验证

测试是及时构建和发布有效且可靠的软件的重要组成部分。一旦编排了容器化的工作负载,测试就尤为重要,因为“发布”可能包含多个容器化的服务,这些服务必须同时运行。使测试用例和使用场景自动化可以使团队缩短开发周期。自动化测试更快,更不容易出错,并且需要最少的手动交互。成功的开发团队会验证其应用程序的有效性,可靠性,安全性和性能,以确保质量。

2.5 安全性,合规性和验证

安全一直是早期采用容器的人们最关心的问题之一。因为容器化的工作负载共享主机内核,所以它们彼此隔离的方式与在完全独立的主机或VM上运行的工作负载的方式不同。容器不会阻止应用程序被破坏。但是,由于隔离性的减弱,会放大破坏性。这是因为应用程序和用户是按容器隔离的,因此只要主机操作系统上不存在内核特权提升漏洞,它们就不会危害其他容器或主机操作系统。而基础架构供应过程的自动化使主机OS中的安全实施更加简单和高效。

如果没有正确维护,测试和验证,则容器映像也可能会引入漏洞。因此,作为测试和验证过程的一部分, 必须定期检查映像中的所有基础层,使能层和应用程序代码层。Dockerfile中的命令按照您在运行“docker build”时在Dockerfile中声明的顺序执行。Dockerfile命令的顺序至关重要,因为Docker构建容器时,每个命令都对应于创建映像的新层。从本质上讲,因为每个Docker映像都是只读文件,所以和洋葱一样,每个新映像都是通过写时复制行为创建的,是通过在先前层之上连续覆盖新的只读层而制成的。


3. 分配新角色和职责

3.1 开发团队和运维团队的职责

将容器和Kubernetes带入CI / CD管道引入了一些新的职责。当前正在配置应用程序交付管道的团队将不得不开始询问以下问题:

◎ 谁来编写容器映像和清单文件?

◎ 文件将如何维护?

◎ 如果部署失败,或者必须应用更新或修复,将会发生什么?

图中显示了容器部署组件,并将其所有权分配给开发人员或操作员。左右面板应该不足为奇。我们已经确定开发人员负责编写应用程序代码。运维工程师管理支持这些应用程序的基础结构。他们的职责包括构建和维护服务器,存储和网络。随着容器的引入,开发人员必须创建Dockerfile,但是也必须有人配置和管理集群管理和编排系统。

3.2 编写部署清单文件的职责

但是,描述容器化服务部署的清单文件包括有关服务体系结构和基础结构详细信息的基本信息,这个关键的部署清单文件又如何呢?谁负责?部署清单是一个独特的工件,因为其创建需要开发和运营团队的协作。

这里有两种方案,一是部署清单由应用程序开发团队完全定义。它与容器映像一起移交给运维团队;二是部署清单由应用程序开发和运营团队共同定义。

第一种方案,这种类型的方法使开发团队会在公共云中部署和管理自己的工作负载,可以轻松地快速采用新的工作流程和技术。但是,在以下方面可能会遇到挑战和瓶颈,

◎ 控制基础设施成本

◎ 最终将生产部署的某些管理方面交给运维团队(可能缺少适当的技能)

所以,我们主张第二种方案,它体现了DevOps的精神,并迫使团队团结一致。在第二种方案中,开发人员以运维团队可以理解和使用的方式表达清单中与应用程序体系结构有关的所有方面。同样,作为基础基础结构和业务流程系统的所有者,运维工程师将构建清单的一部分,以与开发人员的愿景保持一致,同时遵守内部政策。

拥抱容器需要运维团队了解和学习开发的架构,而开发团队向运维靠近并了解运维的工具和技术。

3.3 实施平台运维以提供共享的容器平台

一旦多个DevOps团队组成并共享同一个容器管理平台,所有团队成员就应该接受平台的操作。通过这种方法,平台运维团队将容器管理平台视为将产品交付给客户,在这种情况下,客户是内部人员:开发和交付容器化应用程序的团队。

平台运维团队致力于为DevOps团队提供一个一致的平台来交付软件产品,并应用产品管理生命周期方法来计划和交付共享容器管理平台。当使用基于Kubernetes的容器管理平台实施平台操作时,可以为平台操作团队和DevOps团队明确定义操作责任范围。

如图所示,运维团队和开发团队共享容器平台

企业级部署容器应用程序的方法_java

实践DevOps的产品团队负责应用程序代码和Dockerfile,并且可能负有创建和更新Kubernetes部署清单的共同责任。然后,平台运营团队为实践DevOps的团队提供一个一致的平台,以在该平台上交付软件产品, 并应用产品管理生命周期方法来计划和交付共享容器管理平台,以下是他们的职责在其中的划分。

企业级部署容器应用程序的方法_java_02

在这里必须强调

◎ 需要应用程序开发与运维团队之间的紧密协作。无论您使用哪种特定的集成化的方案,孤零零的方法在这里都没有立足之地,并且会导致挫败感和敏捷性下降;

◎ 对所有团队都有意义的方式分配部署清单的责任,由于创建和维护这些文件需要开发团队和运维团队的广泛投入,因此需要DevOps方法将两个团队有机结合起来。

◎ 一旦组成多个实践DevOps的团队组成,就拥抱平台,并共享相同的容器编排平台。

3.4 自动化基础结构更新和升级的过程

因为容器会将应用程序与底层硬件分离,自动化基础架构配置非常重要。此外,无论是在虚拟主机还是裸机主机上,在本地还是在公共云中,容器的可移植性允许任何容器化的工作负载随时在任何基础架构上运行,这样,底层基础结构的准备应该与容器化应用程序的交付一样快。

虽然底层的基础结构可能不会随着容器的引入而发生很大变化,但是它将需要对一些新的组件和过程进行严格的处理。如何管理这些新方面的版本控制,更新和升级呢?

支持容器的运维团队必须具有技能和工具,能够自信且权宜地处理这两种情况,因为容器化带来了更多的责任,如图所示

企业级部署容器应用程序的方法_java_03

3.4.1 更新安装在物理或虚拟服务器上的容器主机操作系统

该操作系统最终将承载容器化的工作负载以及容器化的Kubernetes控制平面的各个部分。托管容器不需要明确要求特殊的操作系统,但是由于兼容性等原因,大多数客户更喜欢继续使用他们熟悉的操作系统。

3.4.2 更新在节点上创建容器的Container Runtime(CR)

最广泛使用的是 这样一个过程,kubelet –> Dockershim -> Docker daemon –> containerd,可以看到其中主要是Docker。Docker Container Runtime(称为Docker Engine)的更新经常发布,其中可能包含强大的新功能。每个运行容器的主机都需要容器运行时的最新版本。

3.4.3 更新容器编排系统

编排系统使容器化的应用程序可以根据放置和服务级别策略跨服务器集群部署。建立和管理该系统的过程通常是容器化计划中最困难的方面之一,因为它需要运维团队掌握全新的技能。

3.4.4 更新容器基础镜像

容器镜像是构建每个容器化服务和应用程序的基本构建块。如上一节所述,这些映像往往包括轻量级的OS以及任何库,以及容器中运行的软件的其他依赖关系。这些镜像可以直接从供应商或开源社区获得

3.5 容器编排自动缩放

Kubernetes中的关键自动化功能是能够在无需管理员干预的情况下响应不断变化的工作负载在群集中添加和删除资源。自动扩展可确保容器化工作负载连续提供所需的资源,以达到所需的性能和响应级别。Kubernetes平台中有三种可能的自动缩放类型:

3.5.1 水平Pod自动缩放(HPA)

在这种方法中,Kubernetes编排器根据用户静态或动态实施的预定义策略自动增加或减少集群上计划的Pod数量。

3.5.2 集群自动扩展

通过这种方法,Kubernetes编排器会自动重新配置集群中的工作节点,以确保集群中有合适数量的资源可用于容纳HPA。

3.5.3 垂直容器自动缩放(VPA)

在这种方法中,Kubernetes协调器可以根据监视工具的反馈在调度容器时为CPU和内存请求推荐值,或者可以自动更新CPU和存储器请求的值。

这些自动缩放方法的配置基于之前讨论的部署清单。选择正确的自动缩放方法或方法的组合,然后调整其设置将需要应用程序开发人员和运维人员之间的协作。

3.6 重点考虑点

3.6.1 自动化

在引入容器编排之前,自动化与基础架构配置和维护相关的运维任务,正如前面所讲过的HashiCorpTerraform之类的CCA工具。引入容器编排后,应用的部署也可以由诸如chef、Red Hat Ansible,Puppet之类的工具来部署,以实现对托管容器集群和基础架构的一体化控制,进一步提高持续管理的运营效率。

3.6.2 资源考虑

仅当您愿意在分布式系统工程上进行大量投资时,才选择编排容器的自我管理方法。如果您缺乏部署和操作容器编排平台的资源,请使用公共云容器编排服务。在本地,使用具有强大升级过程的供应商支持的容器编排平台。

3.6.3 脚本与版本协同

将版本控制与用于支持运维部署和升级过程的所有脚本一起使用。就像应用程序代码一样,将这些脚本视为一流的工件。

3.6.4 限制开发使用的基础镜像

限制允许开发团队用来构建其应用程序的基本映像。将它们限制为供应商提供的受信任镜像和或开放源社区管理的正式镜像。只有这些策划的镜像才能应用于构建生产上的容器化应用程序。

3.6.5 自动缩放

在容器编排平台中使用自动缩放功能可保持应用程序性能,而无需操作员干预。