随着云计算技术的发展,云原生技术成为当今时代的主流。云原生(Cloud Native)是一种理念,本质上是一套“以利用云计算技术为用户降本增效”的最佳实践与方法论。
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。
这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。
在云原生场景下如何做好应用的定义与交付也同样影响着企业的成本投入,也影响着股东的每一份利润。
在进入互联网这个行业以来,很长一段时间我理解的应用交付就是程序的安装部署,把业务方给我的程序安装包运行起来就好了。但是,随着在这个行业中逐渐的摸索,我对交付有了新的理解,我认为交付就是将需求转化成某种介质提供给需求方,以达到提供服务能力并创造价值目的的过程。而应用交付的对象是应用更加具体,更侧重于软件的需求交付,但也不仅局限于程序的安装部署了。
应用的交付可以有多种形态。互联网企业或业务团队成立的初衷是实现一些想法或者目标,比如想要即时通讯 IM工具,想要使用电商平台,想要提供互联网检索功能等等。企业创始人或业务负责人给到业务团队的需求是明确的,就如需求目标就是想要一个即使通讯的工具来支撑整个集团的高效沟通,但是业务团队如何实现并交付这样的需求其实是不固定。当然,可以选择从新开发一个新的通讯IM工具来交付这个需求,更可能的情况确是提供一套解决方案采购其他厂商已有的产品,两种方式都是可以满足最初的需求交付,只是满足需求的方式或者说介质不同了罢了。交付需求的介质可能是打包的程序、代码函数、API接口、公有云产品、解决方案、设计图稿甚至是 Markdown 文档等等,只要能满足的需求方的需求即可,并不局限于固有的意识形态。
随着时代技术的演进,应用交付的载体也在不断的变化以满足不同的交付场景,通过对交付过去、现在和未来的方式进行分析,以便对应用交付有更加深入的理解。
传统的应用交付是应用交付的基础方式,比如常用的 RPM 软件包或者直接二进制的方式安装运行,比较适合场景相对固定的基础设施。如果有较多的软件包依赖,一般还会搭建一些 YUM 的软件源来快速安装依赖。这类服务的运行一般也可以通过 systemd 或者 supervisor 的方式来管理。
基于可执行文件交付的应用一般运行方式比较直接,直接在 shell 中运行程序。比如 /opt/myapp.sh
。如果在终端中运行影响使用,一般还会在命令最后添加 &
符号使其在后台运行,如 java -jar myapp.jar &
。
直接使用可执行文件交付没有固定的规范约束,每个研发或运维人员的习惯的不一样,文件放置的位置和启动的命令等都会有差异,就导致在运维管理上有较大的困难,因此规范这些文件成为了一个趋势。将可执行文件和配置按照一定的规范要求封装,就是大家常用的软件安装包。
软件包具有特定的格式,这些格式就是对软件安装的规范过程。由于识别和管理软件包的工具不同,出现了大量的不同类型的软件封装方式,如 CentOS 使用 RPM 包,Debian 使用 DEB 包,Java Web 使用 WAR 包,Windows 使用 exe 包等等。这些不同格式的软件由不同的工具来管理和运行,如 WAR 一般使用 tomcat 运行管理,RPM 和 DEB 包使用 systemd 管理服务等。
虽然软件包能够规范文件的管理,但是由于程序的运行处自身可执行文件和配置外,还会有其他例如系统库文件的依赖才能正常运行,这就是程序的运行环境。由于操作系统的种类不同,版本不同,安装的基础库软件不同都会导致无法满足程序正常运行的需要,管理这些运行环境成为新的痛点。Docker 的出现完美的解决了这个问题。
为了实现企业的降本增效的目的,云原生理念成为当前主流,应用交付方式也逐渐云原生化。
Docker 的镜像将程序以及依赖的软件或库文件一起打包成 Docker 镜像,在这个镜像中有着程序运行所有的依赖,这样无论这个镜像运行在任何支持 Docker 的操作系统的任何版本,都可以将程序运行起来。由于这种特性确实解决了很多应用交付的痛点问题,因此 Docker 一经出现就立马风靡全球。
Docker 镜像将一个应用的交付难度大大降低,但是在多个应用一起交付和管理时就不那么便捷了,而且程序运行还会有依赖和配置的需求,因此多容器服务的管理 docker-compose 被提出。
docker-compose 将多个应用使用 yaml 的方式管理,可以单个或多个服务的批量安装部署和服务起停。docker-compose 给多应用的交付提供了很好的参考思路。
由于 docker-compose 仍然是一个单机工具,虽然可以很好的管理单台机器上的服务,但是在多台机器上部署和管理服务却显得力不从心。这时,基于容器的编排调度服务出现了。
在早期,基于容器的服务编排调度系统有三大产品,分别是 Swarm、Mesos 和 Kuberentes。在激烈的市场竞争中,Kuberentes 由于其优秀的设计与强大的能力等原因脱颖而出。在 Kuberentes 中,用户只需要定义自己想要的服务运行副本数量和运行方式即可(deployment),在结合 Service 和 Ingress 等资源就可以完成应用的交付,完全不需要关注服务调度的节点。Kuberentes 是云原生的操作系统,目前已经成为容器编排事实上的标准。有些企业为了便于操作,使用了基于 Web 的容器云平台来管理,比如一些开源的容器云平台。
基于 Kuberentes 的应用交付已经很简单了,但是在 Kubernetes 中部署应用时还是会涉及较多类型资源管理问题。在 Kubernetes 集群中部署服务并不是简单的将 Image 镜像运行起来就可以了,实际上还会涉及一些其他相关的 Kubernetes 的资源,例如常见的资源有 Deployment、Service、Ingress、Secret、ConfigMap、PV/PVC、ServiceAccount、RBAC等等以及其他扩展服务的相关资源,如 Prometheus-operator 的 ServiceMonitor。这么多类型的文件该如何维护管理才能高效且不出错呢?
Helm Chart 能够将 Kuberentes 的各种资源进行打包管理,也可以添加自定义的安装或升级逻辑。Helm 是 Kubernetes 应用查找、分享和使用的最佳方式。
Helm 已经是 Kuberentes 应用的常规推荐交付方式了,只是在一些特有的场景下还可以有更加高效的交付方式,如 CI/CD。
CI/CD 是持续集成和持续交付的简称,通过流水线可以将应用的交付流程串联起来,触发流水线自动将源代码拉取、编译、测试、打包、构建、部署和运行测试等过程执行起来。这在开发和测试过程中能极大的提升应用交付效率,将更多的时间留给研发编写功能和测试验证异常。
任何一种交付方式都有其历史背景与应用场景,基于 CI/CD 的应用交付同样不是绝对完美的。因为自动 CD(交付)的过程在当今这个时期并不符合大多数企业的要求,无论是在交付质量、上线流程、安全合规等方面都可能无法满足企业的需求。
因此,应用的交付应该选择应该符合实际的时代背景与技术体系。就目前,推荐在测试开发阶段使用 CI/CD 高效交付应用,在生产环境使用 Helm 稳定交付应用,以及在某些特殊情况下依然可以使用早期的几种交付方式来满足业务交付的需求。
以上的应用交付形态都是在考虑将应用的以程序的方式在环境中运行起来提供服务,追溯问题的本源,交付是在交付什么?交付是在交付需求,核心并不是代码,代码只是当前技术体系下可选的最佳介质而已。
今天大多数公司在开发应用程序并将其部署在服务器上的时候,无论是选择公有云还是私有的数据中心,都需要提前了解究竟需要多少台服务器、多大容量的存储和数据库的功能等。并需要部署运行应用程序和依赖的软件到基础设施之上。假设我们不想在这些细节上花费精力,是否有一种简单的架构模型能够满足我们这种想法?
OAM 是一个专注于描述应用的标准规范。有了这个规范,应用描述就可以彻底与基础设施部署和管理应用的细节分开。这种关注点分离(Seperation of Conerns)的设计好处是非常明显的。 举个例子,在实际生产环境中,无论是 Ingress ,CNI,还是 Service Mesh,这些表面看起来一致的运维概念,在不同的 Kubernetes 集群中可谓千差万别。 通过将应用定义与集群的运维能力分离,我们就可以让应用开发者更专注于应用本身的价值点,而不是”应用部署在哪“这样的运维细节。
此外,关注点的分离让平台架构师可以轻松地把平台的运维能力封装成可被复用的组件,从而让应用开发者能够专注于将这些运维组件与代码进行集成,从而快速、轻松地构建可信赖的应用。 Open Application Model 的目标是让简单的应用管理变得更加轻松,让复杂的应用交付变得更加可控。
Serverless 架构是基于互联网的系统,其中应用开发不使用常规的服务进程。它们仅依赖于第三方服务(例如 AWS Lambda 服务),客户端逻辑和服务托管远程过程调用的组合。
最开始,“无服务器”架构试图帮助开发者摆脱运行后端应用程序所需的服务器设备的设置和管理工作。这项技术的目标并不是为了实现真正意义上的“无服务器”,而是指由第三方云计算供应商负责后端基础结构的维护,以服务的方式为开发者提供所需功能,例如数据库、消息,以及身份验证等。简单地说,这个架构的就是要让开发人员关注代码的运行而不需要管理任何的基础设施。程序代码被部署在诸如 AWS Lambda 这样的平台之上,通过事件驱动的方法去触发对函数的调用。
很明显,这是一种完全针对程序员的架构技术。其技术特点包括了事件驱动的调用方式,以及有一定限制的程序运行方式,例如 AWS Lambda 的函数的运行时间默认为3秒到5分钟。从这种架构技术出现的两年多时间来看,这个技术已经有了非常广泛的应用,例如移动应用的后端和物联网应用等。简而言之,无服务器架构的出现不是为了取代传统的应用。然而,从具有高度灵活性的使用模式及事件驱动的特点出发,开发人员/架构师应该重视这个新的计算范例,它可以帮助我们达到减少部署、提高扩展性并减少代码后面的基础设施的维护负担。
低代码开发是一种可视化应用开发方法。通过低代码开发,不同经验水平的开发人员能够通过图形用户界面,使用拖放式组件和模型驱动逻辑来创建 Web 和移动应用。低代码开发平台减轻了非技术开发人员的压力,帮其免去了代码编写工作,同时也为专业开发人员提供了支持,帮助他们提取应用开发过程中的繁琐底层架构与基础设施任务。
无代码是完全不需要编写代码,也称为零代码,基于视觉的拖放式无代码平台允许用户创建基本但实用的应用程序。
低代码和无代码开发平台都提供了无需编写代码即可构建软件应用程序的方法。它们不要求开发人员具备任何传统编程语言的知识,而是提供了一种可视化的应用程序开发方法。这使得更多的人可以使用应用程序开发,特别是在业务领域工作的精通技术的人。
低代码和无代码开发平台有望帮助专业和非专业开发人员以更高的效率创建应用程序,从而提高生产力。由于几乎总是以平台即服务 (PaaS) 形式提供,两者都消除了建立环境和维护基础设施的开销。
使用低代码平台,开发人员可以使用自己编码的增强功能扩展应用。无代码平台在开发环境中添加了约束,限制了用户在供应商提供的解决方案之外扩展其应用的能力。
可以确定的是以上的应用交付形态将会同时存在,并且会长期存在。但不同的交付形态的采纳比重会有侧重,目前主流的应用交付形态会是云原生的应用交付模式,即基于容器、Kubernetes的应交付。
传统应用交付将作为无奈的兜底选择。在企业没有新型的基础设施和人才资源时,还需要继续使用传统的应用交付模式,虽然不那么高效和先进,但是他足够的成熟和稳定。
云原生应用的交付是当前的主流。其优秀的设计理念与高效交付效率是各大技术公司追求的理想技术,这些公司努力储备云原生的技术人才,让其业务在新时代的数字化背景下大放异彩。
新型应用交付是未来发展方向,是当前的前沿的技术形态。更多的还是在早期阶段,只有一些大型互联网厂商在投入研究,在真正的普及和产生实际的效益的路上还是在摸着石头过河。
应用的定义决定了应用的交付方式,不同的交付方式也影响着如何定义应用。应用的定义可以理解为是根据特定的交付场景,对交付物(或交付介质)进行符合一定规范标准的组织方式。
这些规范标准可能涉及应用运行的平台、开发的语言、运行文件封装方式、配置及环境信息以及说明性的材料等。
在定义或者封装一个应用时,需要明确其运行时的平台。在硬件层面需要考虑 CPU 类型,是 X86 架构还是 ARM 架构,甚至需要考虑兼容更多其他的 CPU 架构,不同的 CPU 架构的指令集不同,驱动及系统库不同可能导致应用无法在不兼容的硬件平台上运行。
在明确好硬件平台后,还有考虑其运行的操作系统 OS,这也决定着不同的软件运行生态的依赖,例如在 Windows 上打包的程序很可能无法在 Linux 操作系统上运行。
在目前云原生场景下,可以将 Kubernetes 理解成分布式的操作系统平台,如果应用想在 Kuberentes 平台上运行,就需要按照 Kubernetes 的标准来封装应用。
应用的定义规范的核心是如何更好的打包、管理、运行可运行的文件,可运行文件由于编写语言的不同,主要分为两种。
一种是脚本化语言编写的应用,他们由解析器来解析执行,例如 Shell 脚本、Python 脚本、Nodejs 等;另一种是编译型语言,需要经过链接编译后才能正常运行,如 C/C++可执行文件、Golang 可执行文件、Java 的 jar 包等。
虽然可执行文件是应用的核心,但是一个完整的应用一般由多个不同功能的文件组成,如可执行文件、配置文件、依赖的库文件以及帮助文档等。如果不能合理的管理相关的文件,会给交付运维人员的管理带来很多麻烦。由于运行平台不同,运行文件的封装方式也多种多样,如在 CentOS 上打包成 RPM 包,在 Debian 上打包 DEB 包,在 Windows 上打包成 EXE 包等等。在云原生场景下,会封装成容器镜像,并进一步的封装成 Helm Chart。
仅仅只是封装的软件包依旧只是程序文件,需要实际运行起来提供服务才有意义,应用运行起来的实际配置也是应用定义的一部分。例如和实际运行相关的服务配置文件 nginx.conf,服务启动时 JVM 参数,或者 Helm Chart 安装时以来的 values.yaml 配置。
说明的材料能够让使用着或者部署运维的人员对该应用有一定了解,能够更好的使用和管理该应用的服务。一般的应用可执行文件都会提供 --help 的帮忙说明,能够提供简单基础的说明。对于程序更详细的说明一般提供 man 手册详细描述,对于云原生应用的 Helm Chart 通过 README.md 或 NOTES.txt 来描述。
定义好一个应用需要考虑很多维度的信息,特别是云原生的应用和传统应用有着较大的差别,这里将云原生应用于传统应用在多个维度上进行对比,便于更好的理解云原生应用
在云原生的背景下,应用的定义与交付可能由于 CI/CD 的流水线而变得界限模糊。但是不是所有的场景都适合使用 CI/CD 来实现,如下几种场景
在 Kubernetes 集群中部署服务并不是简单的将 Image 镜像运行起来就可以了,实际上还会涉及一些其他相关的 Kubernetes 的资源一起配合才能正常提供功能,例如常见的资源有 Deployment、Service、Ingress、Secret、ConfigMap、PV/PVC、ServiceAccount、RBAC 等等,还其他扩展服务的相关资源,如 Prometheus-operator 的 ServiceMonitor,或用户自定义的 CRD 等等。这么多类型的文件该如何维护管理才能高效且不出错呢?
应用在测试环境功能测试验证后,在生产环境部署时相关的资源文件全部都重新一一创建也是可以的,但是很容易由于细节疏漏导致上线时出现文件缺失,配置错误等异常,给上线带来一定的困难和风险。这种情况推荐使用 Helm Chart 来定义应用,将该应用相关的 Kuberentes 资源统一进行打包管理,测试和生产的部署也仅有配置上的少量差异,降低管理多 Kuberentes 资源的复杂性问题。
有些公司测试环境与生产环境是网络隔离的状态,甚至是物理上的隔离需要更换设备才能访问不同环境,生产上线仅仅是想 CD 也是不行的。即便是想在生产环境单独搭建完整的流水线也不抬符合实际,因为代码是企业的核心资产,大部分企业的 Git 代码服务器是不允许放通到生产环境,防止可能被攻击的风险。
因此大部分企业更多的是在测试环境编译打包和测试应用,将应用封装成 Helm Chart 包,在测试环境经过严格的测试验证后,在生产环境部署 Helm Chart 即可。在测试环境对构建好的 Helm Chart 部署相关资源和配置都可以进行覆盖测试,这样也可以保障 Kubernetes 相关资源的准确与完整性,为生产环境上线提供高质量 SLA。
在企业内部一个部门开发了好的一款优秀的应用,其他部门也希望能够使用这个应用,特别是大型企业有多个子公司时尤为明显。这类应用例如:日报周报系统、设备日志系统、发票管理系统、ERP系统等等。这时如何将这些应用分享给其他部门会成为一个挑战,如果交付过程太过复杂就会导致推广受限,进而在集团层面产生资源的浪费。
使用 Helm Chart 来定义和封装应用,给其他相关人员提供程序时提供一个 Helm Chart 包即可,helm install 安装过程也方便快捷。
如前文提到的 ERP 系统、网易数帆轻舟平台等,这些 toB 私有化产品在交付时会有很多的无法预测的基础设施问题,如何高效高质量的将产品服务交付到客户环境成为这类企业核心关注的重点之一。
使用 Helm Chart 来定义和封装应用,将多个应用进行关联来构建一套功能完整的系统,对私有化的交付会有很大的帮助。
轻舟平台就是网易数帆在私有化的场景下,云原生技术栈的实践载体,涉及微服务平台、容器云平台、PaaS 中间件平台以及低代码平台,这么多类型的平台服务想要高效的私有化交付是如何做到的呢?
网易数帆在私有化交付过程是通过 CI/CD 和 Helm Chart 两种方式结合。由于轻舟平台涉及的产品多,模块及镜像服务更多,在内部开发迭代时这么多的服务组件使用人工的方式安装部署是明显不合适的;轻舟采用的方式就是基于轻舟 CI/CD 平台来给各个组件配置流水线,通过持续集成部署的方式来进行应用的快速迭代开发。但前面也说了,在私有化场景下不可能通过 CI/CD 来将这套平台直接部署到客户的机房中,因此在版本发布时会将应用都打包成 Helm Chart,使用 Helm Chart 在客户机房离线部署。
通过多年的经验对交付有了更深刻的认识理解,交付的目的是交付需求,而需求的交付方式是多种多样的。当需求需要使用应用来交付时,从应用交付方式的演进来分析过去、现在和未来的交付方式。由于交付方式的不同,对应用的定义也有所不同,核心主要是应用运行的平台、开发的语言、运行文件封装方式、配置及环境信息以及说明性的材料。最后,分享了网易数帆轻舟平台的云原生交付实践方式,给感兴趣的云原生爱好提供参考案例。
结合以上的内容,总结了几点建议:
总之,企业应该结合业务场景与技术能力来选择合适的应用定义与交付方式。