docker安装Apollo,并用java连接测试

2023-10-29

What is Apollo

背景:

随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关、参数的配置、服务器的地址……

对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境、分集群管理配置,完善的权限、审核机制……

在这样的大环境下,传统的通过配置文件、数据库等方式已经越来越无法满足开发人员对配置管理的需求。

Apollo配置中心应运而生!

简介:

Apollo(阿波罗)是携程框架部门研发的开源配置管理中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。

Apollo支持4个维度管理Key-Value格式的配置:

  1. application (应用)

  2. environment (环境)

  3. cluster (集群)

  4. namespace (命名空间)

同时,Apollo基于开源模式开发,开源地址:https://github.com/ctripcorp/apollo

配置基本概念

既然Apollo定位于配置中心,那么在这里有必要先简单介绍一下什么是配置。

按照我们的理解,配置有以下几个属性:

  • 配置是独立于程序的只读变量

    • 配置首先是独立于程序的,同一份程序在不同的配置下会有不同的行为。

    • 其次,配置对于程序是只读的,程序通过读取配置来改变自己的行为,但是程序不应该去改变配置。

    • 常见的配置有:DB Connection Str、Thread Pool Size、Buffer Size、Request Timeout、Feature Switch、Server Urls等。

  • 配置伴随应用的整个生命周期

    • 配置贯穿于应用的整个生命周期,应用在启动时通过读取配置来初始化,在运行时根据配置调整行为。

  • 配置可以有多种加载方式

    • 配置也有很多种加载方式,常见的有程序内部hard code,配置文件,环境变量,启动参数,基于数据库等

  • 配置需要治理

    • 权限控制

      • 由于配置能改变程序的行为,不正确的配置甚至能引起灾难,所以对配置的修改必须有比较完善的权限控制

    • 不同环境、集群配置管理

      • 同一份程序在不同的环境(开发,测试,生产)、不同的集群(如不同的数据中心)经常需要有不同的配置,所以需要有完善的环境、集群配置管理

    • 框架类组件配置管理

      • 还有一类比较特殊的配置 - 框架类组件配置,比如CAT客户端的配置。

      • 虽然这类框架类组件是由其他团队开发、维护,但是运行时是在业务实际应用内的,所以本质上可以认为框架类组件也是应用的一部分。

      • 这类组件对应的配置也需要有比较完善的管理方式。

Why Apollo

正是基于配置的特殊性,所以Apollo从设计之初就立志于成为一个有治理能力的配置发布平台,目前提供了以下的特性:

  • 统一管理不同环境、不同集群的配置

    • Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。

    • 同一份代码部署在不同的集群,可以有不同的配置,比如zookeeper的地址等

    • 通过命名空间(namespace)可以很方便地支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖

  • 配置修改实时生效(热发布)

    • 用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序

  • 版本发布管理

    • 所有的配置发布都有版本概念,从而可以方便地支持配置的回滚

  • 灰度发布

    • 支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例

  • 权限管理、发布审核、操作审计

    • 应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。

    • 所有的操作都有审计日志,可以方便地追踪问题

  • 客户端配置信息监控

    • 可以在界面上方便地看到配置在被哪些实例使用

  • 提供Java和.Net原生客户端

    • 提供了Java和.Net的原生客户端,方便应用集成

    • 支持Spring Placeholder, Annotation和Spring Boot的ConfigurationProperties,方便应用使用(需要Spring 3.1.1+)

    • 同时提供了Http接口,非Java和.Net应用也可以方便地使用

  • 提供开放平台API

    • Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。不过Apollo出于通用性考虑,不会对配置的修改做过多限制,只要符合基本的格式就能保存,不会针对不同的配置值进行针对性的校验,如数据库用户名、密码,Redis服务地址等

    • 对于这类应用配置,Apollo支持应用方通过开放平台API在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制

  • 部署简单

    • 配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少

    • 目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来

    • Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数

Apollo at a glance

如下即是Apollo的基础模型:

  1. 用户在配置中心对配置进行修改并发布

  2. 配置中心通知Apollo客户端有配置更新

  3. Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用

界面概览 

 

上图是Apollo配置中心中一个项目的配置首页

  • 在页面左上方的环境列表模块展示了所有的环境和集群,用户可以随时切换。

  • 页面中央展示了两个namespace(application和FX.apollo)的配置信息,默认按照表格模式展示、编辑。用户也可以切换到文本模式,以文件形式查看、编辑。

  • 页面上可以方便地进行发布、回滚、灰度、授权、查看更改历史和发布历史等操作

添加/修改配置项

输入配置信息:

 

发布配置

通过配置中心发布配置:

 填写发布信息:

 

Apollo in depth 

Core Concepts 核心概念

在介绍高级特性前,我们有必要先来了解一下Apollo中的几个核心概念:

  1. application (应用)

    • 这个很好理解,就是实际使用配置的应用,Apollo客户端在运行时需要知道当前应用是谁,从而可以去获取对应的配置

    • 每个应用都需要有唯一的身份标识 -- appId,我们认为应用身份是跟着代码走的,所以需要在代码中配置,具体信息请参见Java客户端使用指南

  2. environment (环境)

    • 配置对应的环境,Apollo客户端在运行时需要知道当前应用处于哪个环境,从而可以去获取应用的配置

    • 我们认为环境和代码无关,同一份代码部署在不同的环境就应该能够获取到不同环境的配置

    • 所以环境默认是通过读取机器上的配置(server.properties中的env属性)指定的,不过为了开发方便,我们也支持运行时通过System Property等指定,具体信息请参见Java客户端使用指南

  3. cluster (集群)

    • 一个应用下不同实例的分组,比如典型的可以按照数据中心分,把上海机房的应用实例分为一个集群,把北京机房的应用实例分为另一个集群。

    • 对不同的cluster,同一个配置可以有不一样的值,如zookeeper地址。

    • 集群默认是通过读取机器上的配置(server.properties中的idc属性)指定的,不过也支持运行时通过System Property指定,具体信息请参见Java客户端使用指南

  4. namespace (命名空间)

    • 一个应用下不同配置的分组,可以简单地把namespace类比为文件,不同类型的配置存放在不同的文件中,如数据库配置文件,RPC配置文件,应用自身的配置文件等

    • 应用可以直接读取到公共组件的配置namespace,如DAL,RPC等

    • 应用也可以通过继承公共组件的配置namespace来对公共组件的配置做调整,如DAL的初始数据库连接数 

自定义Cluster

比如我们有应用在A数据中心和B数据中心都有部署,那么如果希望两个数据中心的配置不一样的话,我们可以通过新建cluster来解决。

新建Cluster

新建Cluster只有项目的管理员才有权限,管理员可以在页面左侧看到“添加集群”按钮。

 

点击后就进入到集群添加页面,一般情况下可以按照数据中心来划分集群,如SHAJQ、SHAOY等。

不过也支持自定义集群,比如可以为A机房的某一台机器和B机房的某一台机创建一个集群,使用一套配置。

 在Cluster中添加配置并发布

集群添加成功后,就可以为该集群添加配置了,首先需要按照下图所示切换到SHAJQ集群,之后配置添加流程和添加/修改配置项一样,这里就不再赘述了。

 指定应用实例所属的Cluster

Apollo会默认使用应用实例所在的数据中心作为cluster,所以如果两者一致的话,不需要额外配置。

如果cluster和数据中心不一致的话,那么就需要通过System Property方式来指定运行时cluster:

  • -Dapollo.cluster=SomeCluster

  • 这里注意apollo.cluster为全小写

自定义Namespace

如果应用有公共组件(如hermes-producer,cat-client等)供其它应用使用,就需要通过自定义namespace来实现公共组件的配置。

 新建Namespace

以hermes-producer为例,需要先新建一个namespace,新建namespace只有项目的管理员才有权限,管理员可以在页面左侧看到“添加Namespace”按钮。

 

点击后就进入namespace添加页面,Apollo会把应用所属的部门作为namespace的前缀,如FX。

 

4.3.2 关联到环境和集群

Namespace创建完,需要选择在哪些环境和集群下使用

 

在Namespace中添加配置项

接下来在这个新建的namespace下添加配置项

 

添加完成后就能在FX.Hermes.Producer的namespace中看到配置。

 

发布namespace的配置

 

4.3.5 客户端获取Namespace配置

对自定义namespace的配置获取,稍有不同,需要程序传入namespace的名字。Apollo客户端还支持和Spring整合,更多客户端使用说明请参见Java客户端使用指南.Net客户端使用指南

Config config = ConfigService.getConfig("FX.Hermes.Producer");
Integer defaultSenderBatchSize = 200;
Integer senderBatchSize = config.getIntProperty("sender.batchsize", defaultSenderBatchSize);

4.3.6 客户端监听Namespace配置变化

Config config = ConfigService.getConfig("FX.Hermes.Producer");
config.addChangeListener(new ConfigChangeListener() {
  @Override
  public void onChange(ConfigChangeEvent changeEvent) {
    System.out.println("Changes for namespace " + changeEvent.getNamespace());
    for (String key : changeEvent.changedKeys()) {
      ConfigChange change = changeEvent.getChange(key);
      System.out.println(String.format(
        "Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s",
        change.getPropertyName(), change.getOldValue(),
        change.getNewValue(), change.getChangeType()));
     }
  }
});

4.3.7 Spring集成样例

@Configuration
@EnableApolloConfig("FX.Hermes.Producer")
public class AppConfig {}
@Component
public class SomeBean {
    //timeout的值会自动更新
    @Value("${request.timeout:200}")
    private int timeout;
}

配置获取规则

在有了cluster概念后,配置的规则就显得重要了。

比如应用部署在A机房,但是并没有在Apollo新建cluster,这个时候Apollo的行为是怎样的?

或者在运行时指定了cluster=SomeCluster,但是并没有在Apollo新建cluster,这个时候Apollo的行为是怎样的?

接下来就来介绍一下配置获取的规则。

 应用自身配置的获取规则

当应用使用下面的语句获取配置时,我们称之为获取应用自身的配置,也就是应用自身的application namespace的配置。

Config config = ConfigService.getAppConfig();

对这种情况的配置获取规则,简而言之如下:

  1. 首先查找运行时cluster的配置(通过apollo.cluster指定)

  2. 如果没有找到,则查找数据中心cluster的配置

  3. 如果还是没有找到,则返回默认cluster的配置

图示如下:

 

所以如果应用部署在A数据中心,但是用户没有在Apollo创建cluster,那么获取的配置就是默认cluster(default)的。

如果应用部署在A数据中心,同时在运行时指定了SomeCluster,但是没有在Apollo创建cluster,那么获取的配置就是A数据中心cluster的配置,如果A数据中心cluster没有配置的话,那么获取的配置就是默认cluster(default)的。

 公共组件配置的获取规则

FX.Hermes.Producer为例,hermes producer是hermes发布的公共组件。当使用下面的语句获取配置时,我们称之为获取公共组件的配置。

Config config = ConfigService.getConfig("FX.Hermes.Producer");

对这种情况的配置获取规则,简而言之如下:

  1. 首先获取当前应用下的FX.Hermes.Producer namespace的配置

  2. 然后获取hermes应用下FX.Hermes.Producer namespace的配置

  3. 上面两部分配置的并集就是最终使用的配置,如有key一样的部分,以当前应用优先

图示如下:

 

通过这种方式,就实现了对框架类组件的配置管理,框架组件提供方提供配置的默认值,应用如果有特殊需求,可以自行覆盖。

 总体设计

 

上图简要描述了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进程中

4.5.1 Why Eureka

为什么我们采用Eureka作为服务注册中心,而不是使用传统的zk、etcd呢?我大致总结了一下,有以下几方面的原因:

  • 它提供了完整的Service Registry和Service Discovery实现

    • 首先是提供了完整的实现,并且也经受住了Netflix自己的生产环境考验,相对使用起来会比较省心。

  • 和Spring Cloud无缝集成

    • 我们的项目本身就使用了Spring Cloud和Spring Boot,同时Spring Cloud还有一套非常完善的开源代码来整合Eureka,所以使用起来非常方便。

    • 另外,Eureka还支持在我们应用自身的容器中启动,也就是说我们的应用启动完之后,既充当了Eureka的角色,同时也是服务的提供者。这样就极大的提高了服务的可用性。

    • 这一点是我们选择Eureka而不是zk、etcd等的主要原因,为了提高配置中心的可用性和降低部署复杂度,我们需要尽可能地减少外部依赖。

  • Open Source

    • 最后一点是开源,由于代码是开源的,所以非常便于我们了解它的实现原理和排查问题。

4.6 客户端设计

 

上图简要描述了Apollo客户端的实现原理:

  1. 客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。

  2. 客户端还会定时从Apollo配置中心服务端拉取应用的最新配置。

    • 这是一个fallback机制,为了防止推送机制失效导致配置不更新

    • 客户端定时拉取会上报本地版本,所以一般情况下,对于定时拉取的操作,服务端都会返回304 - Not Modified

    • 定时频率默认为每5分钟拉取一次,客户端也可以通过在运行时指定System Property: apollo.refreshInterval来覆盖,单位为分钟。

  3. 客户端从Apollo配置中心服务端获取到应用的最新配置后,会保存在内存中

  4. 客户端会把从服务端获取到的配置在本地文件系统缓存一份

    • 在遇到服务不可用,或网络不通的时候,依然能从本地恢复配置

  5. 应用程序从Apollo客户端获取最新的配置、订阅配置更新通知

 配置更新推送实现

前面提到了Apollo客户端和服务端保持了一个长连接,从而能第一时间获得配置更新的推送。

长连接实际上我们是通过Http Long Polling实现的,具体而言:

  • 客户端发起一个Http请求到服务端

  • 服务端会保持住这个连接60秒

    • 如果在60秒内有客户端关心的配置变化,被保持住的客户端请求会立即返回,并告知客户端有配置变化的namespace信息,客户端会据此拉取对应namespace的最新配置

    • 如果在60秒内没有客户端关心的配置变化,那么会返回Http状态码304给客户端

  • 客户端在收到服务端请求后会立即重新发起连接,回到第一步

考虑到会有数万客户端向服务端发起长连,在服务端我们使用了async servlet(Spring DeferredResult)来服务Http Long Polling请求。

可用性考虑

配置中心作为基础服务,可用性要求非常高,下面的表格描述了不同场景下Apollo的可用性:

场景 影响 降级 原因
某台config service下线 无影响 Config service无状态,客户端重连其它config service
所有config service下线 客户端无法读取最新配置,Portal无影响 客户端重启时,可以读取本地缓存配置文件
某台admin service下线 无影响 Admin service无状态,Portal重连其它admin service
所有admin service下线 客户端无影响,portal无法更新配置
某台portal下线 无影响 Portal域名通过slb绑定多台服务器,重试后指向可用的服务器
全部portal下线 客户端无影响,portal无法更新配置
某个数据中心下线 无影响 多数据中心部署,数据完全同步,Meta Server/Portal域名通过slb自动切换到其它存活的数据中心

安装

docker安装mysql

使用Docker安装Mysql是比较方便的,最简单的只需一句命令即可完成。但如需安装且配置好则需要准备一点前期工作

拉取镜像:

docker pull mysql

使用命令拉取mysql的镜像包,如需指定版本添加接口,不指定默认latest

创建挂载目录

拉取镜像后建议将配置文件,数据,日志挂载出来。方便后续修改配置或排查问题

mkdir -p /data/mysql/conf
mkdir -p /data/mysql/data
mkdir -p /data/mysql/logs

运行容器

docker run --name mysql -p 36306:3306 -v /data/mysql/conf/my.cnf:/etc/mysql/my.cnf -v /data/mysql/data:/var/lib/mysql -v /data/mysql/log:/var/log/mysql -e MYSQL_ROOT_PASSWORD=123456 --restart=always --privileged=true -d mysql

连接测试

使用Navicat创建连接测试即可。账号为root,密码为启动容器时设置的。

 Docker安装Apollo

docker镜像仓库:https://hub.docker.com/

Docker安装Apollo首先需要拉取apollo所需要的镜像包,apollo所需的镜像包有三个。分别是apollo-configservice、apollo-adminservice、apollo-portal,可以在镜像仓库选择自己需要的版本,不加版本号,默认拉取最新版本。

docker pull apollo-configservice:2.0.1
docker pull apollo-adminservice:2.0.1
docker pull apollo-portal:2.0.1

然后:

docker images

 准备配置数据:

首先需要apollo配置数据的sql脚本文件。可在apollo的github上获取.https://github.com/apolloconfig/apollo/tree/master/scripts/sql

获取到脚本文件后在Navicat 刚创建的Mysql连接中运行即可。运行之后修改apolloconfigdb数据库的serverconfig表中的eurekaUrl的值 

 将Ip地址替换为服务器IP,端口可以修改可以不修改,对应后续启动容器时的端口。

运行容器:

因为apollo拉取了三个镜像包,所以自然需要运行三个容器。且运行容器的顺序建议先是config,再是admin,最后才是portal

启动config

docker run -p 8081:8080  -e SPRING_DATASOURCE_URL="jdbc:mysql://ip:36306/ApolloConfigDB?characterEncoding=utf8"  -e SPRING_DATASOURCE_USERNAME=root -e SPRING_DATASOURCE_PASSWORD=123456  -d -v /data/apolloConfigservice/logs:/opt/logs --name apollo-configservice apolloconfig/apollo-configservice:2.0.1

启动admin

docker run -p 8091:8090  -e SPRING_DATASOURCE_URL="jdbc:mysql://ip:36306/ApolloConfigDB?characterEncoding=utf8"  -e SPRING_DATASOURCE_USERNAME=root -e SPRING_DATASOURCE_PASSWORD=123456  -d -v /data/apolloAdminservice/logs:/opt/logs --name apollo-adminservice apolloconfig/apollo-adminservice:2.0.1

启动portal

docker run -p 8071:8070  -e SPRING_DATASOURCE_URL="jdbc:mysql://ip:36306/ApolloPortalDB?characterEncoding=utf8"  -e SPRING_DATASOURCE_USERNAME=root -e SPRING_DATASOURCE_PASSWORD=123456 -e APOLLO_PORTAL_ENVS=dev  -e DEV_META=http://ip:8081  -d -v /data/apolloPortal/logs:/opt/logs --name apollo-portal apolloconfig/apollo-portal:2.0.1

运行验证

启动成功后可使用命令查看容器状态

 然后访问:http://ip:8071/signin

初始账户名:apollo 密码:admin 

Java介入

依赖

<!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-client</artifactId>
    <version>1.7.0</version>
</dependency>

配置文件

app.id=001

apollo.meta=http://ip:8081.   #configServer地址
apollo.bootstrap.enabled=true
apollo.bootstrap.namespaces=application

测试controller

@RestController
public class MainController {

	
	@Value("${conf}")
	private String conf;
	
	@GetMapping("/")
	public String list() {
		System.out.println(conf);
		return conf;
	}
	
}

此时启动项目会报错:

2022-09-15 10:54:02.832  INFO 55090 --- [           main] c.c.f.f.i.p.DefaultApplicationProvider   : App ID is set to operation by app.id property from System Property
2022-09-15 10:54:02.835  INFO 55090 --- [           main] c.c.f.f.i.p.DefaultServerProvider        : Environment is set to null. Because it is not available in either (1) JVM system property 'env', (2) OS env variable 'ENV' nor (3) property 'env' from the properties InputStream.
2022-09-15 10:54:02.853  INFO 55090 --- [           main] c.c.f.a.i.DefaultMetaServerProvider      : Located meta services from apollo.meta configuration: http://ip:8081!
2022-09-15 10:54:02.855  INFO 55090 --- [           main] c.c.f.apollo.core.MetaDomainConsts       : Located meta server address http://ip:8081 for env UNKNOWN from com.ctrip.framework.apollo.internals.DefaultMetaServerProvider
2022-09-15 10:54:04.612  WARN 55090 --- [           main] c.c.f.a.i.RemoteConfigRepository         : Load config failed, will retry in 1 SECONDS. appId: operation, cluster: default, namespaces: application
2022-09-15 10:54:06.619  WARN 55090 --- [           main] c.c.f.a.i.AbstractConfigRepository       : Sync config failed, will retry. Repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository, reason: Load Apollo Config failed - appId: operation, cluster: default, namespace: application, url: http://172.17.0.4:8080/configs/operation/default/application?ip=172.20.10.2 [Cause: Could not complete get operation [Cause: connect timed out]]
2022-09-15 10:54:07.628  WARN 55090 --- [           main] c.c.f.a.i.RemoteConfigRepository         : Load config failed, will retry in 1 SECONDS. appId: operation, cluster: default, namespaces: application
2022-09-15 10:54:09.634  WARN 55090 --- [           main] c.c.f.a.i.LocalFileConfigRepository      : Sync config from upstream repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository failed, reason: Load Apollo Config failed - appId: operation, cluster: default, namespace: application, url: http://172.17.0.4:8080/configs/operation/default/application?ip=172.20.10.2 [Cause: Could not complete get operation [Cause: connect timed out]]
2022-09-15 10:54:09.649  WARN 55090 --- [ngPollService-1] c.c.f.a.i.RemoteConfigLongPollService    : Long polling failed, will retry in 1 seconds. appId: operation, cluster: default, namespaces: application, long polling url: http://172.17.0.4:8080/notifications/v2?cluster=default&appId=operation&ip=172.20.10.2&notifications=%5B%7B%22namespaceName%22%3A%22application%22%2C%22notificationId%22%3A-1%7D%5D, reason: Could not complete get operation [Cause: connect timed out]
2022-09-15 10:54:10.636  WARN 55090 --- [           main] c.c.f.a.i.RemoteConfigRepository         : Load config failed, will retry in 1 SECONDS. appId: operation, cluster: default, namespaces: application
2022-09-15 10:54:11.657  WARN 55090 --- [ngPollService-1] c.c.f.a.i.RemoteConfigLongPollService    : Long polling failed, will retry in 2 seconds. appId: operation, cluster: default, namespaces: application, long polling url: http://172.17.0.4:8080/notifications/v2?cluster=default&appId=operation&ip=172.20.10.2&notifications=%5B%7B%22namespaceName%22%3A%22application%22%2C%22notificationId%22%3A-1%7D%5D, reason: Could not complete get operation [Cause: connect timed out]
2022-09-15 10:54:12.643  WARN 55090 --- [           main] c.c.f.a.i.LocalFileConfigRepository      : Sync config from upstream repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository failed, reason: Load Apollo Config failed - appId: operation, cluster: default, namespace: application, url: http://172.17.0.4:8080/configs/operation/default/application?ip=172.20.10.2 [Cause: Could not complete get operation [Cause: connect timed out]]
2022-09-15 10:54:12.644  WARN 55090 --- [           main] c.c.f.a.i.AbstractConfigRepository       : Sync config failed, will retry. Repository class com.ctrip.framework.apollo.internals.LocalFileConfigRepository, reason: Load config from local config failed! [Cause: Cannot read from local cache file /Users/chenhao/workspace/apollo/apolloDemo/target/classes/config-cache/operation+default+application.properties]
2022-09-15 10:54:13.647  WARN 55090 --- [           main] c.c.f.a.i.RemoteConfigRepository         : Load config failed, will retry in 1 SECONDS. appId: operation, cluster: default, namespaces: application
2022-09-15 10:54:14.663  WARN 55090 --- [ngPollService-1] c.c.f.a.i.RemoteConfigLongPollService    : Long polling failed, will retry in 4 seconds. appId: operation, cluster: default, namespaces: application, long polling url: http://172.17.0.4:8080/notifications/v2?cluster=default&appId=operation&ip=172.20.10.2&notifications=%5B%7B%22namespaceName%22%3A%22application%22%2C%22notificationId%22%3A-1%7D%5D, reason: Could not complete get operation [Cause: connect timed out]
2022-09-15 10:54:15.651  WARN 55090 --- [           main] c.c.f.a.i.LocalFileConfigRepository      : Sync config from upstream repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository failed, reason: Load Apollo Config failed - appId: operation, cluster: default, namespace: application, url: http://172.17.0.4:8080/configs/operation/default/application?ip=172.20.10.2 [Cause: Could not complete get operation [Cause: connect timed out]]
2022-09-15 10:54:15.652  WARN 55090 --- [           main] c.c.f.apollo.internals.DefaultConfig     : Init Apollo Local Config failed - namespace: application, reason: Load config from local config failed! [Cause: Cannot read from local cache file /Users/chenhao/workspace/apollo/apolloDemo/target/classes/config-cache/operation+default+application.properties].
2022-09-15 10:54:15.653  WARN 55090 --- [           main] c.c.f.apollo.internals.DefaultConfig     : Could not load config for namespace application from Apollo, please check whether the configs are released in Apollo! Return default value now!
2022-09-15 10:54:15.666  INFO 55090 --- [           main] com.itlum.apollo.SpringBootStarter       : Starting SpringBootStarter on chenhaodeMacBook-Pro-2.local with PID 55090 (/Users/chenhao/workspace/apollo/apolloDemo/target/classes started by chenhao in /Users/chenhao/workspace/apollo/apolloDemo)
2022-09-15 10:54:15.667  INFO 55090 --- [           main] com.itlum.apollo.SpringBootStarter       : No active profile set, falling back to default profiles: default
2022-09-15 10:54:16.180  INFO 55090 --- [           main] o.s.c.a.ConfigurationClassPostProcessor  : Cannot enhance @Configuration bean definition 'com.ctrip.framework.apollo.spring.boot.ApolloAutoConfiguration' since its singleton instance has been created too early. The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.
2022-09-15 10:54:16.294  WARN 55090 --- [           main] o.s.b.c.p.PropertySourcesDeducer         : Multiple PropertySourcesPlaceholderConfigurer beans registered [propertySourcesPlaceholderConfigurer, org.springframework.context.support.PropertySourcesPlaceholderConfigurer], falling back to Environment
2022-09-15 10:54:16.575  INFO 55090 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-09-15 10:54:16.594  INFO 55090 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-09-15 10:54:16.594  INFO 55090 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.19]
2022-09-15 10:54:16.694  INFO 55090 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-09-15 10:54:16.695  INFO 55090 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 992 ms
2022-09-15 10:54:16.747  WARN 55090 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mainController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'config' in value "${config}"
2022-09-15 10:54:16.750  INFO 55090 --- [           main] o.apache.catalina.core.StandardService   : Stopping service [Tomcat]
2022-09-15 10:54:16.760  INFO 55090 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2022-09-15 10:54:16.768 ERROR 55090 --- [           main] o.s.boot.SpringApplication               : Application run failed

注意这一行报错:

Sync config failed, will retry. Repository class com.ctrip.framework.apollo.internals.RemoteConfigRepository, reason: Load Apollo Config failed - appId: operation, cluster: default, namespace: application, url: http://172.17.0.4:8080/configs/operation/default/application?ip=172.20.10.2 

原因是我们使用docker安装,所以docker容器内部会分配一个ip地址,此时我们只需要在idea上添加

在运行代码,运行正常 

事件监听

@Configuration
public class ApolloConfig {

    @Bean
    public void config() {
        // config instance is singleton for each namespace and is never null
        Config config = ConfigService.getAppConfig();
        config.addChangeListener(changeEvent -> {
            System.out.println("Changes for namespace " + changeEvent.getNamespace());
            for (String key : changeEvent.changedKeys()) {
                ConfigChange change = changeEvent.getChange(key);
                System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change.getOldValue(), change.getNewValue(), change.getChangeType()));
            }
        });
    }
}

上面代码会实时监控我们apollo里面配置的改变,我们可以在此程序中决定是否要用新值代替旧值

缓存

另外apollo会在本地缓存配置:

linux
/opt/data/{appId}/config-cache 
Windows下
C:\opt\data{appId}\config-cache

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

docker安装Apollo,并用java连接测试 的相关文章

随机推荐

  • Idea 生成模板代码(Demo)

    1 在html文件中复制需要生成模板的代码 如下图选中部分 ctrl c 2 点击 File gt Settings 如下图 3 选择 Editor gt Live Template 点击右边的 然后点击 1 Live Template 如
  • 【Yarn】Yarn ApplicationMasterLauncher的工作机制

    文章目录 1 概述 2 源码 2 1 类变量 2 2 构造方法 2 4 serviceInit 2 5 serviceStart 2 6 LauncherThread 2 7 launch事件 2 8 AMLauncher的run 1 概述
  • 前端框架Vue(5)——Vue + Echarts (数据可视化)

    Echarts 是数据可视化中佼佼者 推荐大家可以玩一玩 非常实用 如果第一次接触Echarts的同学 这边有我以前写过的一篇入门 浅谈Echarts3 0 Vue Echarts 现附上代码
  • 数据结构作业:实现链表的基本操作

    数据结构作业 实现链表的基本操作 链表是一种常见的数据结构 它由一系列节点组成 每个节点包含数据和指向下一个节点的指针 本文将介绍链表的基本操作 包括创建链表 插入节点 删除节点以及遍历链表 首先 我们需要定义链表节点的结构体 节点包含一个
  • signature=31a231fa44057e3d64bcbe8f86676d0e,typescript-definitions

    THIS IS AN AUTOGENERATED FILE DO NOT EDIT THIS FILE DIRECTLY yarn lockfile v1 continuous auth client 1 1 0 version 1 2 3
  • 2020-04-08

    查看有关计算机的基本信息 1 右键点击 计算机 的 属性 就能看到这台电脑的基本信息了
  • Android Platform 3.0 SDK和Eclipse ADT安装记录(最初版本,纪念用)

    注意 此文非常非常地过时 只是用于个人回想 请参看 二 以后的笔记 20110926 注意 此文由于结构过于混乱且内容过时 将会被删除 用新的学习日记取代 如果我有时间的话 注 我只是为了学习简单的Android编程和模拟 所以没有考虑SD
  • 图示CORDIC算法

    目录 简介 原理 硬件实现 简介 CORDIC Coordinate Rotation Digital Computer 坐标旋转数字计算方法 应用 计算三角函数 cos sin tan 或者计算旋转角 原理 问题 在下图中 C点的坐标是
  • 阿里云教程安装WordPress没有 安装新插件 及 主题 的按钮

    表象 在插件页面和主题页面没有Add New的按钮 经过一番百度后 主要分为两派 文件权限问题 your wordpress site folder如果按照阿里云教程 该地址为 var www html wp blog 解决方案 chown
  • React 项目:计算器

    本教程专注于 React 部分 故对 css 及 js 不做过多解释 项目地址 yuzheng14 calculator github com 分析原型 应用中一共包含 4 个组件 APP 整个应用的整体 Display 展示输入数据及计算
  • 外网SSH远程连接linux服务器「cpolar内网穿透」

    文章目录 1 Linux CentOS安装cpolar 2 创建TCP隧道 3 随机地址公网远程连接 4 固定TCP地址 5 使用固定公网TCP地址SSH远程 本次教程我们来实现如何在外公网环境下 SSH远程连接家里 公司的Linux Ce
  • SpringBoot结合Liquibase实现数据库变更管理

    从零打造项目 系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建 SpringBoot集成Mybatis项目实操 SpringBoot集成MybatisPlus项目实
  • Java利用正则表达式获取指定两个字符串之间的内容

    package com starit analyse util import java text SimpleDateFormat import java util ArrayList import java util List impor
  • CentOS 7 下使用 MySQL 5.7 + PHP 7 + Apache 部署 Nextcloud

    准备 如果你准备使用 VPS 或者云主机作为 Nextcloud 服务器的话 可以先安装一个 Xshell 注 以下代码块中 代表注释 代表 Linux 命令 姊妹篇 Ubuntu 16 04 下使用 MySQL 5 7 PHP 7 Apa
  • python对指定字符串逆序的6种方法

    对于一个给定的字符串 逆序输出 这个任务对于python来说是一种很简单的操作 毕竟强大的列表和字符串处理的一些列函数足以应付这些问题 了 今天总结了一下python中对于字符串的逆序输出的几种常用的方法 方法一 直接使用字符串切片功能逆转
  • cuda学习笔记之异步并行执行

    异步函数使得主机端与设备端并行执行 控制在设备还没有完成前就被返回给主机线程 包括 kernel启动 以Async为后缀的内存拷贝函数 device到device内存拷贝函数 存储器初始化函数 比如cudaMemset cudaMemset
  • linux离线安装llvm,Debian/Ubuntu Linux 下安装LLVM/Clang 编译器

    第一步 首先编辑 etc apt sources list 加入以下源 Debian平台 deb http llvm org apt wheezy llvm toolchain wheezy main deb src http llvm o
  • Qt将文件保存到指定目录下(另存为的功能)

    因为Qt才开始入门 对文件的操作还不是很熟练 经过一段时间查找终于找出一些适用于入门的代码 QDir d d mkpath D 123 file new QFile D 123 tmp file gt open QFile WriteOnl
  • MySQL索引实现原理分析

    目前大部分数据库系统及文件系统都采用B Tree B树 或其变种B Tree B 树 作为索引结构 B Tree是数据库系统实现索引的首选数据结构 在 MySQL 中 索引属于存储引擎级别的概念 不同存储引擎对索引的实现方式是不同的 本文主
  • docker安装Apollo,并用java连接测试

    What is Apollo 背景 随着程序功能的日益复杂 程序的配置日益增多 各种功能的开关 参数的配置 服务器的地址 对程序配置的期望值也越来越高 配置修改后实时生效 灰度发布 分环境 分集群管理配置 完善的权限 审核机制 在这样的大环