1.背景与介绍
随着微服务架构的发展,企业级项目由无数的服务组成,这时候急需用到集中管理、治理的配置的组件,来统一管理各个服务的开关、配置参数、数据库地址、服务器等等,然而这还不够,还要对这个管理配置的组件有着修改后实时发布、多环境、灰度发布、权限控制、审核等等机制,由此配置中心出现了,而由携程开源的apollo(阿波罗)人气最高、高可用性、各种功能非常完善,当然最关键选择apollo的一点是,文档真的非常非常完善,==本篇文章主要介绍基于docker版本的apollo搭建,apollo的一些核心概念、架构设计以及中间遇到的一些问题解决方案。
官方文档
开源地址
2.apollo核心概念
3.apollo架构设计
这是apollo官方提供的架构图,由图可见,这是典型的微服务架构,如果做过微服务的同学看起来比较容易,这里面涉及的服务、中间件拆分细节如下:
configService和AdminService都是无状态的,因此可以横向无线扩展,于是携程就引入只支持java的服务发现中间件Euraka引入进来,当服务启动时候,自动注册服务,Portal与java客户端(client)通过Euraka的SLB地址来发现服务列表,后来呢,因为要支持其他语言,又引入MetaServer做为Euraka的反向代理中间件,而MetaServer也做成集群,暴漏SLB地址,这样把Euraka的SLB换成MetaServer的SLB地址,所有语言都可以轻易使用Apollo。
如图:
写到这的时候,突发一个思考,由于目前主流微服务架构,单服务大概率都是基于docker部署的且多pod形式存在,本身该服务这些pod会有一个负载IP,但是通过服务注册发现后,有两种注册方式:
4.配置发布的实时通知设计
客户在portal操作发布后,内部调用adminService接口进行对配置数据库的操作,然后发送ReleaseMessage给ConfigService,收到消息后,通知Client。
推送ReleaseMessage的实现原理如下,本来想通过消息队列的形式,但人家做为开源框架,不想使用多的外部依赖,所以通过数据库消息表形式来完成简单的消息队列,具体流程如下:
5.客户端实现原理

6.apollo的高可用性
直接贴出官方给出的表格
7.apollo部署
说真的,携程这个开源的配置中心,文档真的非常非常细,大赞!从单体部署到分布式部署以及各种形式部署,都非常详细,文档地址:部署文档,这里由于小霸王服务器问题,我们只部署一个环境的非分布式部署来搭建apollo,真正的生产环境上,公司的运维会扛起分布式部署大旗,我们后端辅助即可哈哈。
本文部署使用基于docker方式:
先安装mysql,每安装的去安装,这里不多说;
搭建所依赖的两个数据库ApolloPortalDB和ApolloConfigDB,我这选择从人家github上直接下载脚本,去执行,数据脚本传送,下载完后,在navcat上直接执行,会得到两个数据库
拉取configService镜像
docker pull apolloconfig/apollo-configservice:1.8.0
4. 运行configService容器
docker run -p 8080:8080
-e SPRING_DATASOURCE_URL="jdbc:mysql://你的mysql地址:3306/ApolloConfigDB?characterEncoding=utf8"
-e SPRING_DATASOURCE_USERNAME=数据库用户 -e SPRING_DATASOURCE_PASSWORD=数据库密码
-d -v /tmp/logs:/opt/logs --name apollo-configservice apolloconfig/apollo-configservice:1.8.0
5. 拉取adminService镜像
docker pull apolloconfig/apollo-adminservice:1.8.0
6. 运行adminService容器
docker run -p 8090:8090
-e SPRING_DATASOURCE_URL="jdbc:mysql://你的mysql地址:3306/ApolloConfigDB?characterEncoding=utf8"
-e SPRING_DATASOURCE_USERNAME=数据库用户 -e SPRING_DATASOURCE_PASSWORD=数据库密码
-d -v /tmp/logs:/opt/logs --name apollo-adminservice apolloconfig/apollo-adminservice:1.8.0
7. 拉取portal镜像
docker pull apolloconfig/apollo-portal:1.8.0
8. 运行portal容器
docker run -p 8070:8070
-e SPRING_DATASOURCE_URL="jdbc:mysql://你的mysql地址:3306/ApolloPortalDB?characterEncoding=utf8"
-e SPRING_DATASOURCE_USERNAME=数据库用户 -e SPRING_DATASOURCE_PASSWORD=数据库密码
-e APOLLO_PORTAL_ENVS=dev,pro (注意这里,你需要什么环境,就填写哪些,运行起来会自动更新数据库ApolloPortalDB中的apollo.portal.envs,这测试只写dev)
-e DEV_META=http://你的metaService:8080 (注意,configService与euraka正常启动在同一进程)
-d -v /tmp/logs:/opt/logs --name apollo-portal apolloconfig/apollo-portal:1.8.0
全部运行起来后,查看docker运行情况如下图:
8.apollo管理界面使用
1.运行portal地址,默认账号密码是apollo/admin,登录
2.什么是创建项目?独立管理你微服务中一个或一类的私有配置集合,比如我有个订单服务,我这里就建一个OrderApi项目,正常情况下,有1个货几个公共项目,其他都是业务类项目。
3.修改部门,在数据库ApolloPortalDB.表ServerConfig.organizations修改。下面具体怎么使用,也没什么可说的,实在不会就照着文档来官方使用说明
4.我新建了一个docker-api的项目,和一个share公共项目,并分别新增和发布了配置,注意下,命名空间,公有私有的属性问题;
9..net core使用apollo
1.新建一个.net core3.1项目,nuget包安装Com.Ctrip.Framework.Apollo.Configuration;
2.启动类构造函数
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
//输出debug日志在控制台,方便查找问题
Com.Ctrip.Framework.Apollo.Logging.LogManager.UseConsoleLogging(Com.Ctrip.Framework.Apollo.Logging.LogLevel.Debug);
var builder = new ConfigurationBuilder()
.AddApollo(configuration.GetSection("apollo"))
.AddNamespace("yf.Share")
.AddDefault();
Configuration = builder.Build();
}
3.appsetting.json
{
"apollo": {
"AppId": "docker-api1",
"MetaServer": "http://xxxxxxx:8080",
"ConfigServer": [ "http://xxxxxxxx:8080/" ]
}
}
4.Api
[HttpGet("get/configs")]
public async Task GetConfigs()
{
var res = "";
//获取公共命名空间下的配置
var publicConfig = configuration["env"];
//获取该私有项目下的配置
var privateConfig = configuration["myConfig1"];
res = $"公共:{publicConfig},私有:{privateConfig}";
return Ok(res);
}
5.运行
10.常见问题
按照官方文档搭建部署的话,基本会碰到如下问题,为避免新人踩坑浪费时间,现总结如下:
1.当容器全部启动成功后,新建完项目,点击进去,右上角弹窗报错“请联系管理员”,我大概记得这么个问题,查看容器日志发现,apollo的ApolloConfigDB数据库中的ServerConfig中的eureka.service.url配置的默认是本地URL,由于docker的隔离性,所以请求失败,我们去这里给改成docker间可通信地址即可。
2.都配置完后,管理界面也都正常发布,但是代码里死活取不到数据,这个问题查了好久,终于最后在github上提问中找到篇这个问题的帖子,查看问题,就是startup中给debug日志打开,可以看到在注册apollo的时候的控制台日志,原因就客户端在连接configService服务列表时,通过metaserver(eureka反向代理地址)时候,默认取的是内网容器IP,在我们客户端没法访问,所以解决方案,就是appsetting中增加ConfigServer配置,来指定即可解决。
3.搭建时候,重点查看