SpringCloud入门实战(3)-Apollo使用
Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。本文主要介绍Apollo的基本使用,文中使用到的软件版本:Apollo 1.7.0、Spring Boot 2.2.5.RELEASE、Spring Cloud Hoxton.SR3、Java 1.8.0_191、 Mysql 5.7.26。
1、apollo架构
- Config Service提供配置的读取、推送等功能,服务对象是Apollo客户端
- Admin Service提供配置的修改、发布等功能,服务对象是Apollo Portal(管理界面)
- Config Service和Admin Service都是多实例、无状态部署,所以需要将自己注册到Eureka中并保持心跳
- 在Eureka之上我们架了一层Meta Server用于封装Eureka的服务发现接口
- Client通过域名访问Meta Server获取Config Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Client侧会做load balance、错误重试
- Portal通过域名访问Meta Server获取Admin Service服务列表(IP+Port),而后直接通过IP+Port访问服务,同时在Portal侧会做load balance、错误重试
- 为了简化部署,我们实际上会把Config Service、Eureka和Meta Server三个逻辑角色部署在同一个JVM进程中
2、服务端部署
2.1、环境
Apollo可以管理不同环境的配置:
DEV 开发环境
FAT 测试环境,相当于alpha环境(功能测试)
UAT 集成环境,相当于beta环境(回归测试)
PRO 生产环境
Apollo里不同组件部署方式不一样:
a、Portal只需部署一套,通过它来管理DEV、FAT、UAT、PRO等环境的配置
b、Meta Server、Config Service和Admin Service在每个环境都单独部署,使用独立的数据库
c、Meta Server和Config Service部署在一个JVM进程中
2.2、部署步骤
2.2.1、规划
假设所有服务都部署在10.49.196.10上,并都使用默认的端口:
服务 | 端口 | 部署目录 |
apollo-configservice | 8080 | /home/hadoop/app/apollo/apollo-configservice |
apollo-adminservice | 8090 | /home/hadoop/app/apollo/apollo-adminservice |
apollo-portal | 8070 | /home/hadoop/app/apollo/apollo-portal |
2.2.1、创建ApolloPortalDB
通过Mysql客户端导入数据库的初始化脚本:
https://github.com/ctripcorp/apollo/blob/master/scripts/sql/apolloportaldb.sql
2.2.2、创建ApolloConfigDB
通过Mysql客户端导入数据库的初始化脚本:
https://github.com/ctripcorp/apollo/blob/master/scripts/sql/apolloconfigdb.sql
2.2.3、下载并解压安装包
https://github.com/ctripcorp/apollo/releases 下载adminservice、configservice、portal三个包,如下载1.7.0版本的安装包:apollo-adminservice-1.7.0-github.zip、apollo-configservice-1.7.0-github.zip、apollo-portal-1.7.0-github.zip。把三个安装包放到三个单独的目录(apollo-adminservice、apollo-configservice、apollo-portal)里,然后解压:
cd apollo-adminservice unzip apollo-adminservice-1.7.0-github.zip cd apollo-configservice unzip apollo-configservice-1.7.0-github.zip cd apollo-portal unzip apollo-portal-1.7.0-github.zip
2.2.4、配置修改
2.2.4.1、ApolloPortalDB配置
配置项统一存储在ApolloPortalDB.ServerConfig表中,也可以通过管理员工具 - 系统参数页面进行配置,无特殊说明则修改完一分钟实时生效。
apollo.portal.envs | 可支持的环境列表 | 默认值是dev,如果portal需要管理多个环境的话,以逗号分隔即可(大小写不敏感),如:DEV,FAT,UAT,PRO |
apollo.portal.meta.servers | 各环境Meta Service列表 | Apollo Portal需要在不同的环境访问不同的meta service(apollo-configservice)地址,该配置优先级高于其它方式设置的Meta Service地址 |
2.2.4.2、ApolloConfigDB配置
配置项统一存储在ApolloConfigDB.ServerConfig表中,需要注意每个环境的ApolloConfigDB.ServerConfig都需要单独配置,修改完一分钟实时生效。
eureka.service.url | Eureka服务Url | apollo-configservice本身就是一个eureka服务,所以只需要填入apollo-configservice的地址即可,如有多个,用逗号分隔 |
2.2.4.3、配置数据库连接信息
修改 apollo-configservice、apollo-adminservice 两个应用包中 config/application-github.properties 配置文件,配置数据库连接:
spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?useSSL=false&characterEncoding=utf8 spring.datasource.username = someuser spring.datasource.password = somepwd
修改 apollo-portal 应用包中 config/application-github.properties 配置文件,配置数据库连接:
pring.datasource.url = jdbc:mysql://localhost:3306/ApolloPortalDB?useSSL=false&characterEncoding=utf8 spring.datasource.username = someuser spring.datasource.password = somepwd
2.2.4.4、修改脚本里的日志文件路径
修改apollo-configservice、apollo-adminservice、apollo-portal三个应用包中scripts/startup.sh启动脚本,修改日志文件路径:
LOG_DIR=/opt/logs/100003171
2.2.4.5、修改样例
ApolloPortalDB.ServerConfig,配置了dev和pro环境,并指向了同一个meta地址
ApolloConfigDB.ServerConfig:
apollo-configservice/config/application-github.properties、apollo-adminservice/config/application-github.properties:
spring.datasource.url = jdbc:mysql://10.49.196.10:3306/ApolloConfigDB?characterEncoding=utf8 spring.datasource.username = admin spring.datasource.password = Root_123!
apollo-portal/config/application-github.properties:
spring.datasource.url = jdbc:mysql://10.49.196.10:3306/ApolloPortalDB?characterEncoding=utf8
spring.datasource.username = admin
spring.datasource.password = Root_123!
scripts/startup.sh
#apollo-configservice/scripts/startup.sh LOG_DIR=/home/hadoop/app/appolo/apollo-configservice/scripts/logs #apollo-adminservice/scripts/startup.sh LOG_DIR=/home/hadoop/app/appolo/apollo-adminservice/scripts/logs #apollo-portal/scripts/startup.sh LOG_DIR=/home/hadoop/app/appolo/apollo-portal/scripts/logs
2.2.5、启动各应用
cd apollo-configservice/scripts ./startup.sh cd apollo-adminservice/scripts ./startup.sh cd apollo-portal/scripts ./startup.sh
2.2.6、portal控制台
http://10.49.196.10:8070/ (apollo/admin)
在控制台先创建项目,在项目里先选择环境,默认会有一个application的namespace,可以创建新的namespace,创建的namespace可以设置为public或private,public的namespace可以被其他的项目关联,private的只能本项目访问,客户端访问的时候需指定namespace。
3、客户端使用
3.1、引入依赖
<dependency> <groupId>com.ctrip.framework.apollo</groupId> <artifactId>apollo-client</artifactId> <version>1.7.0</version> </dependency>
3.2、修改application.yml
app:
id: general
apollo:
meta: http://10.49.196.10:8080
bootstrap:
enabled: true
namespaces: application,db,sms
3.3、在控制台增加配置信息
创建一个general的项目,里面有一个默认的namespace(application),一个关联其他项目(public)的公共namespce(db),一个新增的namespace(sms):
3.4、编写controller
package com.abc.scdemo.general.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; import java.util.Properties; @RestController public class HelloController { private static Logger logger = LoggerFactory.getLogger(HelloController.class); @Value( "${spring.application.name}" ) private String applicationName; @Value( "${server.port}" ) private String applicationPort; @Value("${spring.datasource.url}") private String dbUrl; @Value("${spring.datasource.driverClassName}") private String dbDriverClassName; @Value("${sms.host}") private String smsHost; @Value("${sms.port}") private String smsPort; @GetMapping("getInfo") public Map<String, Properties> getInfo() { logger.debug("getInfo start...."); Properties application = new Properties(); application.setProperty("name", applicationName); application.setProperty("port", applicationPort); Properties db = new Properties(); db.setProperty("url", dbUrl); db.setProperty("driverClassName", dbDriverClassName); Properties sms = new Properties(); sms.setProperty("host", smsHost); sms.setProperty("port", smsPort); Map<String, Properties> info = new HashMap<>(); info.put("application", application); info.put("db", db); info.put("sms", sms); logger.debug("getInfo end."); return info; } }
3.5、验证
启动应用后并访问controller可以看到获取到相关信息:
3.6、监控配置项变化
package com.abc.scdemo.general.config; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfig; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Configuration; @Configuration public class ApolloConf { private static Logger logger = LoggerFactory.getLogger(ApolloConf.class); //inject config for namespace application @ApolloConfig("application") private Config anotherConfig; /**config change listener for namespace application*/ @ApolloConfigChangeListener public void configChangeListter(ConfigChangeEvent changeEvent) { logger.info("配置改变。。。"); String item = "someItem"; if (changeEvent.isChanged(item)) { ConfigChange configChange = changeEvent.getChange(item); logger.info(item + "配置项改变,oldValue={},newValue={}", configChange.getOldValue(), configChange.getNewValue()); } } }