云原生应用的12要素是一套设计原则,旨在帮助开发者构建可扩展、易于维护和能够充分利用现代云计算平台优势的应用程序。这些原则最初由Heroku提出,并在业界得到了广泛的认可。以下是这12个要素的概述,以及我在开发过程中实践的一些经验。
基准代码(Codebase)
使用版本控制系统管理一份代码库,该代码库可以被多次部署到多个环境中。
实践
一个模块/一个微服务就是一个代码仓。
依赖关系(Dependencies)
显式声明所有依赖项,并且不要将它们硬编码到应用程序中;使用依赖管理工具来隔离依赖。
实践
比如Java的maven/gradle,可以清晰的看到一个模块依赖什么模块。后期上线升级能清晰的知道影响范围
配置(Config)
将应用的配置存储于环境变量中,与代码分离。这样可以在不改变代码的情况下调整配置。
实践
因为一个服务就是一个pod,一个pod就是一套操作系统,可以在k8s在生成pod的配置文件中动态的修改配置文件。方便配置。
后端服务(Backing Services)
把数据库、队列系统等后端服务视为附加资源,通过网络访问,并能轻松替换或升级。
实践
比如用华为云只能使用gauss,阿里云,aws有各自数据库。连接方式可能各有不同,有更加高效的链接方式,但归根到底还是通过网络访问,网络访问是一个统一的,确定了端口,基本上就可以通用
构建、发布、运行(Build, release, run)
严格区分构建阶段、发布阶段和运行阶段。构建阶段生成执行文件,发布阶段确定部署的具体实例,而运行阶段则是在执行环境中启动应用程序。
实践
在过去的应用中往往发布和运行是一体的。比如我部署好了客户就可以直接使用了。但把发布和运行解耦开,把一个IT行为转换为业务行为。就可以实现诸如灰度发布,蓝绿发布等影响范围更小,更有针对性,控制性更高的操作。
进程(Processes)
应用应该以一个或多个无状态进程的形式运行,每个请求都应该包含处理所需的所有信息。
实践
无状态的应用是解耦的,能够更方便的进行扩缩容。云原生适合最终一致性的应用,而不是强一致性的应用。
端口绑定(Port binding)
应用程序应该自己绑定到端口并监听连接,而不是依靠外部网络服务器来转发请求。
实践
通过端口作为划分,只和端口进行绑定,不依赖其他服务,让每个服务更加的干脆。如果后期需要升级,替换应用,更加的方便。
并发(Concurrency)
在Web应用中,通过水平扩展进程数量来实现并发性。
实践
在Java中,我们往往想使用多线程解决并发,属于是纵向的扩展。而通过其多个pod可以说是横向的并发,可以用更多机器的资源。但状态的维护就带来了问题,所以云原生应用要是无状态的。
易处理(Disposability)
应用程序应该能够快速启动和优雅地关闭,以便支持弹性的伸缩策略。
实践
能够快速启动,自检尽量少而且是必要的。优雅关闭指的是我这个应用先停止接受请求,等处理完目前正在运行的🍜再进行自杀。保证业务不会中断,尽量少的重试,减少不必要的开销。也就是优雅。
开发/生产等价(Dev/prod parity)
开发、预生产和生产环境应尽可能保持一致,减少因为环境差异导致的问题。
实践
都是基于一个镜像部署的,与业务无关的变量尽可能的少,降低后期维护成本,能够在开发过程中发现更多的风险。
日志(Logs)
将应用程序的日志视为事件流,通常输出到标准输出,然后由外部系统收集和聚合。
实践
比如通过普罗米修斯进行日志采集,统一的日志格式,告警处理。能够整体的来看所有应用的部署情况。
管理进程(Admin processes)
管理任务应该作为一次性进程运行,就像正常的应用程序进程一样。
遵循这些原则可以帮助开发者创建更加灵活、可靠且易于管理的云原生应用程序。
实践
进程只关注自己的业务逻辑,像诸如权限管理,熔断,限流,失败重试等等公共能力应当由另一个进程去执行。方便后期运维和组件升级。进一步说就是istio的边车模式