写点什么

一个合格的 CloudNative 应用:程序当开源软件编写,应用配置外置

发布于: 2021 年 03 月 19 日

​​​​​​​​摘要:对于一个合格的 CloudNative 应用,应该把自己的程序当做开源软件来编写的,不该将数据库连接信息和密码放在代码里,一定要将配置外置。


本文分享自华为云社区《一个合格的CloudNative应用:程序当开源软件编写,应用配置外置》,原文作者:敏捷的小智。


作者:关耳山石

 

对于一个合格的 CloudNative 应用,应该把自己的程序当做开源软件来编写的,不该将数据库连接信息和密码放在代码里,一定要将配置外置。


因此我试着在华为云上落地这套标准,期间尝试了从 ServiceStage、CCE、CSE 这三个入口进行配置注入,最终实现能够在应用启动时,主动拉取配置,覆盖本地配置文件里的调试配置,并能够在线配置并生效。


打法是:CCE 配置启动参数,制定 SpringProfiles;配合 CSE 做应用配置,将资源外置后的配置记录于此,并可以动态更新,最终实现了配置外置的诉求。


另外,通过这次增加的多版本管理,尝试梳理了一下 ServiceStage 的组件、CCE 的 workload、CSE 的应用和微服务之间,错综复杂的概念之间的关系,个人浅见,欢迎指正:



1. 初始化配置


在系统初始化的时候,不可能一点配置都没有,所以保留一些基础配置在配置文件里是有必要的。配置外置并不意味着 100%的配置都要外置,而是把外部依赖资源的配置,特别是容易变化配置外置。


1.1 启用 Bootstrap 和 Spring profile


在代码层面,首先要进行基础配置。先看代码结构,这里除了最基本的 application.yaml,增加了 bootstrap.yaml 和*-dev.yml 等带后缀的文件。



介绍一下原理:


首先介绍 Bootstrap Application Context:

它是 Spring Cloud Context 的父 Context,所以从外部配置源里加载配置一般从这里来,且优先级高于其他一切配置文件。于是,我们也利用这个能力,借助 CSE 的微服务配置中心能力,进行 Spring 的外部参数写入。



然后介绍 Spring profiles:

为了把通用配置和环境相关的配置区分开,比如 DEV 环境没有 AK/SK 认证,而线上环境都有认证,这种配置项上的区别,引入了 Spring profiles 的概念,当 Springboot 启动的时候,会根据 profiles.active 参数判断应该启用那个环境配置



PS:参考 SpringCloud 官方解释


另外,就是哪些配置应该放在配置文件里,理论上除了最基础的配置,在启动时使用的,其余的配置都可以放在 CSE 的微服务配置中心里,而不必在本地配置文件里存在,另外就是本地配置里存在的,也可以通过二次设置在微服务的配置中心里,进行覆盖,比如数据库连接池的大小,而不需要修改代码,至于改完以后,要不要重启,那就得看生效的逻辑了。


1.2 引入 CSE 配置中心


CSE 配置中心引入,需要先引入依赖包,然后在 bootstrap.yaml 中配置 CSE 配置中心的地址、认证信息等。

这里可以参考官方文档,主要关注 bootstrap.yaml 的配置参数:使用分布式配置中心

补充:获取 spring-cloud-starter-huawei-config 的版本

参考地址:huaweicloud/spring-cloud-huawei



​可以参考现有的 SpringCloud 基线版本,选择 SpringCloud-Huawei 的版本


补充:关于配置中心的优先级


微服务引擎提供了分层次的配置机制。按照优先级从高到低,分为:


  • 配置中心(动态配置)

  • Java System Property(-D 参数)

  • 环境变量

  • 配置文件

参考官方文档:配置微服务

2. 本地 CSE 配置中心能力验证


前提条件,本地得安装一个 Local-CSE 并启动,这部分参考云上DevOps:2.1-本地环境准备


2.1 配置 application.yaml 和 bootstrap.yml


原始文件可以参考 Github 的 Demo,配置文件入口,我这里进行了修改,因为 bootstrap.yaml 优先级高于 application.yaml,参数只要在 bootstrap.yaml 中出现过,就不会使用 application.yaml 中的配置了。

上代码,application.yaml,可以看到配置很少,因为大部分 bootstrap.yml 中已经包含,就都去掉了



​这是 bootstrap.yml,注意这里的 spring.application.name、

spring.cloud.servicecomb.discovery.appName 和 spring.cloud.servicecomb.discovery.version 会组成一个微服务私有的参数作用域,这里的优先级高于全局作用域 application。特别注意,云上的 CSE 环境,除了上面提到的,还需要增加 server.env 参数。另外,server.env 有四个参数可以选 development、testing、acceptance、production



关于如上参数的定义,参考官方文档:使用分布式注册中心官方文档:使用分布式配置中心


2.2 准备验证代码


直接上代码



2.3 静态配置能力


为了验证 CSE 配置中心的参数,是否能覆盖 application.yaml 中的参数配置,我选了一个很特别的参数:spring.datasource.password,如果能够覆盖成功,那么启动后,创建数据库连接池一定会报错。


首先,打开本地 CSE 配置中心,地址为:http://localhost:30106/#/cse/services/config,创建一个配置项,作用域选 VodMgrService@CabgOne#1.0.0,关于 application 的作用域后面再解释。



重启本地微服务,启动后创建数据库连接池就报错了,符合预期。



结论:CSE 配置中心的参数,能够覆盖 application.yaml 中的参数配置


2.4 动态配置能力


为了验证 CSE 配置中心的参数动态生效,需要使用注解 @RefreshScope,同时也引入 ConfigRefreshEvent 来监听事件变化,这样就会得到一个效果,对于动态生效的参数,可能需要一些重建或刷新,比如连接池、缓存、Client 等。

首先,增加一个配置项 config.value



然后很快可以看到后台日志打印出来,包括自己的监听器,也响应了日志



​查看一下数据,已经响应为 TryMe



​具体的配置,在后台是轮询的,响应周期配置参数为 cloud.servicecomb.config.watch.delay,目前是 10 秒一次



​修改一下配置,为 TryMeAgain



​再看后台日志,有新的触发器发生



再次请求 API,数据已经更新



再深入去看,这里的 getChange()返回是一个 Set<String>,因此可以针对特定的参数做文章。

结论:本地 CSE 配置中心的参数能够动态刷新,并开放了 ConfigRefreshEvent,以扩展配置更新后的业务动作。


2.5 配置的作用域限制


目前 CSE 的配置中心提供两级作用域限制,一个是全域,一个是私域,即微服务内部(不同版本有区分)。


增加一个作用域为 application 的全域参数,一个作用域为 VodMgrService@CabgOne#1.0.0 的私域同名参数



​验证一下,生效的作用域是 VodMgrService@CabgOne#1.0.0



​删除私域参数后,生效的作用域是 application



​结论:本地 CSE 配置中心的全域配置的优先级,低于微服务内部配置,即私域配置可以覆盖全域配置。

3. 云上配合外置落地


3.1 代码提交并自动打包推送 SWR


代码提交,推送到 CodeHub 上,流水线在 CloudPipeline 自动驱动起来,开始执行,打包、制作镜像、推送 SWR,并且展开了代码质量检查。这些得益于前面的 WIKI:Phase2 - 云上DevOps



3.2 CCE 启动参数配置


由于 ServiceStage 的自动部署能力还不满足,所以手工将 DockerImage 升级到环境上,这里直接使用 CCE 进行操作,原因在题记里介绍了,ServiceStage 的参数配置不太好用

 

3.2.1 利用 CCE 的容器启动命令写入参数


选择升级版本,点高级配置,CCE 的核心配置入口都在这里了



在启动时,注入最核心的一个参数-Dspring.profiles.active=uat



​此处的命令是 Docker 启动是的 ENTRYPOINT,下面那个是 CMD,会覆盖 Dockerfile 里的命令



点击右下角的提交,会看到实例列表中已经有一个新的 pod 在启动



回到 AOM 服务,查看日志,会发现 The following profiles are active: uat,符合预期



3.3 CCE 环境变量配置


3.3.1 利用 CCE 的环境变量写入参数


首先回退上面那一步的配置,进入高级设置->环境变量

增加环境变量 JAVA_TOOL_OPTIONS,值设置为-Dspring.profiles.active=uat



​提交以后查看日志,符合预期



​至于为啥 JAVA_TOOL_OPTIONS 能用,因为 JVM 原生就包含这个参数,可以用来在启动时写入配置,可以参考 Oracle 的官方文档



3.4 CCE 配置中心


3.4.1 利用 CCE 的配置中心+环境变量写入参数


CCE 的配置中心包含了两个大类,配置项 ConfigMap 和秘钥 Secret,前面介绍的 CCE 环境变量,支持从配置中心导入参数,比如我可以在 ConfigMap 里写入这个参数,然后在 CCE 的环境变量中引入。

首先创建一个配置项,这里的配置项是按照集群、命名空间区分的



然后创建一套配置项,输入一套 KV



回到 CCE 升级的步骤,修改环境变量,增加一项配置项写入的变量,可以选到刚才输入的 KEY,就不用输入 VALUE 了



​然后再看看秘钥,玩儿法类似,但是有一点很“有趣”:这里的秘钥是要主动用 BASE64 转码过才能保存,不过在使用的时候,会解密的,因此不必关心转码回来的问题。



3.4.2 利用 CCE 的配置中心 + 数据存储写入参数


无论是配置项 ConfigMap 还是秘钥 Secret,都可以支持利用 CCE 的数据存储挂载能力写入参数到容器里,简单理解,就是会自动帮你把配置下载到一个容器的存储位置上,文件名是 KEY,内容是 VALUE,可以在代码里读取这个配置。

配置方式很简单,选择配置项,然后写一个挂载目录即可



3.5 云上 CSE 配置中心


这里是另一个核心,线下验证过,云上的 CSE 类似,但是配置模型更复杂,增加了 server.env 维度,并且全域和私域参数配置位置不一样。

首先,从 ServiceStage->微服务 CSE->配置管理,进入全域配置页面,选择环境为 yaml 里配置的 server.env 参数返回结果为,生效



PS:如果这里不选环境,则参数无法读取,即环境为空也是一类环境,不同环境之间隔离

然后,从 ServiceStage->微服务 CSE->微服务目录,进入私域页面



进而选择动态配置,在配置作用域时,选择不带 version 的,环境是固定值,



返回结果为,生效



​​同样的页面下,在配置作用域时,选择带 version 的,



返回结果为,生效

总结:云上 CSE 配置中心参数加载优先级


  • P1:微服务私域,带 Version

  • P2:微服务私域,无 Version

P3:全域,带环境

其余参数都不生效,包括全域无环境、全域不同环境、微服务私域不同 Version

总结


综上,基于华为云 ServiceStage、CCE、CSE 的配置外置能力,可以支撑微服务在不同环境中灵活部署,而无需修改代码。目前的总结打法是:


1.    利用 CCE 的容器启动参数,或环境变量,写入 profiles.active 参数

2.    利用 CSE 的配置中心,写入业务参数,如 MySQL 连接串、连接池配置、GES 引擎地址、VOD 服务 Endpoint 地址等


点击关注,第一时间了解华为云新鲜技术~


发布于: 2021 年 03 月 19 日阅读数: 15
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
一个合格的CloudNative应用:程序当开源软件编写,应用配置外置