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.inspur.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.inspur.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()); } } }