Skip to main content

· 24 分钟阅读

在数字化浪潮席卷之下,很多传统行业的线上业务急速增长,其业务场景、用户行为都发生了转变,面对敏捷的业务和IT应变需求,如何快速地进行创新实验,提高IT部门的总体运营效率,高效融合开发和运维的能力等一系列问题,已成为企业需要直面的挑战。

2009年以来,DevOps越来越被重视,最开始是为了让开发和运维人员更好地沟通协作,后来逐渐成为打通软件产品交付过程中IT工具链和高效解决团队成员协作沟通问题的有效理念。但DevOps的整体发展是独木不成林的,现在已经有越来越多的技术支撑,微服务架构理念、容器技术等使得DevOps的实施变得更加容易。

我们研发团队从内部产品研发需求出发,将敏捷管理、CI/CD、自动化测试、运营管理、基于SpringCloud的微服务架构、容器编排等相关工具整合为一个PaaS平台,用来支持这些传统企业的数字化转型。

本文主要分析了项目研发团队在开发过程中存在的一些问题,介绍了Choerodon猪齿鱼对此的解决方法,最后解答了应用迁移到Choerodon猪齿鱼平台前的几点疑虑。

主要分为以下几个部分:

一、为什么要使用Choerodon猪齿鱼

  • 一般研发项目现状分析
  • Choerodon猪齿鱼能做哪些事情?

二、使用Choerodon猪齿鱼之前的疑问

  • 编程语言
  • 容器化
  • 数据库
  • 前后端分离
  • 微服务
  • 移动端支持
  • 公有云、混合云

三、总结

为什么要使用Choerodon猪齿鱼

在Choerodon开发团队接触的大部分传统企业中,他们面临着业务创新的需求和压力,同时也面临着无法很好得使用新型技术和方法快速将创意转化为产品的困境,IT团队希望能够利用Agile/DevOps、微服务和容器技术帮助业务进行快速创新,相关的工具非常多,而且工具链条很长,把它们整合应用起来对IT部门来说要求非常高,很多传统的企业并不具备这样的能力。

一般研发项目现状分析

应对易变的需求能力弱

传统的研发项目往往采用瀑布式的开发方式,从立项、需求、设计、开发,测试到最终运营管理,由于市场或者用户的需求经常性发生变化,瀑布式模型的能力比较弱;当然,现在很多项目并不是完全遵循瀑布式的开发方式,在进入运营期当需求变化时,会进行灵活地处理,尤其是持续更新的产品。但这种情况仍缺乏明确的管理策略,更多的是“东补西凑”的“理念”,与敏捷开发还是有所不同。另外,开发人员往往没有书面记录用户的变更需求,可能会导致无法追溯系统软件变更的历史。

缺乏有效的分支管理与版本控制机制

现在越来越多的项目使用Git作为版本控制的工具,通过Git进行分支和Tag管理,大多数情况这个过程都由手工完成,缺乏相应的规范,对于分支和版本号的控制也很随意,出现这样的情况往往是大家对软件交付过程中的软件版本控制不够重视,“只要确保软件是最新的版本即可”,甚至是项目管理的漏洞或者缺陷。

多采用手工或者半自动的部署方式

能否实现自动化和高效地部署是衡量一个团队工作能力的核心标志之一。很多团队采用手工的部署方式,有经验的“老司机”都知道,部署过程往往都是拉取源代码、编译、构建,然后上传到服务器、停止服务器、覆盖代码,最后启动,甚至还有各种系统设置等。每次部署都要经历这个过程,小到一个Bug的修复,大到发布一个大版本。这样直接会导致部署频率较低,进而降低用户需求或者价值的交付频率。

文档缺乏规范管理

文档是项目或者系统的积累和沉淀,包括项目初期的应用蓝图、架构图、分阶段实施计划,以及开发过程中的设计文档、产品功能文档等。在系统开发前期,大家可能对于维护文档还是比较积极的,但是随着产品不断迭代,慢慢大家就会疏于更新文档,导致文档与功能没有办法衔接对照。

缺乏驾驭微服务架构的能力

近几年微服务方兴未艾,尤其是Spring Cloud架构的不断成熟,以及Service Mesh的正式版本发布。由于微服务架构体系涉及到的技术种类非常多,几乎所有的微服务框架不能直接拿来使用,需要投入很大的人力物力进行前期研究、基础系统框架的搭建,这对于很多传统研发团队来说是一件很难的事情。

软硬件资源及交付过程缺乏统一管控

项目组在申请软硬件资源时,缺乏统一管控,各项目组独立部署,无法实现资源有效共享,资源利用率低,浪费严重。另外,在企业内部缺乏统一的支撑平台,每个项目组从开发到上线,基本上都是从零开始,项目交付过程中的沉淀很少,功能模块无法复用,交付过程也缺乏统一,交付周期长,需求响应慢。

以上是Choerodon团队在实践过程中遇到看到的情况,这些情况的存在可能导致研发团队效能的低下,进而影响到用户需求和价值的交付。对于研发团队效能的问题,国际上的一些组织也有相关的研究和定义,DORA 与 Google Cloud 合作发布的 2018 年《DevOps 现状报告》中,将团队根据 DORA 的软件交付效能基准划分为三种类型:高效能、中效能与低效能团队,以团队产出来进行评价,发布频率、变更响应时间、服务恢复时间,以及变更故障率等指标作为划分的参考标准。其划分标准如下:

软件交付性能的考量方面精英团队高效能团队中效能团队低效能团队
部署频率
对于使用的主要应用程序或服务,您的组织部署代码的频率为?
按需(一天多次)一天一次到一小时一次之间一周一次到一月一次之间一周一次到一月一次之间
变更响应时间
对于使用的主要应用程序或服务,您更改的前置时间(即,从代码提交到代码在生产中成功运行的时间)为?
小于一小时一天到一周之间一周到一月之间一个月到6个月之间
服务恢复时间
对于使用的主要应用程序或服务,在服务发生事故后(例如,计划外中断,服务损伤)恢复服务通常需要多长时间?
小于1小时小于1天小于1天1天到1月之间
变更故障率
对于使用的主要应用程序或服务,变更有多大比例会导致服务质量下降或随后需要修复(例如,导致服务受损,服务中断,需要修补程序,回滚,修复转发,修补程序)?
0-15%0-15%0-15%46%-60%

​对于低效能团队如何改进才能进一步释放潜能,提高团队的效率,DORA 的研究强调技术转型实践至关重要。这些重要的实践包括版本控制,自动化部署,持续集成(CI),基于主干的开发以及松耦合架构。 今年DORA还发现,有助于持续交付(CD)的实践包括:使用监控和可观察性解决方案,持续测试,将数据库更改集成到这样的软件交付流程中,以及关注安全性。

Choerodon猪齿鱼能做哪些事情?

对于一般软件研发类项目,往往包含产品立项、需求分析、应用设计,以及开发 、测试、持续部署与发布,生产运维等。本节将给大家阐述,Choerodon猪齿鱼是如何支持整个研发过程的,以及采用哪些手段来提高软件交付的效率。

产品立项

产品立项是启动产品研发的第一个阶段,最核心的工作是要确定产品的定位,包括目标用户、用户需要、产品名称、产品类型、关键优点、主要竞品、主要不同,以及相关成本投入、团队建设等。此时,可以使用Choerodon猪齿鱼的知识管理功能,方便的记录产品立项阶段的各种输出文档。

需求分析

针对产品立项中的要求(例如用户需要、关键优点)进行需求分析,做好用户访谈等。此时,可以使用Choerodon猪齿鱼的知识管理功能,方便的记录需求分析的各种输出文档。

应用设计

在应用设计阶段,将设计应用蓝图,构建整体系统架构和指定分阶段实施计划等。此时,可以使用Choerodon猪齿鱼的知识管理功能,方便地记录应用设计阶段的各种输出文档。

知识管理是一个轻量级的强大Wiki平台,允许用户根据自己的特定需求自定义Wiki,为企业、IT团队提供方便的项目协作平台和强大的项目内容管理平台,集中式管理产品相关内容等,例如需求收集、架构设计、功能设计、开发规范、命名规范、会议记录、计划安排等。

开发

在项目进入开发阶段,主要进行代码开发、单元测试、分支管理和版本控制等。Choerodon的开发流水线采用Gitlab CI作为持续集成工具,研发团队可以进行代码托管、分支管理、版本控制,有效简化应用开发、缩短应用生命周期,快速迭代。

测试

在测试过程中,团队需要进行测试用例管理、测试计划和执行,以及测试分析等。Choerodon的测试管理为用户提供敏捷化的持续测试工具,包括测试用例管理、测试循环、测试分析等,可以有效地提高软件测试的效率和质量,提高测试的灵活性和可视化水平,最终减少测试时间,让用户将主要精力放到软件功能构建上。

持续部署与发布

持续部署与发布是采用自动化的手段,持续地发布可部署的系统版本,并能够实现方便自动地将系统版本部署到目标环境中。此过程可以借助Choerodon猪齿鱼的部署流水线,方便地管理各种使用Choerodon开发部署的应用服务和资源,包括一键部署、应用启停、状态监控,以及应容器管理等。

生产运维

在生产运维阶段要对系统进行监控等,可以借助Choerndon的运营管理服务,其提供一整套完整的运营管理工具,在软件交付生产的各个环节建立数据收集和度量,监控主要包含开发类指标、服务器日志、应用系统日志和微服务调用链等信息;同时,提供各种分析报告,帮助用户优化IT资源配置。

另外,还有项目管理,项目管理贯穿整个产品的研发周期,借助Choerodon的敏捷管理服务,通过故事地图、用户故事来管理用户故事和发布计划,通过迭代来管理冲刺,最后通过看板来可视化冲刺的执行,让需求、计划、执行一目了然,使整个软件开发流程管理规范化。

并且,Choerodon猪齿鱼提供了一套基于Spring Cloud的微服务开发框架,在其中,做了大量的集成和封装,预置了权限、数据一致性、登录、前端UI 、审批、系统管理、个人中心等诸多模块,可以让用户专注基于业务的实现开发。

迁移之前的疑问

在迁移之前,系统架构师或者软件工程师对Choerodon猪齿鱼可能有一些疑问,例如,Choerodon是否有编程语言限制,对数据库的支持情况怎么样,是否支持公有云等。下面就对于普遍的疑问,一一作答。

编程语言

Choerodon猪齿鱼的核心部分是一个PaaS平台,采用Sping Cloud微服务架构进行开发构建。根据Choerodon猪齿鱼的设计思路,只要是能够容器化的应用都可以使用Choerodon的PaaS平台进行开发和部署,应用本身可以采用不同的编程语言,例如Java、C、C++、C#、Python、Go,以及由编程语言衍生出来的各种开发框架,例如Spring Cloud、Spring、Struts、Mybatis、Django、Flask、ReactJs、AngularJs等(这里不一一列举)。

容器化

Choerodon猪齿鱼一个核心的特性是通过镜像和容器实现“不可变架构”,不可变架构的好处是在程序开发阶段生成的可部署版本是镜像,在镜像中已经做过系统需要的各种设置,可直接通过镜像生成部署容器,不管是开发环境、测试环境还是正式环境,镜像不可变化,即所有环境的系统设置是一致的,避免不一致导致的各种系统问题。

Choerodon的开发流水线结束生成后将生成版本化的镜像和相关的配置文件,在部署阶段,直接将镜像部署到Kubernetes集群中,所以,如果要使用Choerodon猪齿鱼的部署功能,应用程序必须容器化。

数据库

软件系统一般分为应用层(前端、后端)和数据库层,以及部署相关,Choerodon猪齿鱼主要覆盖应用层,以及部署相关的容器层,现在还没有覆盖数据库层的相关内容。对于数据库层,用户可以选择自建或者是使用公有云的RDS服务。另外,程序中依然可以使用自动化的脚本构建数据库和初始化数据等,与原来没有任何区别。

前后端分离

目前很流行前后端分离的架构,例如后端使用SSM,前端采用React、Ant Design,移动端采用React Native等。Choerodon猪齿鱼完全支持这样的前后端分离架构,其实还是那句话“只要是能够容器化的应用都可以使用Choerodon的PaaS平台进行开发和部署”。

微服务

微服务是目前非常流行的技术之一,代表有Spring Cloud、Dubbo等。现在大家在谈微服务的时候一定要加上Agile/DevOps,貌似微服务+Agile/DevOps是不可分割的整体。根据实践经验,微服务的实施和落地需要从项目管理,开发,部署,运营监控,以及容器化等多个方面来考虑和配套。Choerodon猪齿鱼实际上是因微服务而生,有一整套完整的工具链条来支撑微服务的实施和落地。

移动应用支持

现在有各种移动应用技术,如React Native,Weex,PWA等。用这些或者别的框架开发的模块应用,只要能够打包成一个文件并且能够在原生应用中使用的,就可以通过Choerodon猪齿鱼进行移动微服务的版本跟踪、发布、回退甚至是根据不同主版本号进行个性化定制。

但是总应用的开发(一般用原生的Java或者OC或者Swift来开发原生应用)作为一个前置条件,是不通过微服务管理的(因为往往要涉及到应用的审核、推送、上架等),所以这里说的移动应用微服务化是指其中的模块应用。总应用只要能够实现文件的下载、覆盖,版本的对比即可。

如果总应用开发完成,在日常开发中开发人员要做的只是独立的模块开发,推送到Git库,触发CI,这时会生成模块的镜像并推送,然后在Choerodon猪齿鱼中选择是否可见和版本管理,即可在手机的应用上查看或者更新该模块。

公有云、混合云

Choerodon猪齿鱼是基于Kubernetes部署的,只要是能够安装部署Kubernetes就可以安装使用猪齿鱼,所以公有云、私有云或者混合云,只要安装了Kubernetes,就可以安装使用Choerodon猪齿鱼,另外,对于公有云中提供的RDS、NFS等服务Choerodon也可以使用,但是对于公有云提供的Kubernetes服务,阿里云、腾讯云的K8s服务是没有问题的,AWS的K8s服务可能有问题,因为AWS的Kubernetes服务是经过客户化的版本的可能有所不同。

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

· 4 分钟阅读

2018年DevOps国际峰会暨DevOps金融峰会深圳站将于11月2日-3日在深圳举办,Choerodon猪齿鱼社区高级架构师蒋尚勤将作为企业专场的嘉宾,带来《基于Choerodon猪齿鱼构建企业IT研发体系》的分享。

演讲主题

《基于Choerodon猪齿鱼构建企业IT研发体系》

嘉宾

蒋尚勤

华润置地信息管理部技术总监 & Choerodon猪齿鱼社区高级架构师

具有丰富的复合型的从业经验,在中大型企业研发领域深耕10年,包括技术研发、商务套件实施以及技术团队管理,对传统企业内部IT的特征有深刻理解,对Agile/DevOps在传统企业实施落地有丰富的经验,成功主导了多个中大型企业技术路线的转型重塑,以及研发体系的构建。目前致力于生态在企业的推行和应用,作为Choerodon猪齿鱼社区核心成员和高级架构师,参与猪齿鱼社区的建设和产品设计,并积极推进猪齿鱼平台在企业数字化服务中的实践应用。

主题简介

从华润置地实践经验入手,基于Choerodon猪齿鱼构建华润置地IT研发体系,分享在实际业务场景中 Agile/DevOps 理念的落地和实践,介绍如何使用Choerodon构建高效和标准化的DevOps交付流水线,以及猪齿鱼如何融入生态。

内容提要
  • 发现猪齿鱼,善用工具之力
  • 借力猪齿鱼,打造DevOps交付流水线,构建精益IT研发体系
  • 拥抱猪齿鱼,融入大生态

关于信息

欢迎通过我们的GitHub猪齿鱼社区进行反馈与贡献,帮助Choerodon猪齿鱼不断成长,我们将持续迭代优化,敬请期待。

· 6 分钟阅读

随着企业业务创新和应用复杂度的升高,传统的“瀑布式开发模型”面临着需求变更、过度开发、适应性不强等诸多问题,亟待改善。不仅如此,企业内部程序复杂,业务发展快,开发效率也逐渐变得愈发重要。

本次直播将介绍Choerodon猪齿鱼如何助力华润置地实现中台化转型,基于真实案例和实践经验,讲解Choerodon猪齿鱼如何帮助企业利用微服务和容器技术构建中台架构体系,打造以Choerodon猪齿鱼为核心的敏捷研发体系,聚焦业务,快速迭代,持续交付。

华润置地架构转型背景

华润置地有限公司是财富500强企业华润集团旗下的地产业务旗舰,是中国内地最具实力的综合型地产发展商之一,主营业务包括房地产开发、商业地产开发及运营、物业服务等。

华润置地一直重视企业的信息化建设,从最早期的采用ERP套件,到后面自主研发的一系列“烟囱式”应用,应用之间相互独立,系统功能重合,架构各异,伸缩扩展能力有限,服务器及人力资源浪费严重,产品交付周期长,运维工作繁重。

引入Choerodon猪齿鱼后,统一开发框架和平台,新的系统尽量采用微服务方式开发,基于敏捷迭代研发的思想,一般几周便可快速上线系统,部署周期从数周减少到几分钟,应用交付的效率提高了数十倍,容器平台由专门团队运维,项目组只需要专注于业务需求和交付,极大的降低了日常的运维成本,产品在设计、开发、运维等各个阶段均有改善。

Choerodon猪齿鱼是什么

Choerodon猪齿鱼 是一个全场景效能平台,基于Kubernetes的容器编排和管理能力,整合DevOps工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理,并提供IoT、支付、数据、智能洞察、企业应用市场等业务组件,来帮助企业聚焦于业务,加速数字化转型。

此次直播分享有什么?

本次直播主要介绍华润置地中台转型背景及落地过程。

主要内容包括:
  • 华润置地中台转型背景和架构体系介绍
  • Choerodon在华润置地的部署架构及业务架构
  • 转型过程
    • 单体应用架构向微服务应用架构转变
    • 传统部署架构向容器部署架构转变--DevOps落地实践
    • 瀑布式研发向敏捷迭代式研发方式转变
  • 实践经验总结
直播时间
10月15日(周一)下午 14:00
直播地址

欢迎各位提前报名

关于信息

欢迎通过我们的GitHub猪齿鱼社区进行反馈与贡献,帮助Choerodon猪齿鱼不断成长,我们将持续迭代优化,敬请期待。

· 12 分钟阅读

Kubeadm是什么

Kubeadm是一个提供Kubeadm init 和 Kubeadm join命令,用于创建Kubernetes集群的最佳实践“快速路径”工具。

Kubeadm可以在多种设备上运行,可以是Linux笔记本电脑,虚拟机,物理/云服务器或Raspberry Pi。这使得Kubeadm非常适合与不同种类的配置系统(例如Terraform,Ansible等)集成。

开发者可以在支持安装deb或rpm软件包的操作系统上非常轻松地安装Kubeadm。SIG集群生命周期SIG Cluster Lifecycle Kubeadm的SIG相关维护者提供了预编译的这些软件包,也可以在其他操作系统上使用。

Kubeadm的目标

Kubeadm的目标是在不安装其他功能插件的基础上,建立一个通过Kubernetes一致性测试Kubernetes Conformance tests的最小可行集群。它在设计上并不会安装网络解决方案,而是需要用户自行安装第三方符合CNI的网络解决方案(如:flannel,calico,weave network等)。

Kubeadm的子任务

  • kubeadm init 初始化Kubernetes主节点
  • kubeadm join 初始化Kubernetes工作节点并将其加入群集
  • kubeadm upgrade 将Kubernetes集群升级到更新版本
  • kubeadm token 用于管理Kubeadm join所使用的令牌
  • kubeadm reset 恢复由Kubeadm init或 Kubeadm join对此主机所做的任何更改
  • kubeadm version 版本打印Kubeadm版本

Kubeadm的安装

安装Kubeadm需要手动安装Kubelet和Kubectl,因为Kubeadm是不会安装和管理这两个组件的。

  • Kubelet:在群集中的所有计算机上运行的组件,并执行诸如启动pod和容器之类的操作。
  • Kubectl:操作群集的命令行工具。

▌Ubuntu

apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

▌CentOS

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF
setenforce 0
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable kubelet && systemctl start kubelet

CFSSL

CFSSL是CloudFlare开源的一款PKI/TLS工具。它既是命令行工具,也是用于签名、验证和捆绑TLS证书的HTTP API 服务器。

CFSSL包括:

  • 一组用于生成自定义 TLS PKI 的工具
  • cfssl,即CFSSL的命令行工具
  • multirootca 是可以使用多个签名密钥的证书颁发服务器
  • kbundle 用于构建证书池
  • cfssljson 从cfssl和multirootca中获取JSON输出,并将证书,密钥,CSR和bundle写入磁盘

PKI借助数字证书和公钥加密技术提供可信任的网络身份,通常,证书就是一个包含如下身份信息的文件:

  • 证书所有组织的信息
  • 公钥
  • 证书颁发组织的信息
  • 证书颁发组织授予的权限,如:证书有效期、适用的主机名、用途等
  • 使用证书颁发组织私钥创建的数字签名

CFSSL的安装

由于运行环境不同,故使用Go命令进行编译安装,在安装之前请确保已安装1.8版本以上的Go命令行以及配置了环境变量GOPATH。

go get -u github.com/cloudflare/cfssl/cmd/...

Ansible

Ansible是什么

Ansible是个什么东西呢?官方的title是“Ansible is Simple IT Automation”——简单的自动化IT工具。这个工具的目标有这么几项:自动化部署APP;自动化管理配置项;自动化的持续交付;自动化的云服务管理。

所有的这几个目标本质上来说都是在一台或者几台服务器上,执行一系列的命令而已。就像Fabric,以及基于Fabric开发的自动化应用部署的工具: Essay 。都是做了这么个事——批量地在远程服务器上执行命令 。

那么Fabric和Ansible有什么差别呢?简单来说Fabric像是一个工具箱,提供了很多好用的工具,用来在Remote执行命令,而Ansible则是提供了一套简单的流程,你只要按照它的流程来做,就能轻松完成任务。这就像是库和框架的关系一样。

当然,它们之间也有共同点——都是基于 Paramiko 开发的。这个Paramiko是什么呢?它是一个纯Python实现的ssh协议库。因此Fabric和Ansible还有一个共同点就是不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。

Ansible基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。Ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是Ansible所运行的模块,Ansible只是提供一种框架,主要包括:

  1. 连接插件connection plugins:负责和被监控端实现通信;
  2. host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
  3. 各种模块:核心模块、command模块、自定义模块;
  4. 借助于插件完成记录日志邮件等功能;
  5. Playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。

Ansible的基本架构

  1. 核心引擎:即图中所看到的Ansible。

  2. 核心模块(core module):

    模块库(module library)分为两部分,一个是核心模块,另外一个就是自定义模块(custom modules)。核心模块中都是Ansible自带的模块,Ansible模块资源分发到远程节点使其执行特定任务或匹配一个特定的状态。这些核心模块都遵循 Batteries Included 哲学。其实这里还是很有意思的,Batterires Included:Python has a large standard library, commonly cited as one of Python’s greatest strengths,providing tools suited to many tasks. 这就意味着Python有巨大的库支持你完成你想完成的任务工作。

  3. 自定义模块(custom modules):

    如果Ansible无法满足你所需求的模块,那么你能使用 Ansible 添加自定义化的模块。

  1. 插件(plugin):

    这里的理解就是完成较小型的任务,辅助模块来完成某个功能。

  1. 剧本(playbook):

    定义需要给远程主机执行的一系列任务。比如安装一个nginx服务,可以把这拆分为几个任务放到一个playbook中。例如:第一步,需要下载nginx的安装包。第二步,将事先写好的nginx.conf的配置文件下发的目标服务器上。第三步,把服务启动起来。第四步,检查端口是否正常开启。这些步骤可以通过playbook来进行整合,然后通过inventory来下发到想要执行剧本的主机上。并且playbook也支持交互式执行playbook里面的步骤,如果有哪一个步骤执行返回了一个错误报告,可以仅仅只单独执行这个步骤。你可以把playbook理解成为一个组策略,控制管理这个OU下所有的主机行为。

  1. 连接插件(connectior plugins):

    Ansible默认是基于SSH连接到目标机器上执行操作的。但是同样的Ansible支持不同的连接方法,要是这样的话就需要连接插件来完成连接了。

  1. 主机清单(host inventory):

    为Ansible定义了管理主机的策略。一般小型环境下只需要在host文件中写入主机的IP地址即可,但是到了中大型环境有可能需要使用静态inventory或者动态主机清单来生成所需要执行的目标主机。

Ansible的功能特性

  1. 应用代码自动化部署

  2. 系统管理配置自动化

  3. 支持持续交付自动化

  4. 支持云计算,大数据平台环境

  5. 轻量级,无序在客户端安装agent,更新时只需在控制机上进行更行即可

  6. 批量任务执行可以写成脚本,不用分发到远程就可以执行

  7. 支持非root用户管理操作,支持sudo

  8. 使用python编写,维护更简单

Ansible的安装

▌Ubuntu

sudo apt-get install software-properties-common
sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

▌CentOS

sudo yum install epel-release
sudo yum install ansible

总结

通过前面的介绍,可以大致了解Kubeadm、CFSSL、Ansible这三个工具的作用,由于安装Kubernetes集群时执行Kubeadm命令较为固定和繁琐,并且有些命令需要所有节点都执行,故将这些命令编写为Ansible playbooks,使用Ansible进行执行,从而提高部署效率和降低出错的概率。

该系列第一篇为:《从0到1使用Kubernetes系列——Kubernetes入门》,下一篇将介绍如何使用Ansible快速安装Kubernetes集群,欢迎各位持续关注。

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

· 29 分钟阅读

在Choerodon猪齿鱼设想之初,我们希望基于容器技术,整合DevOps工具链、微服务应用框架,开发一个企业级的PaaS平台,来帮助企业实现敏捷化的应用交付和自动化的运营管理。同时,也确定了技术堆栈的要求,即充分地使用主流成熟的组件,利用工具的扩展机制来构建平台,打造一个开放的技术平台和体系,让企业享受到社区的成果。

当然,罗马不是一天建造起来的。从初期确定技术栈到现在,除Choerodon猪齿鱼平台具体应用的实践与迭代,平台的技术栈也在不断进行着迭代。在社区中解决一个相同问题的有很多,而如何验证甄别哪些既能够满足现在的系统需求,在未来又有比较好的适应性,就给广大的架构师和软件设计师提出了挑战。根据Choerodon猪齿鱼实践经验,在使用时,可以从如下几个方面来进行考虑:

  • 语言 - 选择一个非常核心的考量是尽量使用应用比较广泛的开发技术,避免涉及相对来说的新技术、开发语言,这样可以进一步研发降低成本。例如Java的使用非常广泛。

  • 成熟度 - 的版本是否已经发布稳定版本或者更高版本是其成熟的重要标志,例如Istio在8月发布1.0版本,促使了很过公司和产品跟进使用;如果产品仍处于孕育阶段,则其技术变更的风险就比较大,例如 Apache 的 incubating 、 0.XXX版本或者beta版本等都有可能有各种技术缺陷或者没有经过较好的实际检验。

  • 社区 - 社区的活跃度在一定程度上反映了整个技术的生命力,例如是否有大量相关社区存在,K8s在国内就有Kubernetes中文社区,K8s中文社区等,以及定期还有各种关于K8s的Meetup或者论坛等;当然GitHub 上的 stars 的数量是一个参考指标,以及贡献者数量、代码更新频率等。

  • 生态圈 - 围绕是否有活跃健康的生态圈,是否有比较多的用户在使用,尤其是一些大公司,以及围绕产品是否有较多的文章、知识分享,或者围绕产品的某一块功能第三方增强工具,例如围绕Hadoop有Sqoop、Hbase、Hive等。

  • 文档 - 完备并及时更新的文档,非常有利于用户了解产品的设计思路、安装、使用等,方便产品在用户这边落地实践。想想 sourceforge.net 上如今已是代码的坟墓,没有文档的代码生命周期通常都不长。

  • 资源 - 如果在业界比较高的人气,应该有比较多的使用者,市场上相关人员资源也非常丰富,比较有利于团队技术人员的补充。

到目前为止,Choerodon猪齿鱼经过不断地迭代,逐渐形成了以 Spring Cloud + Kubernetes 为主体的微服务技术体系。

什么是微服务架构

在开始介绍之前,首先需要了解什么是微服务架构? 2014年初(该年可以称之为微服务的元年),微服务之父 Martin Fowler 在其博客上发表了"Microservices" 一文,文中正式提出了微服务架构风格,并指出了微服务架构的一些特点。

简单地说,微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间通过基于HTTP的RESTful API进行通信协作。被拆分的每一个小型服务都围绕着系统中的某一项或一些耦合度较高的业务功能进行构建,并且每个服务都维护着自身的数据存储、业务开发、自动化测试案例以及独立部署机制。由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。

-- 作者 James Lewis and Martin Fowler, 翻译自《Spring Cloud微服务实战》

在传统的单体应用系统架构中,一般分为三个部分,即数据库、服务应用端和前端展现,在业务发展初期,由于所有的业务逻辑在一个应用中,开发、测试、部署都比较容易。但是,随着业务的发展,系统为了应对不同的业务需求会不断为单体应用增加不同的业务模块。久而久之,不断扩充的业务需求导致单体应用的系统越来越庞大臃肿。此时,单体应用的问题也逐渐显现出来,由于单体应用是一个“整体”,往往修改一个小的功能,为了部署上线就会影响到其他功能的运行。而且,对于业务而言,往往不同模块对系统资源的要求不也尽相同,而单体应用各个功能模块因为无法分割,也就无法细化对系统资源的需求。所以,单体应用在初期是比较方便快捷,但是随着业务的发展,维护成本会越来越大,且难以控制。

Martin Fowler 认为微服务架构与单体应用最大的区别在于,微服务架构将一个完整的单体应用拆分成多个有着独立部署能力的业务服务,每个服务可以使用不同的编程语言,不同的存储介质,来保持低限度的集中式管理。下面这张图,很好的说明了单体架构和微服务架构的区别。

根据 Choerodon 猪齿鱼的开发实践和产品化经验,在互联网+、云计算和大数据、人工智能等的大背景下,构建软件系统产品,首先要把系统的基础框架搭好,方便后续的扩展。而微服务架的独立部署、松耦合等特点,与Choerodon猪齿鱼的想法和设计理念不谋而合, 所以 Choerodon 最终选择了微服务架构作为基础架构。

而在微服务基础框架中,有两个不得不提的微服务架构,分别是阿里巴巴的 Dubbo 和 Pivotal 公司开源的 Spring Cloud 。

Dubbo的诞生背景

Dubbo 是一个高性能、基于JAVA 的开源RPC 框架。阿里巴巴开源的 Dubbo 致力于提供高性能和透明化的RPC 远程服务调用方案,以及SOA 服务治理方案,使得应用可通过高性能RPC 实现服务的输出和输入功能,和 Spring 框架可以无缝集成。本质上而言,是一个服务框架。根据Dubbo 的官方 Roadmap 可以看到,Dubbo 的发展经历了如下几个过程:

  • 数据访问框架(ORM):早期的主流开发方式是面向对象的开发方式。只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。关系数据库是企业级应用环境中永久存放数据的主流数据存储系统,简化了增删改查工作量。

  • Web框架(MVC):随着访问量逐渐增大,单一应用已经无法满足业务需求,将应用拆分成互不相干的几个应用,分离视图层和业务逻辑层以提升效率。

  • 分布式服务框架(RPC):当垂直应用越来越多,应用之间交互不可避免,将业务抽取出来,作为独立的服务,逐渐形成稳定的分布式服务架构。

  • 面向服务的架构(SOA):当服务越来越多,业务和环境的变化越来越快时,对于资源的控制,性能的要求也就越发重要。SOA 将一个应用程序的业务逻辑或某些单独的功能模块化并作为服务呈现给消费者或客户端,使得业务IT 系统变得更加灵活。

Dubbo 按照分层来规划我们的系统,包含远程通讯、集群容错和自动发现三个核心部分。提供透明化的远程方法调用,使各个服务之间解耦合,并通过RPC的调用来实现服务的调用。

Dubbo 由于自身的设计使得服务之间的调用更加透明,网络消耗小,同时借助类似zookeeper 等分布式协调服务实现了服务注册。但是Dubbo 的缺点也是显而易见的,比如:

  • 只支持JAVA 使得Dubbo 在开发语言上受到了限制
  • 虽然RPC 相对于HTTP 而言性能更高,但是在网络通用性上却有着局限性
  • 而且对于一个微服务架构而言,包括服务网关,配置中心等很多东西都是缺失的,需要自己实现
  • 虽然Dubbo 很早就进行了开源,但是在很长一段时间官方都没有对开源版本进行维护

由于这些缺点,Choerodon 并没有选择 Dubbo 作为基础开发框架。

Spring Cloud 应运而生

在微服务架构的概念提出之后,很快 Netflix 公司将自家经过多年大规模生产验证的微服务架构,抽象落地形成 一整套开源的微服务基础组件 NetflixOSS 。2015年,Pivotal 将 NetflixOSS 开源微服务组件集成到其 Spring 体 系,并推出 Spring Cloud 微服务开发技术栈。自此,微服务技术迅猛普及,甚至 Spring Cloud一度成为了微服务的代名词。

可能更多了解微服务架构的读者都是从 Spring Cloud 入门,凭借之前 Spring Framework 的良好群众基础和Cloud 这个具有时代感的名字,Spring Cloud 的名字可以说是无人不知,无人不晓。结合Pivotal 公司的 Spring Boot,我们通过封装开源成熟的Spring Cloud 组件和一些基础的分布式基础服务,就可以简单快速的实现一个微服务框架,降低应用微服务化的门槛。

Spring Cloud 提出了一整套有关于微服务框架的解决方案。包括:

  • 服务注册发现:Spring Cloud Eureka
  • 负载均衡:Spring Cloud Netflix
  • 服务网关:Spring Cloud Zuul
  • 配置管理:Spring Cloud Config
  • 服务消费: Spring Cloud Ribbon/Feign
  • 分布式追踪:Spring Cloud Sleuth
  • 服务容错:Spring Cloud Hystrix
  • ...

下图说明了借助Spring Cloud 搭建的一套简单的微服务体系。

可以看到,Spring Cloud 集成了众多组件,从技术架构上降低了对大型系统构建的要求,使架构师以非常低的成本(技术或者硬件)搭建一套高效、分布式、容错的平台。但同时,在实际开发中也发现 Spring Cloud 存在着的一些问题:

  • 技术要求高:Spring Cloud 对于配置中心、熔断降级、分布式追踪、在权限认证、分布式事物等基本的功能,并没有提供一个成熟的组件,需要结合第三方的组件或自研实现。这对整个开发团队提出了非常高的技术要求。
  • 代码侵入性强:Spring Cloud 对业务代码有一定的侵入性,技术升级替换成本高,导致实施团队配合意愿低,微服务落地困难。
  • 服务运维困难:Spring Cloud 在服务调度和部署、服务日志、服务监控等仍有缺失。当服务的规模增大,对于微服务的管理有可能会增加运维的负担。
  • 多语言支持不足:对于大型公司而言,尤其是快速发展的互联网公司,企业的性质决定了多语言的技术栈、跨语言的服务调用也是常态,跨语言调用也恰恰是微服务概念诞生之初的要实现的一个重要特性之一。

Dubbo & Spring Cloud 对比

对比Dubbo 和Spring Cloud 可以发现,Dubbo 只是实现了服务治理,而Spring Cloud 的子项目则分别覆盖了微服务架构下的众多组件,而服务治理只是其中的一个方面。

通过谷歌和百度的搜索统计可以看到,自2015年起到现在,国内对于Spring Cloud 检索指数也在逐渐赶超Dubbo。

综合而言,Dubbo专注于服务治理;Spring Cloud关注于微服务架构生态。

虽然 Spring Cloud 降低了微服务化的门槛,但是除了基础的服务发现以外,Choerodon 团队在实际开发中也遇到了诸多的挑战。例如,各个组件并非完美无缺,很多组件在实际应用中都存在诸多不足和缺陷。 Spring Cloud 并不是银弹,微服务架构解决了单体系统变得庞大臃肿之后产生的难以维护的问题,但是也因为服务的拆分引发了诸多原本在单体应用中没有的问题,比如部署困难,监控困难,运维成本大,是选择 Spring Cloud 首先要面对的问题。

而容器化的普及,尤其是云原生技术生态的不断完善,比较好地解决了微服务架构的采用引发的诸多问题,使得微服务在普通传统企业的落地成为了可能。

Kubernetes + Docker 使微服务实施成为一种可能

当企业逐步接受微服务架构,享受着微服务带来好处的同时,也面临着微服务运维成本的增加, 环境的不一致,服务的编排、部署、迁移等诸多问题。Choerodon 平台经过不断地演进,从初期引入Docker,到Rancher + Jenkins,再到现在采用 Kubernetes 为容器编排和管理工具。

容器技术产生的主要原因,并不是因为资源浪费。主要是开发和运维人员环境不一致,导致开发效率大大降低。通过容器可以在一个完全隔离的环境中非常高效地运行代码,容器化天然适用于微服务,改善了引入Spring Cloud 微服务后开发效率大大降低的问题。但是单独使用Docker 并没有完整的解决微服务管理的痛点,服务的部署和运维仍然急需解决。

Kubernetes 是谷歌推出的容器编排引擎,是基于GoLang 实现的一个开源软件。K8s(Kubernetes)初源于谷歌内部的Borg,提供了面向应用的容器集群部署和管理系统,其目标旨在消除编排物理/虚拟计算、网络和存储基础设施的负担,并使应用程序运营商和开发人员完全将重点放在以容器为中心的原语上进行自助运营。

早期大家对于K8s 定位是容器编排引擎,同一时期流行的容器编排引擎还有MESOS、Docker Swarm 等。但是经过几年的发展,K8s 已经成为了云供应商的通用基础设施,我们熟悉的Google Cloud,AWS,Microsoft Azure,阿里云,华为云等等,都提供了对K8s 的支持。现在,K8s 已经不仅仅是一种工具,更多的是作为微服务架构的一种行业标准。

下图通过使用微服务架构的设计思想来看待K8s,并对K8s 中的一些功能进行了说明。

通过对比可以看到,在设计上,K8s本身就属于微服务架构的范畴。这里有的人可能就会有疑问,既然 K8s 功能这么强大,那么K8s 和 Spring Cloud 到底哪个更好?Choerodon 为什么不直接使用Kubernetes 作为基础的微服务架构呢?

为了区分Spring Cloud 和Kubernetes 两个项目的范围,下面这张图列出了几乎是端到端的微服务架构需求,从底层的硬件到上层的 DevOps 和自服务经验,并且列出了如何关联到Spring Cloud 和Kubernetes 平台。

可以看到:

  • Spring Cloud:自上而下,面向开发者,从应用代码到微服务架构的方方面面
  • Kubernetes:自下而上,面向基础设施,试图将微服务的问题在平台层解决,对开发者屏蔽复杂性

综上对比,K8s 遵循了微服务架构的基本核心要素,虽然在一些功能上有所欠缺,但不可否认,K8s 帮助补足了使用Spring Cloud 所缺失的一部分。

微服务“新秀”--Service Mesh

Choerodon 通过使用 Spring Cloud + Kubernetes 的模式,帮我们能够很容易的构建和部署微服务架构。但是在线上管理整个微服务体系的时候,仍然面临着一些难点。

一直以来都存在一个谬误,那就是在分布式系统中网络是可靠的。实际上网络是不可靠的,也是不安全的,微服务中大部分的故障都是出现在服务通信中。

K8s 帮我们实现了微服务的部署,但服务的网络调用、限流、熔断和监控这些问题,依旧让开发和运维人员都十分头痛。如何保证应用调用和事务的安全性与可靠性?Service Mesh 由此应运而生。

在过去几个月里,Service Mesh是行业内毋庸置疑的焦点。Service Mesh 译作“服务网格”或“服务栅格”,作为服务间通信的基础设施层。Service Mesh 是一种模式,而非技术。Buoyant 公司的 CEO Willian Morgan 在他的文章《WHAT’S A SERVICE MESH? AND WHY DO I NEED ONE?》中解释了什么是 Service Mesh。

A service mesh is a dedicated infrastructure layer for handling service-to-service communication It’s responsible for the reliable delivery of requests through the complex topology of services that comprise a modern, cloud native application. In practice, the service mesh is typically implemented as an array of lightweight network proxies that are deployed alongside application code, without the application needing to be aware.*

Service Mesh 本质上是一个轻量级的网络代理,好比应用程序或者说微服务间的 TCP/IP。

对于开发人员而言,在编写应用的时候无需关心网络这一层,使得服务回归到本质,专注于业务功能,服务中的交互则交给Service Mesh。Service Mesh 为服务提供了一个视图,提高了追踪能力,并提供了添加跟踪而不触及所有应用的能力,也就是所谓的Service Mesh 代码无侵入和透明性,能够帮助团队更好地管理服务。

Service Mesh 架构图:

可以看到,Service Mesh 通过一种Sidecar的模式。给每一个微服务实例部署一个Sidecar Proxy。该Sidecar Proxy 负责接管对应服务的入流量和出流量,并将微服务架构中的服务订阅、服务发现、熔断、限流、降级、 分布式跟踪等功能从服务中抽离到该Proxy 中。

Sidecar 以一个独立的进程启动,可以每台宿主机共用同一个Sidecar 进程,也可以每个应用独占一个Sidecar 进程。所有的服务治理功能,都由Sidecar 接管,应用的对外访问仅需要访问Sidecar 即可。当该Sidecar 在微服务中大量部署时,这些Sidecar 节点自然就形成了一个服务网格。

通过控制面组件对这些服务网格进行管理,这样也就提供了一种对于微服务进行高效而统一的管理方式。集中化的控制面板,同时仍然具有随心所欲的敏捷性和基于云的应用开发。这一特性,使得Service Mesh 成为大势所趋。

总 结

回顾微服务结构发展的这几年,微服务架构的逐渐普及,容器技术的兴起,云原生的趋势,微服务技术生态在不断地变化中,容器、Cloud Native、Serverless、Service Mesh,Knative 等新技术新理念你方唱罢我登场,使得整个以微服务为核心的生态越来越完善成熟。

像在前文中提到的Kubernetes、Service Mesh等都是解决微服务架构本身系统范围的问题,扎实可靠的基础框架,有利于后续的开发,这也是产品研发、系统实施的关键第一步。

除了系统本身的技术栈,工程落地实施是另一个要解决的问题。很多产品开始开发的时候,都不太注意规范化,待产品需求越来越复杂,人员越来越多时,整个项目会变得很难维护,甚至会影响产品的持续迭代。特别是微服务技术体系的引入,这个问题会更加明显。所以如果项目一开始,就以工程化的思想去组织代码,以规范化的流程去做构建发布,会给后续的发展打下坚实的基础。微服务的工程落地实施是Choerodon猪齿鱼一直关注和实践的方向,通过整合DevOps工具链和引入落地敏捷实施的方法论,让微服务架构的工程落地变得容易,这也成了Choerodon的PaaS平台能力,在这就不做赘述,感兴趣的读者可以到Choerodon的官网了解。

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

· 24 分钟阅读

基本概念

Docker 是什么

Docker 起初是 dotCloud 公司创始人 Solomon Hykes 在法国的时候发起的一项公司内部项目,Docker 是基于 dotCloud 公司多年云服务技术的一次革新,在 2013 年 3 月以 Apache 2.0 授权协议进行开源,其项目主要代码在 GitHub 上进行维护,自从 Docker 开源之后,就一直受到了广泛讨论和关注。

Docker 进行开发实现使用的是 Google 公司推出的 Go 语言,对进程进行封装隔离是基于 Linux 内核的 cgroup,namespace,以及 AUFS 类的 Union FS 等技术,这属于操作系统层面的虚拟化技术。因为隔离的进程独立于宿主与其它隔离的进程,所以也称其为容器(后文会对“容器”的概念进行详细介绍)。Docker 在容器的基础上,进行了进一步的封装,从网络互联、文件系统到进程隔离等,大大地简化了容器的创建和维护,让 Docker 技术比虚拟机技术更加轻便、快捷。

以下两张图片对比了 Docker 与传统虚拟化方式的不同之处。Docker 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,没有进行硬件虚拟;而传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程。因此容器要比传统虚拟机更为轻便。

图为 传统虚拟化

图为 Docker

为什么要使用 Docker?

Docker 是一种新兴的虚拟化方式,跟传统的虚拟化方式相比具有众多优势。

  • 系统资源利用更高效

    因为容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,所以 Docker 对系统资源的利用率更高。

  • 启动时间更快速

    Docker 容器应用由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。极大地节省了开发、测试,部署的时间。

  • 运行环境一致性

    开发过程中比较常见的问题就是环境一致性问题。因为开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 “这段代码在我机器上没问题啊!”这类问题。

  • 持续交付与部署

    对开发和运维人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration)系统进行集成测试,而运维人员则可以直接在各种环境中快速部署该镜像,甚至结合持续部署(Continuous Delivery/Deployment) 系统进行自动部署。

    而且使用 Dockerfile 使镜像构建透明化,不仅开发团队可以理解应用运行环境,也方便运维团队理解应用运行所需条件,帮助更好地在生产环境中部署该镜像。

  • 迁移更轻松

    由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运行结果是一致的。因此用户可以很轻松地将在一个平台上运行的应用,迁移到另一个平台上,而不用担心运行环境变化导致应用无法正常运行的情况。

  • 维护和扩展更轻松

    Docker 使用的分层存储以及镜像技术,使得应用重复部分的复用更为容易,也使得应用的维护更新和基于基础镜像进一步扩展镜像变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大降低了应用服务的镜像制作成本。

Docker 的镜像和容器

Docker 的口号是“Build, Ship and Run Any App, Anywhere.”,大意是编译好一个应用后,可以在任何地方运行,不会像传统的程序一样,一旦换了运行环境,往往就会出现缺这个库,少那个包的问题。那么 Docker 是怎么做到这点的呢?

简单说就是它在编译应用的时候把这个应用依赖的所有东西都构建到镜像里面(有点像程序的静态编译——只是像而已)。我们把这个编译构建好的东西叫 Docker 镜像(Image),然后当 Docker deamon(Docker 的守护进程/服务进程)运行这个镜像的时候,我们称其为 Docker 容器(Container)。可以简单理解 Docker 镜像和 Docker 容器的关系就像是程序和进程的关系一样(当然实质是不一样的)。

Images 和 Layers

每个 Docker 镜像(Image)都引用了一些只读的(read-only)层(layer),不同的文件系统 layer 也不同。这些 layer 堆叠在一起构成了容器(Container)的根文件系统(root filesystem)。下图是 Ubuntu 15.04 的镜像,共由 4 个镜像层(image layer)组成:

Container 和 Layers

容器和镜像的主要区别就是顶部的那个可写层(即之前说的那个“container layer”)。容器运行时做的所有操作都会写到这个可写层里面,当容器删除的时候,这个可写层也会被删掉,但底层的镜像依旧保持不变。所以,不同的容器都有自己的可写层,但可以共享同一个底层镜像。下图展示了多个容器共享同一个 Ubuntu 15.04 镜像。

Docker 的 storage driver 负责管理只读的镜像层和可写的容器层,当然不同的 driver 实现的方式也不同,但其后都有两项关键技术:可堆叠的镜像层(stackable image layer)和写时拷贝技术(copy-on-write, CoW)。

Docker 数据持久化

刚开始的时候,Docker 一般只适用于无状态的计算场景使用。但随着发展,Docker 通过 data volume 技术也可以做到数据持久化了。Data volume 就是我们将主机的某个目录挂载到容器里面,这个 data volume 不受 storage driver 的控制,所有对这个 data volume 的操作会绕过 storage driver 直接其操作,其性能也只受本地主机的限制。而且我们可以挂载任意多个 data volume 到容器中,不同容器也可以共享同一个 data volume。

下图展示了一个 Docker 主机上面运行着两个容器.每一个容器在主机上面都有着自己的地址空间(/var/lib/docker/...),除此以外,它们还共享着主机上面的同一个/data 目录。

Kubernetes 简介

Kubernetes 是谷歌开源的容器集群管理系统,是 Google 多年大规模容器管理技术 Borg 的开源版本,主要功能包括:

  • 于容器的应用部署、维护和滚动升级
  • 负载均衡和服务发现
  • 跨机器和跨地区的集群调度
  • 自动伸缩
  • 无状态服务和有状态服务
  • 广泛的 Volume 支持
  • 插件机制保证扩展性

Kubernetes 发展非常迅速,已经成为容器编排领域的领导者。

Kubernetes 是什么

Kubernetes 提供了很多的功能,它可以简化应用程序的工作流,加快开发速度。通常,一个成功的应用编排系统需要有较强的自动化能力,这也是为什么 Kubernetes 被设计作为构建组件和工具的生态系统平台,以便更轻松地部署、扩展和管理应用程序。

用户可以使用 Label 以自己的方式组织管理资源,还可以使用 Annotation 来自定义资源的描述信息,比如为管理工具提供状态检查等。

此外,Kubernetes 控制器也是构建在跟开发人员和用户使用的相同的 API 之上。用户可以编写自己的控制器和调度器,也可以通过各种插件机制扩展系统的功能。这种设计使得用户可以方便地在 Kubernetes 之上构建各种应用系统。

Kubernetes 不是什么

Kubernetes 不是一个传统意义上,包罗万象的 PaaS (平台即服务) 系统。它给用户预留了选择的自由。

  • 不限制支持的应用程序类型,它不插手应用程序框架, 也不限制支持的语言 (如 Java, Python, Ruby 等),Kubernetes 旨在支持极其多样化的工作负载,包括无状态、有状态和数据处理工作负载。只要应用可以在容器中运行,那么它就可以很好地在 Kubernetes 上运行。
  • 不提供内置的中间件 (如消息中间件)、数据处理框架 (如 Spark)、数据库 (如 mysql) 或集群存储系统 (如 Ceph) 等。这些应用直接运行在 Kubernetes 之上。
  • 不提供点击即部署的服务市场。
  • 不直接部署代码,也不会构建用户的应用程序,但用户可以在 Kubernetes 之上构建需要的持续集成 (CI) 工作流。
  • 允许用户选择自己的日志、监控和告警系统。
  • 不提供应用程序配置语言或系统 (如 jsonnet)。
  • 不提供机器配置、维护、管理或自愈系统。

另外,已经有很多 PaaS 系统运行在 Kubernetes 之上,如 Openshift, Deis 和 Eldarion 等。 你也可以构建自己的 PaaS 系统,或者只使用 Kubernetes 管理你的容器应用。

当然了,Kubernetes 不仅仅是一个 “编排系统”,它消除了编排的需要。Kubernetes 通过声明式的 API 和一系列独立、可组合的控制器保证了应用总是在期望的状态,而用户并不需要关心中间状态是如何转换的。这使得整个系统更容易使用,而且更强大、更可靠、更具弹性和可扩展性。

基本组件

核心组件

Kubernetes 主要由以下几个核心组件组成:

  • etcd:保存了整个集群的状态;
  • apiserver:提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
  • controller manager:负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
  • scheduler:负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
  • kubelet:负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
  • Container runtime:负责镜像管理以及 Pod 和容器的真正运行(CRI);
  • kube-proxy:负责为 Service 提供 cluster 内部的服务发现和负载均衡

除了核心组件,还有一些推荐的 Add-ons:

  • kube-dns:负责为整个集群提供 DNS 服务
  • Ingress Controller:为服务提供外网入口
  • Heapster:提供资源监控
  • Dashboard:提供 GUI
  • Federation:提供跨可用区的集群
  • Fluentd-elasticsearch:提供集群日志采集、存储与查询

组件详细介绍

Etcd

Etcd 是 CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。

Etcd 主要功能:

  • 基本的 key-value 存储
  • 监听机制
  • key 的过期及续约机制,用于监控和服务发现
  • 原子 CAS 和 CAD,用于分布式锁和 leader 选举

kube-apiserver

kube-apiserver 是 Kubernetes 最重要的核心组件之一,主要提供以下的功能:

  • 提供集群管理的 REST API 接口,包括认证授权、数据校验以及集群状态变更等
  • 提供其他模块之间的数据交互和通信的枢纽(其他模块通过 API Server 查询或修改数据,只有 API Server 才直接操作 etcd)

kube-controller-manager

Controller Manager 由 kube-controller-manager 和 cloud-controller-manager 组成,是 Kubernetes 的大脑,它通过 apiserver 监控整个集群的状态,并确保集群处于预期的工作状态。

kube-controller-manager 由一系列的控制器组成

  • Replication Controller
  • Node Controller
  • CronJob Controller
  • Daemon Controller
  • Deployment Controller
  • Endpoint Controller
  • Garbage Collector
  • Namespace Controller
  • Job Controller
  • Pod AutoScaler
  • RelicaSet
  • Service Controller
  • ServiceAccount Controller
  • StatefulSet Controller
  • Volume Controller
  • Resource quota Controller

cloud-controller-manager

在 Kubernetes 启用 Cloud Provider 的时候才需要,用来配合云服务提供商的控制,也包括一系列的控制器,如:

  • Node Controller
  • Route Controller
  • Service Controller

kube-scheduler

kube-scheduler 负责分配调度 Pod 到集群内的节点上,它监听 kube-apiserver,查询还未分配 Node 的 Pod,然后根据调度策略为这些 Pod 分配节点(更新 Pod 的 NodeName 字段)。

调度器需要充分考虑诸多的因素:

  • 公平调度
  • 资源高效利用
  • QoS
  • affinity 和 anti-affinity
  • 数据本地化(data locality)
  • 内部负载干扰(inter-workload interference)
  • deadlines

Kubelet

每个节点上都运行一个 kubelet 服务进程,默认监听 10250 端口,接收并执行 master 发来的指令,管理 Pod 及 Pod 中的容器。每个 kubelet 进程会在 API Server 上注册节点自身信息,定期向 master 节点汇报节点的资源使用情况,并通过 cAdvisor 监控节点和容器的资源。

Container runtime

容器运行时(Container Runtime)是 Kubernetes 最重要的组件之一,负责真正管理镜像和容器的生命周期。Kubelet 通过 Container Runtime Interface (CRI) 与容器运行时交互,以管理镜像和容器。

kube-proxy

每台机器上都运行一个 kube-proxy 服务,它监听 API server 中 service 和 endpoint 的变化情况,并通过 iptables 等来为服务配置负载均衡(仅支持 TCP 和 UDP)。

kube-proxy 可以直接运行在物理机上,也可以以 static pod 或者 daemonset 的方式运行。

kube-proxy 当前支持一下几种实现:

  • userspace:最早的负载均衡方案,它在用户空间监听一个端口,所有服务通过 iptables 转发到这个端口,然后在其内部负载均衡到实际的 Pod。该方式最主要的问题是效率低,有明显的性能瓶颈。
  • iptables:目前推荐的方案,完全以 iptables 规则的方式来实现 service 负载均衡。该方式最主要的问题是在服务多的时候产生太多的 iptables 规则,非增量式更新会引入一定的时延,大规模情况下有明显的性能问题
  • ipvs:为解决 iptables 模式的性能问题,v1.8 新增了 ipvs 模式,采用增量式更新,并可以保证 service 更新期间连接保持不断开
  • winuserspace:同 userspace,但仅工作在 windows 上。

Kubernetes 架构

K8s 设置由几个部分组成,其中一些是可选的,一些是整个系统运行所必需的。下面是 k8s 的全局架构图:

Kubernetes 有两个不同的部分构成,一个是 Master,一个是 Node。Master 负责调度资源和为客户端提供 API,客户端可以是 UI 界面或者 CLI 工具,在 Kubernetes 中 CLI 工具通常为 kubectl。 Kubernetes Master 接受使用 YAML 定义的配置文件,根据配置文件中相关信息将容器分配到其中一个 Node 上。另外,镜像库在 Kubernetes 中也起到一个很重要的角色,Kubernetes 需要从镜像库中拉取镜像基于这个镜像的容器才能成功启动。常用的镜像库有 dockerhub、阿里云镜像库等。下面图片为 Master 的架构图:

Master 有三个组件:API Server、Scheduler、Controller。API Server 提供了友好易用的 API 供外部调用,同时有很多强大的工具使得 API 调用更加简单,如 kubectl 封装了大量 API 调用,使得部署、配置更加简单。Kubernetes-dashboard 可以让用户在界面上操作 Kubernetes,而无需手动输入各个 API 的调用地址参数等信息。

当 API Server 收到部署请求后,Scheduler 会根据所需的资源,判断各节点的资源占用情况分配合适的 Node 给新的容器。判断依据包括内存、CPU、磁盘等。

Controller 负责整个集群的整体协调和健康,保证每个组件以正确的方式运行。

在图的最下边是 ETCD 数据库。如前文所述 ETCD 是分布式存储数据库,其作为 Kubernetes 的中央数据库,存储了集群的状态,组件可以通过查询 ETCD 了解集群的状态。

Kubernetes Master 分配容器到 Node 执行,Node 将会承受压力,通常情况下新容器不会运行在 Master 上。或者说 Master 是不可调度的,但是你也可以选择把 Master 同时也作为 Node,但是这并不是地道的用法。下面的为 Node 的架构图:

Kube-proxy 在 Node 中管理网络,其左右至关重要。Kube-proxy 通过管理 iptables 等方式使得 pod 到 pod 之间,和 pod 到 node 之间网络能够互通。实质上在跨主机的 pod 之间网络也能够互通。

Kubelet 负责向 api server 报告信息,并把健康状态、指标和节点状态信息存入 ETCD 中。

Docker 上文已详细介绍这里就不多做阐述。

Supervisord 保证 Docker 和 kubelet 一直在运行中,supervisord 并不是必须组件,可以使用其他类似组件替换。

Pod 是可以在 Kubernetes 中创建和管理的最小可部署计算单元。一个 POD 中可以包含多个容器,但 Kubernetes 仅管理 pod。如果多个容器运行在一个 POD 中,就相当于这些容器运行在同一台主机中,需要注意端口占用问题。

参考资料

https://yeasy.gitbooks.io/docker_practice/content/introduction/what.html

https://yeasy.gitbooks.io/docker_practice/content/introduction/why.html

https://docs.docker.com/storage/storagedriver/

https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/

http://k8s.docker8.com/

https://www.youtube.com/watch?v=zeS6OyDoy78

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

· 16 分钟阅读

Choerodon猪齿鱼是一个全场景效能平台,是基于Kubernetes的容器编排和管理能力,整合DevOps工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理,并提供IoT、支付、数据、智能洞察、企业应用市场等业务组件,来帮助企业聚焦于业务,加速数字化转型。

2018年8月24日,Choerodon猪齿鱼发布0.9版本,本次更新对知识管理、敏捷管理、持续交付等各项服务增加了新的功能,并对一些功能细节做了进一步优化,欢迎各位更新体验,同时特别感谢社区中的朋友给Choerodon猪齿鱼提出的诸多中肯意见。

  • 发布版本:0.9
  • 发布时间:2018年8月24日
  • 功能范围:知识管理、敏捷管理、持续交付、测试管理以及微服务开发框架

下面就为大家带来详细的版本更新介绍!

新增功能

1.知识管理

  • 知识管理界面添加了多语言支持和按钮权限

  • 用户登录知识管理系统时自动同步Choerodon平台上的用户基本信息

  • 知识管理系统编辑器添加了Markdown语法

同时,知识管理页面添加删除空间的功能,方便对空间进行管理。

2.敏捷管理

敏捷管理服务新增了迭代速度图、史诗报告、统计图三个报告,并且可以对版本、史诗进行拖动排序,详情如下:

  • 迭代速度图功能:用户可以通过选择故事点、问题计数、剩余时间查看不同冲刺对应的问题完成比例柱状图,用于跟踪当前项目下所有冲刺已完成的工时量。水平x轴代表冲刺,垂直y轴代表统计值,可以通过“单位“下拉选择框选择故事点、剩余时间、问题计数中的任一维度查看对应报告统计信息。

  • 史诗报告:用户可以选择不同史诗,通过故事点、问题计数、剩余时间查看当前冲刺的已完成、未完成、未预估的问题,同时还可以查看对应的汇总数据,跟踪未完成或未分配问题来管理团队的开发进度。横坐标代表时间,左侧纵坐标代表统计值,右侧纵坐标代表问题计数,点击问题名称,能跳转至问题详情页。

  • 统计图功能:用户可以根据经办人、模块、问题类型、修复版本、优先级、状态、冲刺、史诗、解决结果查看项目下的问题统计饼图。按图表的图例来区别筛选出的各类问题数量占所有问题数量的百分比。停放在不同的区域时,显示其具体名称、包含的问题数和所占百分比。

  • 版本/史诗拖动排序功能:用户可以在版本管理界面、待办事项界面对版本/史诗进行拖动排序。

除此之外,敏捷管理服务新增了agile-service基于Spock编写的单元测试,并在问题详情中添加创建分支功能,若用户修改问题状态为已完成时,会自动生成该状态下的问题解决日志。

3.持续交付

持续交付增加如下的功能:

  • 采用GitOps方式重构部署流程 持续交付采用GitOps模型重构,持续交付环境流水线中,各个环境增加存放k8s部署文件的git库,部署相关操作时先通过操作部署文件git库,再触发环境客户端执行。Git库中文件的状态既是环境中实际运行应用的状态。通过GitOps,可以轻松使对象进行恢复和迁移。

  • 新增环境总览模块,以便于方便管理某环境的部署相关实体 环境总览页面包含了某个环境内所有与应用部署相关的详情,其中主要包括了该环境中各应用实例的具体信息,如:实例状态、名称、应用版本、实例的各种容器信息、日志、网络以及域名的相关信息。所属项目成员均能通过环境总览页面直观的获取到上述信息,部署管理员能在此页面对所选的某个环境下与部署相关的实体进行管理和操作。总的来说,环境总览既是某个所选环境的快捷管理入口,又是此环境的状态显示器。

  • 安装实例插入相关平台标签

  • 新增前端API测试

  • 增加环境总览相关接口

  • 部署时自动给应用实例中k8s对象插入标签,应用chart中不需要在部署文件中额外添加微服务、日志等其他平台标签

  • 部署支持应用chart中存在依赖关系的复杂chart应用

4.测试管理

测试管理此次主要增加以下几个功能:

  • 增加循环导出功能,用户可将循环的内容导出为excel
  • 增加循环跨版本克隆功能,用户可将测试循环复制到其他版本中复用
  • 增加仪表盘展示界面
  • 增加部分单元测试和部分API测试
  • 增加了创建测试用例时的名称校验
  • 用例详情中的执行记录中增加循环转跳,用户可在用例详情中的执行表格中直接转跳
  • 增加用例管理的默认搜索,不需要先选择字段再进行选择了
  • 关联缺陷时支持转跳,方便新建缺陷

另外,此次更新界面增加了多种言功能,可以配合平台进行多语言切换;问题编号增加了转跳,用户不必切换到敏捷界面查看缺陷;循环详情界面增加人员筛选功能,用户可筛选指派人或执行方。

5.微服务开发框架

微服务开发框架增加了如下的功能:

  • 新增事务定义,开发者能更好的实现分布式事务,避免了分布式场景下产生数据不一致的问题
  • 新增事务实例,开发者可以查看所有运行的事务,可以查看事务中任务的状态以及状态详情
  • 新增角色标签,平台管理员可以查看标签的说明与层级,角色标签只能在同层级的角色中添加
  • 新增仪表盘,用户能在不同的层级使用仪表盘实现信息概览
  • 新增仪表盘配置,平台管理员能设置用于展示的仪表盘卡片
  • 新增邮件模板,平台管理员和组织管理员可定义发送给用户的邮件内容
  • 新增邮箱配置,平台管理员可设置发件邮箱的信息
  • 新增用户批量导入,组织管理员可以下载导入模板,填写后上传文件批量导入用户数据
  • 新增UI组件,开发者可以引用UI组件,快速进行前端开发

功能优化

1.知识管理

  • 修改了知识管理界面的空间列表显示内容
  • 修改了知识管理系统站点favicon
  • 修改系统空间首页内容和布局
  • 修改知识管理系统侧边栏、人员信息页、创建页面入口页
  • 修改了知识管理系统通知弹出框的显示内容
  • 优化了知识管理系统页面的加载性能和使用oauth认证的性能
  • 知识管理页面的空间列表可显示树形空间结构
  • 优化了创建空间过程对用户的状态提示
  • 优化了所有更新页的显示
  • 删除了知识管理系统头部导航栏的人员列表按钮和系统中创建空间的功能

2.敏捷管理

  • agile-service消息机制由Kafka修改为Saga
  • 优化了版本报告图和燃尽图请求时间过长,待办事项界面中史诗和版本加载过慢的问题
  • 调整了待办事项界面样式和版本状态样式
  • 重构了日志处理逻辑

3.持续交付

  • 重写部署实例values,支持标准yml格式
  • 网络多端口支持,label selector 支持,NodePort类型支持
  • 修改网络界面
  • 通过填写标签创建网络
  • 增加网络的 NodePort 类型配置
  • 移除网络关联的应用版本
  • 未修改配置信息不可重新部署
  • 优化各模块数据加载效果
  • 修改容器日志选择背景色,和非编辑状态不可复制

4.测试管理

  • 优化了报表、测试循环、测试步骤、缺陷等查询接口
  • 事件消息改为saga模式
  • 执行详情和用例管理中测试步骤可表格内编辑,降低操作成本
  • 测试状态图标样式变更
  • 测试摘要页面接口整合优化
  • 用例管理页面增加展示内容,排序去掉多余字段
  • 优化报表页面布局,列宽不会因为展开变动

5.微服务开发框架

  • API测试优化为在界面上即可进行API测试操作,输入测试数据并查看结果,且支持其他账号的授权。
  • 修改asgard服务ci,deploy依赖,修改chart部署服务。
  • asgard服务优化,taskInstance的返回值由map json修改为json。
  • API测试中,后端解析dto中的注释,将注释显示在界面。
  • 页面优化为第一个input框自动获取光标。

缺陷修复

1.知识管理

  • 修复系统使用https时,回调地址错误的问题
  • 修复用户在知识管理系统中无法退出登录的问题
  • 修复了空间名字中带有"."的时候,空间显示错误的问题
  • 修复了系统设置按钮的权限判断错误的问题

2.敏捷管理

  • 修复待办事项界面内存溢出问题
  • 修复燃尽图数、累积流图数据不一致问题
  • 修复模块管理创建模块后数据展示不一致问题

3.测试管理

  • 修复测试循环和步骤分页显示问题
  • 修复删除测试用例后的计数不会级联删除的问题
  • 修复删除执行后的页面不会全局自动刷新的问题
  • 修复执行详情界面宽度兼容错误导致看不到编辑按钮的问题
  • 修复了报表的分页数据错误的问题

4.微服务开发框架

  • 修复重新部署oauth后要清缓存才能登录的问题。
  • 修复切换组织/项目后,菜单面板没有收起的问题。
  • 修复手机登录页重定向问题。
  • 修复choerodonui国际化显示不正确的问题。
  • 修复LDAP同步用户,无法全部同步的问题。
  • 修复实例管理部分服务没有配置信息的问题。
  • 修复解析权限的时候,可能报重复字段,导致插入失败的问题。
  • 修复角色分配界面,移除用户角色可能不发送data的问题。

更加详细的内容,请参阅Release Notes官网

欢迎通过我们的GitHub猪齿鱼社区进行反馈与贡献,帮助Choerodon猪齿鱼不断成长,我们将持续迭代优化,敬请期待。

· 26 分钟阅读

众所周知,微服务架构解决了很多问题,通过分解复杂的单体式应用,在功能不变的情况下,使应用被分解为多个可管理的服务,为采用单体式编码方式很难实现的功能提供了模块化的解决方案。同时,每个微服务独立部署、独立扩展,使得持续化集成成为可能。由此,单个服务很容易开发、理解和维护。

微服务架构为开发带来了诸多好处的同时,也引发了很多问题。比如服务运维变得更复杂,服务之间的依赖关系更复杂,数据一致性难以保证。

本篇文章将讨论和介绍Choerodon猪齿鱼是如何保障微服务架构的数据一致性的。

主要内容包括 :

  • 传统应用使用本地事务保持一致性
  • 多数据源下的分布式事务
  • 微服务架构中应满足数据最终一致性原则
  • 使用Event Sourcing保证微服务的最终一致性
  • 使用可靠事件模式保证微服务的最终一致性
  • 使用Saga保证微服务的最终一致性

下面将通过一个实例来分别介绍这几种模式。

在Choerodon 猪齿鱼的 DevOps流程中,有这样一个步骤。

  1. 用户在Choerodon 平台上创建一个项目;
  2. DevOps 服务对应创建一个项目;
  3. DevOps 为该项目 在 Gitlab 上创建对应的group。

传统应用使用本地事务保持一致性

在讲微服务架构的数据一致性之前,先介绍一下传统关系型数据库是如何保证一致性的,从关系型数据库中的ACID理论讲起。

ACID 即数据库事务正确执行的四个基本要素。分别是:

  • 原子性(Atomicity):要么全部完成,要么全部不完成,不存在中间状态
  • 一致性(Consistency):事务必须始终保持系统处于一致的状态
  • 隔离性(Isolation):事务之间相互隔离,同一时间仅有一个请求用于同一数据
  • 持久性(Durability):事务一旦提交,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚

可以通过使用数据库自身的ACID Transactions,将上述步骤简化为如下伪代码:

transaction.strat();
createProject();
devopsCreateProject();
gitlabCreateGroup();
transaction.commit();

这个过程可以说是十分简单,如果在这一过程中发生失败,例如DevOps创建项目失败,那么该事务做回滚操作,使得最终平台创建项目失败。由于传统应用一般都会使用一个关系型数据库,所以可以直接使用 ACID transactions。 保证了数据本身不会出现不一致。为保证一致性只需要:开始一个事务,改变(插入,删除,更新)很多行,然后提交事务(如果有异常时回滚事务)。

随着业务量的不断增长,单数据库已经不足以支撑庞大的业务数据,此时就需要对应用和数据库进行拆分,于此同时,也就出现了一个应用需要同时访问两个或者两个以上的数据库或多个应用分别访问不同的数据库的情况,数据库的本地事务则不再适用。

为了解决这一问题,分布式事务应运而生。

多数据源下的分布式事务

想象一下,如果很多用户同时对Choerodon 平台进行创建项目的操作,应用接收的流量和业务数据剧增。一个数据库并不足以存储所有的业务数据,那么我们可以将应用拆分成IAM服务和DevOps服务。其中两个服务分别使用各自的数据库,这样的情况下,我们就减轻了请求的压力和数据库访问的压力,两个分别可以很明确的知道自己执行的事务是成功还是失败。但是同时在这种情况下,每个服务都不知道另一个服务的状态。因此,在上面的例子中,如果当DevOps创建项目失败时,就无法直接使用数据库的事务。

那么如果当一个事务要跨越多个分布式服务的时候,我们应该如何保证事务呢?

为了保证该事务可以满足ACID,一般采用2PC或者3PC。 2PC(Two Phase Commitment Protocol),实现分布式事务的经典代表就是两阶段提交协议。2PC包括准备阶段和提交阶段。在此协议中,一个或多个资源管理器的活动均由一个称为事务协调器的单独软件组件来控制。

我们为DevOps服务分配一个事务管理器。那么上面的过程可以整理为如下两个阶段:

准备阶段:

提交/回滚阶段:

2PC 提供了一套完整的分布式事务的解决方案,遵循事务严格的 ACID 特性。

但是,当在准备阶段的时候,对应的业务数据会被锁定,直到整个过程结束才会释放锁。如果在高并发和涉及业务模块较多的情况下,会对数据库的性能影响较大。而且随着规模的增大,系统的可伸缩性越差。同时由于 2PC引入了事务管理器,如果事务管理器和执行的服务同时宕机,则会导致数据产生不一致。虽然又提出了3PC 将2PC中的准备阶段再次一分为二的来解决这一问题,但是同样可能会产生数据不一致的结果

微服务架构中应满足数据最终一致性原则

不可否认,2PC 和3PC 提供了解决分布式系统下事务一致性问题的思路,但是2PC同时又是一个非常耗时的复杂过程,会严重影响系统效率,在实践中我们尽量避免使用它。所以在分布式系统下无法直接使用此方案来保证事务。

对于分布式的微服务架构而言,传统数据库的ACID原则可能并不适用。首先微服务架构自身的所有数据都是通 过API 进行访问。这种数据访问方式使得微服务之间松耦合,并且彼此之间独立非常容易进行性能扩展。其次 不同服务通常使用不同的数据库,甚至并不一定会使用同一类数据库,反而使用非关系型数据库,而大部分的 非关系型数据库都不支持2PC。

在这种情况下,又如何解决事务一致性问题呢?

一个最直接的办法就是考虑数据的强一致性。根据Eric Brewer提出的CAP理论,只能在数据强一致性(C)和可用性(A)之间做平衡。

CAP 是指在一个分布式系统下,包含三个要素:Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性),并且三者不可得兼。

  • 一致性(Consistency),是指对于每一次读操作,要么都能够读到最新写入的数据,要么错误,所有数据变动都是同步的。
  • 可用性(Availability),是指对于每一次请求,都能够得到一个及时的、非错的响应,但是不保证请求的结果是基于最新写入的数据。即在可以接受的时间范围内正确地响应用户请求。
  • 分区容错性(Partition tolerance),是指由于节点之间的网络问题,即使一些消息丢包或者延迟,整个系统仍能够提供满足一致性和可用性的服务。

关系型数据库单节点保证了数据强一致性(C)和可用性(A),但是却无法保证分区容错性(P)。

然而在分布式系统下,为了保证模块的分区容错性(P),只能在数据强一致性(C)和可用性(A)之间做平衡。具体表现为在一定时间内,可能模块之间数据是不一致的,但是通过自动或手动补偿后能够达到最终的一致。

可用性一般是更好的选择,但是在服务和数据库之间维护事务一致性是非常根本的需求,微服务架构中应该选择满足最终一致性。

那么我们应该如何实现数据的最终一致性呢?

使用Event Sourcing保证微服务的最终一致性

什么是Event Sourcing(事件溯源)?

一个对象从创建开始到消亡会经历很多事件,传统的方式是保存这个业务对象当前的状态。但更多的时候,我们也许更关心这个业务对象是怎样达到这一状态的。Event Sourcing从根本上和传统的数据存储不同,它存储的不是业务对象的状态,而是有关该业务对象一系列的状态变化的事件。只要一个对象的状态发生变化,服务就需要自动发布事件来附加到事件的序列中。这个操作本质上是原子的。

现在将上面的订单过程用Event Sourcing 进行改造,将订单变动的一个个事件存储起来,服务监听事件,对订单的状态进行修改。

可以看到 Event Sourcing 完整的描述了对象的整个生命周期过程中所经历的所有事件。由于事件是只会增加不会修改,这种特性使得领域模型十分的稳定。

Event sourcing 为整体架构提供了一些可能性,但是将应用程序的每个变动都封装到事件保存下来,并不是每个人都能接受的风格,而且大多数人都认为这样很别扭。同时这一架构在实际应用实践中也不是特别的成熟

使用可靠事件模式保证微服务的最终一致性

可靠事件模式属于事件驱动架构,微服务完成操作后向消息代理发布事件,关联的微服务从消息代理订阅到该 事件从而完成相应的业务操作,关键在于可靠事件投递和避免事件重复消费。

可靠事件投递有两个特性:

  1. 每个服务原子性的完成业务操作和发布事件;
  2. 消息代理确保事件投递至少一次 (at least once)。避免重复消费要求消费事件的服务实现幂等性。

有两种实现方式:

1. 本地事件表

本地事件表方法将事件和业务数据保存在同一个数据库中,使用一个额外的“事件恢复”服务来恢 复事件,由本地事务保证更新业务和发布事件的原子性。考虑到事件恢复可能会有一定的延时,服务在完成本 地事务后可立即向消息代理发布一个事件。

使用本地事件表将事件和业务数据保存在同一个数据库中,会在每个服务存储一份数据,在一定程度上会造成代码的重复冗余。同时,这种模式下的业务系统和事件系统耦合比较紧密,额外增加的事件数据库操作也会给数据库带来额外的压力,可能成为瓶颈。

2. 外部事件表

针对本地事件表出现的问题,提出外部事件表方法,将事件持久化到外部的事件系统,事件系统 需提供实时事件服务以接收微服务发布的事件,同时事件系统还需要提供事件恢复服务来确认和恢复事件。

借助Kafka和可靠事件,可以通过如下代码实现订单流程。

// IAM ProjectService

@Service
@RefreshScope
public class ProjectServiceImpl implements ProjectService {

private ProjectRepository projectRepository;

private UserRepository userRepository;

private OrganizationRepository organizationRepository;

@Value("${choerodon.devops.message:false}")
private boolean devopsMessage;

@Value("${spring.application.name:default}")
private String serviceName;

private EventProducerTemplate eventProducerTemplate;

public ProjectServiceImpl(ProjectRepository projectRepository,
UserRepository userRepository,
OrganizationRepository organizationRepository,
EventProducerTemplate eventProducerTemplate) {
this.projectRepository = projectRepository;
this.userRepository = userRepository;
this.organizationRepository = organizationRepository;
this.eventProducerTemplate = eventProducerTemplate;
}

@Transactional(rollbackFor = CommonException.class)
@Override
public ProjectDTO update(ProjectDTO projectDTO) {
ProjectDO project = ConvertHelper.convert(projectDTO, ProjectDO.class);
if (devopsMessage) {
ProjectDTO dto = new ProjectDTO();
CustomUserDetails details = DetailsHelper.getUserDetails();
UserE user = userRepository.selectByLoginName(details.getUsername());
ProjectDO projectDO = projectRepository.selectByPrimaryKey(projectDTO.getId());
OrganizationDO organizationDO = organizationRepository.selectByPrimaryKey(projectDO.getOrganizationId());
ProjectEventPayload projectEventMsg = new ProjectEventPayload();
projectEventMsg.setUserName(details.getUsername());
projectEventMsg.setUserId(user.getId());
if (organizationDO != null) {
projectEventMsg.setOrganizationCode(organizationDO.getCode());
projectEventMsg.setOrganizationName(organizationDO.getName());
}
projectEventMsg.setProjectId(projectDO.getId());
projectEventMsg.setProjectCode(projectDO.getCode());
Exception exception = eventProducerTemplate.execute("project", EVENT_TYPE_UPDATE_PROJECT,
serviceName, projectEventMsg, (String uuid) -> {
ProjectE projectE = projectRepository.updateSelective(project);
projectEventMsg.setProjectName(project.getName());
BeanUtils.copyProperties(projectE, dto);
});
if (exception != null) {
throw new CommonException(exception.getMessage());
}
return dto;
} else {
return ConvertHelper.convert(
projectRepository.updateSelective(project), ProjectDTO.class);
}
}
}
// DEVOPS DevopsEventHandler
@Component
public class DevopsEventHandler {

private static final String DEVOPS_SERVICE = "devops-service";
private static final String IAM_SERVICE = "iam-service";

private static final Logger LOGGER = LoggerFactory.getLogger(DevopsEventHandler.class);

@Autowired
private ProjectService projectService;
@Autowired
private GitlabGroupService gitlabGroupService;

private void loggerInfo(Object o) {
LOGGER.info("data: {}", o);
}

/**
* 创建项目事件
*/
@EventListener(topic = IAM_SERVICE, businessType = "createProject")
public void handleProjectCreateEvent(EventPayload<ProjectEvent> payload) {
ProjectEvent projectEvent = payload.getData();
loggerInfo(projectEvent);
projectService.createProject(projectEvent);
}

/**
* 创建组事件
*/
@EventListener(topic = DEVOPS_SERVICE, businessType = "GitlabGroup")
public void handleGitlabGroupEvent(EventPayload<GitlabGroupPayload> payload) {
GitlabGroupPayload gitlabGroupPayload = payload.getData();
loggerInfo(gitlabGroupPayload);
gitlabGroupService.createGroup(gitlabGroupPayload);
}
}

使用Saga保证微服务的最终一致性 - Choerodon的解决方案

Saga是来自于1987年Hector GM和Kenneth Salem论文。在他们的论文中提到,一个长活事务Long lived transactions (LLTs) 会相对较长的占用数据库资源。如果将它分解成多个事务,只要保证这些事务都执行成功, 或者通过补偿的机制,来保证事务的正常执行。这一个个的事务被他们称之为Saga。

Saga将一个跨服务的事务拆分成多个事务,每个子事务都需要定义一个对应的补偿操作。通过异步的模式来完 成整个Saga流程。

在Choerodon中,将项目创建流程拆分成多个Saga。

// ProjectService

@Transactional
@Override
@Saga(code = PROJECT_CREATE, description = "iam创建项目", inputSchemaClass = ProjectEventPayload.class)
public ProjectDTO createProject(ProjectDTO projectDTO) {

if (projectDTO.getEnabled() == null) {
projectDTO.setEnabled(true);
}
final ProjectE projectE = ConvertHelper.convert(projectDTO, ProjectE.class);
ProjectDTO dto;
if (devopsMessage) {
dto = createProjectBySaga(projectE);
} else {
ProjectE newProjectE = projectRepository.create(projectE);
initMemberRole(newProjectE);
dto = ConvertHelper.convert(newProjectE, ProjectDTO.class);
}
return dto;
}

private ProjectDTO createProjectBySaga(final ProjectE projectE) {
ProjectEventPayload projectEventMsg = new ProjectEventPayload();
CustomUserDetails details = DetailsHelper.getUserDetails();
projectEventMsg.setUserName(details.getUsername());
projectEventMsg.setUserId(details.getUserId());
ProjectE newProjectE = projectRepository.create(projectE);
projectEventMsg.setRoleLabels(initMemberRole(newProjectE));
projectEventMsg.setProjectId(newProjectE.getId());
projectEventMsg.setProjectCode(newProjectE.getCode());
projectEventMsg.setProjectName(newProjectE.getName());
OrganizationDO organizationDO =
organizationRepository.selectByPrimaryKey(newProjectE.getOrganizationId());
projectEventMsg.setOrganizationCode(organizationDO.getCode());
projectEventMsg.setOrganizationName(organizationDO.getName());
try {
String input = mapper.writeValueAsString(projectEventMsg);
sagaClient.startSaga(PROJECT_CREATE, new StartInstanceDTO(input, "project", newProjectE.getId() + ""));
} catch (Exception e) {
throw new CommonException("error.organizationProjectService.createProject.event", e);
}
return ConvertHelper.convert(newProjectE, ProjectDTO.class);
}
// DevopsSagaHandler
@Component
public class DevopsSagaHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(DevopsSagaHandler.class);
private final Gson gson = new Gson();

@Autowired
private ProjectService projectService;
@Autowired
private GitlabGroupService gitlabGroupService;

private void loggerInfo(Object o) {
LOGGER.info("data: {}", o);
}

/**
* 创建项目saga
*/
@SagaTask(code = "devopsCreateProject",
description = "devops创建项目",
sagaCode = "iam-create-project",
seq = 1)
public String handleProjectCreateEvent(String msg) {
ProjectEvent projectEvent = gson.fromJson(msg, ProjectEvent.class);
loggerInfo(projectEvent);
projectService.createProject(projectEvent);
return msg;
}

/**
* 创建组事件
*/
@SagaTask(code = "devopsCreateGitLabGroup",
description = "devops 创建 GitLab Group",
sagaCode = "iam-create-project",
seq = 2)
public String handleGitlabGroupEvent(String msg) {
ProjectEvent projectEvent = gson.fromJson(msg, ProjectEvent.class);
GitlabGroupPayload gitlabGroupPayload = new GitlabGroupPayload();
BeanUtils.copyProperties(projectEvent, gitlabGroupPayload);
loggerInfo(gitlabGroupPayload);
gitlabGroupService.createGroup(gitlabGroupPayload, "");
return msg;
}
}

可以发现,Saga和可靠事件模式很相似,都是将微服务下的事务作为一个个体,然后通过有序序列来执行。但是在实现上,有很大的区别。

可靠事件依赖于Kafka,消费者属于被动监听Kafka的消息,鉴于Kafka自身的原因,如果对消费者进行横向扩展,效果并不理想。 

而在 Saga 中,我们为 Saga 分配了一个orchestrator作为事务管理器,当服务启动时,将服务中所有的 SagaTask 注册到管理器中。当一个 Saga 实例通过sagaClient.startSaga启动时,服务消费者就可以通过轮询的方式主动拉取到该实例对应的Saga数据,并执行对应的业务逻辑。执行的状态可以通过事务管理器进行查看,展现在界面上。

通过Choerodon的事务定义界面,将不同服务的SagaTask 收集展示,可以看到系统中的所有Saga 定义以及所属的微服务。同时,在每一个Saga 定义的详情中,可以详细的了解到该Saga的详细信息:

在这种情况下,当并发量增多或者 SagaTask 的数量很多的时候,可以很便捷的对消费者进行扩展。 

Saga的补偿机制

Saga支持向前和向后恢复:

  • 向后恢复:如果任意一个子事务失败,则补偿所有已完成的事务
  • 向前恢复:如果子事务失败,则重试失败的事务

Choerodon 采用的是向前恢复,通过界面可以很方便的对事务的信息进行检索,当Saga发生失败时,也可以看到失败的原因,并且手动进行重试。

  通过Choerodon的事务实例界面,可以查询到系统中运行的所有Saga实例,掌握实例的运行状态,并对失败的实例进行手动的重试:

对于向前恢复而言,理论上我们的子事务最终总是会成功的。但是在实际的应用中,可能因为一些其他的因素,造成失败,那么就需要有对应的故障恢复回滚的机制。

使用Saga的要求 

Saga是一个简单易行的方案,使用Saga的两个要求: 

  • 幂等:幂等是每个Saga 多次执行所产生的影响应该和一次执行的影响相同。一个很简单的例子,上述流程中,如果在创建项目的时候因为网络问题导致超时,这时如果进行重试,请求恢复。如果没有幂等,就可能创建了两个项目。
  • 可交换:可交换是指在同一层级中,无论先执行那个Saga最终的结果都应该是一样的。

综合比较

2PC是一个阻塞式,严格满足ACID原则的方案,但是因为性能上的原因在微服务架构下并不是最佳 的方案。

Event sourcing 为整体架构提供了一些可能性。但是如果随着业务的变更,事件结构自身发生一定的变化时,需要通过额外的方式来进行补偿,而且当下并没有一个成熟完善的框架。

基于事件驱动的可靠事件是建立在消息队列基础上,每一个服务,除了自己的业务逻辑之外还需要额外的事件 表来保存当前的事件的状态,所以相当于是把集中式的事务状态分布到了每一个服务当中。虽然服务之间去中 心化,但是当服务增多,服务之间的分布式事务带来的应用复杂度也再提高,当事件发生问题时,难以定位。

而Saga降低了数据一致性的复杂度,简单易行,将所有的事务统一可视化管理,让运维更加简单,同时每一个 消费者可以进行快速的扩展,实现了事务的高可用。

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

· 5 分钟阅读

什么是猪齿鱼

Choerodon猪齿鱼 是一个全场景效能平台,基于Kubernetes的容器编排和管理能力,整合DevOps工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理,并提供IoT、支付、数据、智能洞察、企业应用市场等业务组件,来帮助企业聚焦于业务,加速数字化转型。

直播培训有什么?

本次直播培训将讲解和分享Choerodon猪齿鱼的核心功能和应用实践。

8月14日

Choerodon 猪齿鱼敏捷管理

  1. 敏捷相关概念
  2. 敏捷流程
  3. 敏捷会议
  4. 如何结合猪齿鱼平台进行敏捷管理

Choerodon 猪齿鱼持续交付

  1. 项目的创建
  2. 项目角色的分配
  3. 应用管理
  4. 开发流水线
  5. 应用版本
  6. 部署流水线
  7. 应用发布
  8. 应用市场
  9. 应用导入导出及相关资源扫回逻辑

8月15日

Choerodon猪齿鱼后端微服务开发

  1. Choerodon微服务框架介绍
  2. Choerodon环境搭建
  3. 如何根据模板创建应用
  4. 文件结构讲解
  5. CI/CD
  6. starters介绍
  7. 初始化数据库
  8. 实体类映射
  9. 接口编写
  10. 权限配置
  11. 服务注册
  12. 路由配置
  13. 开发模式介绍

8月16日

Choerodon猪齿鱼测试管理与知识管理

测试管理

  1. 测试用例
  2. 测试循环
  3. 测试执行
  4. 执行结果与缺陷关联
  5. 报表的使用
  6. 状态自定义

知识管理

  1. 空间的创建和其他操作
  2. 文档的创建和编辑
  3. 文档交互

Choerodon猪齿鱼前端开发

  1. 开发环境搭建
  2. 开发新模块
  3. 开发新页面

直播平台

IT大咖说(搜索Choerodon猪齿鱼收藏直播间)

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献:

· 32 分钟阅读

在此之前您可能听说过“GitOps”,但并不知道它到底是什么,除了GitOps,您可能还听说过DevOps,或者AIOps、GOps等,是的,现在是“Ops”盛行的时代。

GitOps是一种实现持续交付的模型,它的核心思想是将应用系统的声明性基础架构和应用程序存放在Git的版本控制库中。Choerodon猪齿鱼在构建持续交付流水线时参考了GitOps,并进行了实践,俗话说“兵马未动,理论先行”,在本文中,将重点阐述GitOps工作流程的原理和模式,以及将它们应用在生产和大规模运行Kubernetes中的一些实践经验。 在下一篇文章中,将介绍Choerodon猪齿鱼是如何实践和落地GitOps,从而构建了一个可重复且可靠的交付过程。

GitOps,90%的最佳实践,10%有意思的新东西需要我们去构建。 —— 《​GitOps - Operations by Pull Request》来自:https://www.weave.works

这篇文章是根据Weave Cloud的几篇关于GitOps的文章翻译整理而来:

GitOps

GitOps: Operations by Pull Request

The GitOps Pipeline - Part 2

GitOps - Part 3: Observability

GitOps - Part 4: Application Delivery Compliance and Secure CICD

主要内容:

  • 什么是GitOps?
    • GitOps的主要优点
  • GitOps的应用场景——适合云原生的持续交付
  • GitOps的基本原则
  • 最佳实践
    • 拉式流水线——Pull Request操作
    • GitOps工作流
    • 可视化
    • 应用交付的合规性和安全的CI/CD
  • GitOps带来的价值

什么是GitOps?

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

将Git作为交付流水线的核心,每个开发人员都可以提交拉取请求(Pull Request)并使用Gi​​t来加速和简化Kubernetes的应用程序部署和运维任务。通过使用像Git这样的简单熟悉工具,开发人员可以更高效地将注意力集中在创建新功能而不是运维相关任务上(例如,应用系统安装、配置、迁移等)。

GitOps: versioned CI/CD on top of declarative infrastructure. Stop scripting and start shipping. https://t.co/SgUlHgNrnY — Kelsey Hightower (@kelseyhightower) January 17, 2018

作为一个有经验项目管理者,或者产品负责人,你一定会思考一个问题:我们项目组在开发过程中应如何管理分支?不错,分支管理将和项目组开发人员日夜伴随,如果采用了一个不合适的分支管理模型,那么可以想象兄弟们得多么的痛苦。

Okay,那么就从分支管理模型开始......

GitOps的主要优点

通过GitOps,当使用Git提交基础架构代码更改时,自动化的交付流水线会将这些更改应用到应用程序的实际基础架构上。但是GitOps的想法远不止于此——它还会使用工具将整个应用程序的实际生产状态与基础架构源代码进行比较,然后它会告诉集群哪些基础架构源代码与实际环境不匹配。

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

将GitOps理论方法应用在持续交付流水线上,有诸多优势和特点:

  • 安全的云原生CI/CD管道模型 
  • 更快的平均部署时间和平均恢复时间 
  • 稳定且可重现的回滚(例如,根据Git恢复/回滚/ fork)
  • 与监控和可视化工具相结合,对已经部署的应用进行全方位的监控

GitOps应用场景——满足云原生环境下的持续交付

作为CI / CD流水线的方案,GitOps被描述为软件开发过程的“圣杯”。 由于没有单一工具可以完成流水线中所需的所有工作,因此可以自由地为流水线的不同部分选择最佳工具。可以从开源生态系统中选择一组工具,也可以从封闭源中选择一组工具,或者根据使用情况,甚至可以将它们组合在一起,其实,创建流水线最困难的部分是将所有部件粘合在一起。

不管如何选择构造自己的交付流水线,将基于Git(或者其他版本控制工具)的GitOps最佳实践应用在交付流水线中都是一个不二选择,这将使构建持续交付流水线,以及后续的推广变得更加容易,这不仅从技术角度而且从文化角度来看都是如此。

当然,GitOps也不是万能的,它也有相应的应用场景。

不可变基础设施

应用都需要运行在多台机器上,它们被组织成不同的环境,例如开发环境、测试环境和生产环境等等。需要将相同的应用部署到不同的机器上。通常需要系统管理员确保所有的机器都处于相同的状态。接着所有的修改、补丁、升级需要在所有的机器中进行。随着时间的推移,很难再确保所有的机器处于相同的状态,同时越来越容易出错。这就是传统的可变架构中经常出现的问题。这时我们有了不可变架构,它将整个机器环境打包成一个单一的不可变单元,而不是传统方式仅仅打包应用。这个单元包含了之前所说的整个环境栈和应用所有的修改、补丁和升级,这就解决了前面的问题。 —— 摘自InfoQ的《关于不可变架构以及为什么需要不可变架构》作者 百占辉

“不可变基础设施”这一概念不是刚刚冒出来的,它也不是必须需要容器技术。然而,通过容器,它变得更易于理解,更加实用,并引起了业内广泛注意。“不可变基础设施”让我们以全新的方式理解和面对应用系统,尤其是使以微服务为代表的分布式系统在部署、运营等方面变得不那么复杂,而有很好的可控性。

那么,如何比较方便地在实际的生产过程中应用“不可变基础设施”,这给业界也提出了另外一个问题。GitOps是在具体Kubernetes的应用实践中出现的,GitOps需要依托于“不可变基础架构”才能发挥其作用。在一定程度上说,“不可变基础架构”为GitOps的出现创造了必要的条件,反过来GitOps应用Kubernetes的容器编排能力,能够迅速的使用镜像搭建出应用系统所需的组件。

声明性容器编排

Kubermetes作为一个云原生的工具,可以把它的“声明性”看作是“代码”,声明意味着配置由一组事实而不是一组指令组成,例如,“有十个redis服务器”,而不是“启动十个redis服务器,告诉我它是否有效”。

借助Kubermetes的声明性特点,应用系统的整个配置文件集可以在Git库中进行版本控制。通过使用Git库,应用程序更容易部署到Kubernetes中,以及进行版本回滚。更重要的是,当灾难发生时,群集的基础架构可以从Git库中可靠且快速地恢复。

Kubernetes等云原生工具的声明性体现在可以对实例、容器、网络、存储、CPU等配置通过一组代码方便的表达出来,Kubernetes等云原生工具可以利用这些配置代码运行出来一套基于容器的应用系统,例如YMAL,

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.choerodon.com.cn/operation-choerodon-dev/nginx-demo:1.13.5-alpine
ports:
- containerPort: 80

GitOps充分利用了不可变基础设施和声明性容器编排,通过GitOps可以轻松地管理多个部署。为了最大限度地降低部署后的变更风险,无论是有意还是偶然的“配置偏差”,GitOps构建了一个可重复且可靠的部署过程,在整个应用系统宕机或者损坏情况下,为快速且完全恢复提供了所需条件。  

GitOps的基本原则

以下是几条在云原生环境中,GitOps的原则:

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

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

  • 不应直接使用Kubectl

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

  • 调用Kubernetes 的API的接口或者控制器应该遵循 Operator 模式

    调用Kubernetes 的API的接口或者控制器应该遵循 Operator 模式(什么是Operator 模式?),集群的状态和Git库中的配置文件等要保持一致,并且查看分析它们之间的状态差异。

最佳实践

以Git作为事实的唯一真实来源

Git是每个开发人员工具包的一部分。学习起来感觉自然而且不那么令人生畏,而且工具本身也非常简单。 通过使用Git作为应用系统的事实来源,几乎可以操作所有东西。例如,版本控制,历史记录,评审和回滚都是通过Git进行的,而无需使用像kubectl这样的工具。

所以,Git是GitOps形成的最基础的内容,就像第一条原则“任何能够被描述的内容都必须存储在Git库中 ”描述的那样:通过使用Git作为存储声明性基础架构和应用程序代码的存储仓库,可以方便地监控集群,以及检查比较实际环境的状态与代码库上的状态是否一致。所以,我们的目标是描述系统相关的所有内容:策略,代码,配置,甚至监控事件和版本控制等,并且将这些内容全部存储在版本库中,在通过版本库中的内容构建系统的基础架构或者应用程序的时候,如果没有成功,则可以迅速的回滚,并且重新来过。

拉式流水线——Pull Request操作

推送流水线  

目前大多数CI / CD工具都使用基于推送的模型。基于推送的流水线意味着代码从CI系统开始,通过一系列构建测试等最终生成镜像,最后手动使用“kubectl”将任何更改推送到Kubernetes集群。

很多开发人员不愿意在CI中启动CD部署流程,或者使用命令行工具操作启动CD部署流程的原因可能是这样做会将集群的用户和密码等公布出去。虽然可以有措施保护CI / CD 脚本和命令行,但是这些操作毕竟还是在集群外部非可信区工作的。所以,类似做法是不可取的,会给系统安全带来潜在的风险。

具有集群外读/写(R/W)权限的典型推送流水线:

  • CI运行测试,输出传递到容器映像存储库。
  • CD系统自动部署容器(或根据请求,即手动)。

拉式流水线

在GitOps中,镜像被拉出并且凭证保留在集群中:

Git库是拉式流水线模式的核心,它存储应用程序和配置文件集。开发人员将更新的代码推送到Git代码库; CI工具获取更改并最终构建Docker镜像。GitOps检测到有镜像,从存储库中提取新镜像,然后在Git配置仓库中更新其YAML。然后,GitOps会检测到群集已过期,并从配置库中提取已更改的清单,并将新镜像部署到群集。

GitOps的流水线

在上节中介绍了GitOps采用拉式模式构建交付流水线,本节将详细地介绍在构建GitOps流水时需要注意哪些事情,有哪些最佳实践。

GitOps流水线

这是一个新图,显示部署上游的所有内容都围绕Git库工作的。在“拉式流水线”中讲过,开发人员将更新的代码推送到Git代码库,CI工具获取更改并最终构建Docker镜像。GitOps的Config Update检测到有镜像,从存储库中提取新镜像,然后在Git配置仓库中更新其YAML。然后,GitOps的Deploy Operator会检测到群集已过期,并从配置库中提取已更改的清单,并将新镜像部署到群集。

使用群集内部的Deploy Operator,群集凭据不会在生产环境之外公开。一旦将Deploy Operator安装到集群与Git仓库建立连接,线上环境中的任何更改都将通过具有完全回滚的Git pull请求以及Git提供的方便审计日志完成。

自动git→集群同步 

由于没有单一工具可以完成流水线中所需的所有工作,可以从开源生态系统中选择一组工具,也可以从封闭源中选择一组工具,或者根据使用情况,甚至可以将它们组合在一起,其实,创建流水线最困难的部分是将所有部件粘合在一起。要实现GitOps,必须要开发出新的组件,用于粘合这些工具,实现拉式交付流水线

部署和发布自动化是应用落实GitOps,并使交付流水线工作的基础。GitOps不仅要保证,当开发人员通过Git更新配置文件集的时候,GitOps流水线要自动根据最新的配置文件状态更新线上环境,而且GitOps还要能够实时比对Git库中配置文件集最新的状态与线上环境最新的状态保持一致。

在上节中提到了两个名词:Config UpdateDeploy Operator,根据GitOps的实践,Config Update 和 Deploy Operator是需要进行设计开发的,它们是实现GitOps流水线必须的关键组件。GitOps赋予了它们神奇的魔法,它们既是自动化容器升级和发布到线上环境的工具,可能也要负责服务、部署、网络策略甚至路由规则等任务。因此,Config Update 和 Deploy Operator是映射代码,服务和运行集群之间所有关系的“粘合剂”

当然,您可以根据具体的设计,赋予各种其他的功能,但是自动同步是一定需要的,确保如果对存储库进行任何更改,这些更改将自动部署到线上环境中

仅部署容器和配置

GitOps建议不直接将应用程序部署到线上环境中,而是将应用程序和相关配置打包成镜像,并存储到镜像库中,最后,通过镜像的方式生成容器,并部署到线上环境中。

容器为什么如此重要?在GitOps模型中,我们使用不可变基础架构模式。一旦代码在Git中提交,GitOps就不希望任何其他内容发生变化,这样可以最大限度地降低系统潜在不确定性、不一致性风险。例如,需要将相同的应用部署到不同的机器上。通常需要系统管理员确保所有的机器都处于相同的状态。接着所有的修改、补丁、升级需要在所有的机器中进行。随着时间的推移,很难再确保所有的机器处于相同的状态,同时越来越容易出错。然而,容器是比较完美地解决了这个问题,当然,使用虚拟机是可以的,显然使用容器更加方便。

GitOps的可观察性

“可观察性就像生产中的驱动测试一样。如果你不知道如何确定它是否正常工作,请勿接受 pull request。@mipsytipsy “ - Adriano Bastos

在GitOps中,使用Git库来存储应用系统的配置文集和应用程序,它确保开发人员将所有对于应用系统的配置和程序的新增、修改等都通过Git库进行版本控制,使Git成为配置和程序的唯一真实来源。而GitOps的可观察性则是确保线上环境的真实状态与Git库中的保持一致性。本章节将给大家介绍GitOps的可观察性。

可观察性是另一个真理来源

在GitOps中,我们使用Git作为系统所需状态的真实来源。例如,如果应用系统宕机,GitOps可以回滚到之前正确状态。而可观察性是系统实际运行状态的真实来源,系统开发人员或者运维人员可以监控系统的状态。这是一张显示流程的图片。

通过观察需寻找问题的答案

如果大家使用Kubernetes作为云原生环境和容器编排工具,相信大家会有这样的感触,虽然Kubernetes是一个非常棒的编排容器平台,但是随之而来的缺乏友好的可视化管理界面给开发人员或者运维人员带来诸多不便。例如:

  • 我的部署成功了吗?我的系统现在处于工作的状态,我现在可以回家吗?
  • 我的系统与以前有什么不同?我可以使用Git或我们的系统历史记录来检查吗?
  • 我的改变是否改善了整体用户体验?(与系统正确性相对)
  • 我在信息中心找不到我的新服务(例如RED指标)
  • 这个故障是否与我上次的服务更新事件有关,还是和其他操作有关系?

大家可能会想到通过监控服务器的CPU、内存、网络等,以及应用的日志,甚至微服务的调用链等来解决问题。是的,这个没有错,能够得到一些反馈信息,但是使用过类似监控的开发人员或者运维人员也会感觉,这些监控仪表盘给我们大量冗繁的信息,需要认真地甄别,而且有很多信息在这些仪表盘中是获得不到的。这意味着需要创建新的仪表盘,用于监控新的指标和内容。

GitOps的可观察性

可观察性可被视为Kubernetes 持续交付周期的主要驱动因素之一,因为它描述了在任何给定时间系统的实际运行状态。观察运行系统以便理解和控制它。新功能和修复程序被推送到git并触发部署管道,当准备好发布时,可以实时查看正在运行的集群。此时,开发人员可以根据此反馈返回到管道的开头,或者将映像部署并释放到生产集群。

在这里GitOps引入一个新的工具:Diffs,用来监控对比系统状态。即:

  • 验证当前线上系统的状态是否和Git库中描述的状态一致,例如,我上一次发布是否符合期望?
  • 提醒开发人员不一致状态,以及相应的明细信息。

在文章前面讲过,在Git库中存储的实际上是“声明性基础设施”,例如Kubernetes的YAML文件,用以构建应用系统所需的各种组件、域名、网络等配置信息。Diffs需要读取Git库中配置信息,同时,通过API等读取集群的相应信息,并进行比对。

例如,Kubernetes集群:所需的Kubernetes状态可能是“有4个redis服务器”。Diffs定期检查群集,并在数量从4变化时发出警报。一般而言,Diffs将YAML文件转换为运行状态查询。

GitOps是面向发布的操作模型,请参见下图。交付速度取决于团队在此周期中绕过各个阶段的速度。

应用交付合规性和安全性

由于以安全的方式跟踪和记录更改,因此合规性和审计变得微不足道。使用Diffs等比较工具还可以将Git库中定义的集群状态与实际运行的集群进行比较,从而确保更改与实际情况相符。

在Git中记录所有的操作日志

通过上面文章的叙述,开发人员或者运维人员通过Git操作系统配置和应用程序的新建和更新等。通过Git客户端git commit /git merge的所有操作都会Git库记录下来,审计员可以查看Git,看看谁做了任何更改,何时以及为何以及如何影响正在运行的系统部署。当然,可以根据自身的需求定制不同的交付合规性。相较于直接进入服务器操作或者通过Kubctl操作集群,Git记录了每一个操作步骤,这些可以为合规性和审计提供完整的操作日志。

角色和权限控制

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

GitOps带来的好处

更加快速地开发

借助GitOps的最佳实践,开发人员可以使用熟悉的Git工具,便捷地将应用程序和其对应的配置文件集持续部署到Kubernetes等云原生环境,提高业务的敏捷度,快速地相应用户的需求,有助于增加企业市场的竞争力。

更好地进行运维

借助GitOps,可以实现一个完整的端到端的交付流水线。不仅可以实现拉式的持续集成流水线和持续部署流水线,而且系统的运维操作可以通过Git来完成。 更强大的安全保证 几乎所有的Git库都提供角色和权限控制,与开发和运维无关的人员没有权限操作Git库。而不是直接把服务器或者集群的操作权限散发出去,这样特别容易引起安全泄露。

更容易合规的审计

由于以安全的方式跟踪和记录更改,因此合规性和审计变得微不足道。使用Diffs等比较工具还可以将集群状态的可信定义与实际运行的集群进行比较,从而确保跟踪和可审计的更改与实际情况相符。

关于猪齿鱼

Choerodon 猪齿鱼是一个全场景效能平台,基于 Kubernetes 的容器编排和管理能力,整合 DevOps 工具链、微服务和移动应用框架,来帮助企业实现敏捷化的应用交付和自动化的运营管理的平台,同时提供 IoT、支付、数据、智能洞察、企业应用市场等业务组件,致力帮助企业聚焦于业务,加速数字化转型。

大家也可以通过以下社区途径了解猪齿鱼的最新动态、产品特性,以及参与社区贡献: