开源配置管理中心apollo使用方法

# 开源配置管理中心apollo使用方法

# 什么是apollo

Apollo(阿波罗)是一款可靠的分布式配置管理中心,诞生于携程框架研发部,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

# 应用什么场景

项目在不同环境对应的不同的配置,统一管理不同环境、不同集群的配置

Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。 同一份代码部署在不同的集群,可以有不同的配置,比如zk的地址等 通过命名空间(namespace)可以很方便的支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖

基于Linux搭建开源配置管理中心apollo

# 系统介绍

系统 Centos7
java环境 java1.8
数据库 MariaDB-10.2.9
IP 192.168.1.8

# 使用文档 (opens new window)

# 名词解释

普通应用 普通应用指的是独立运行的程序,如Web应用程序、带有main函数的程序

公共组件 公共组件指的是发布的类库、客户端程序,不会自己独立运行,如Java的jar包、.Net的dll文件

# 普通应用接入指南

# 创建项目

要使用Apollo,第一步需要创建项目。

  1. 打开apollo-portal主页
  2. 点击“创建项目”

create-app-entry

  1. 输入项目信息
    • 部门:选择应用所在的部门
    • 应用AppId:用来标识应用身份的唯一id,格式为string,需要和客户端app.properties中配置的app.id对应
    • 应用名称:应用名,仅用于界面展示
    • 应用负责人:选择的人默认会成为该项目的管理员,具备项目权限管理、集群创建、Namespace创建等权限

create-app

  1. 点击提交

    创建成功后,会自动跳转到项目首页

app-created

# 项目权限分配

# 项目管理员权限

项目管理员拥有以下权限:

  1. 可以管理项目的权限分配
  2. 可以创建集群
  3. 可以创建Namespace

创建项目时填写的应用负责人默认会成为项目的管理员之一,如果还需要其他人也成为项目管理员,可以按照下面步骤操作:

  1. 点击页面左侧的“管理项目”

    • app-permission-entry
  2. 搜索需要添加的成员并点击添加

    • app-permission-search-user
    • app-permission-user-added

# 配置编辑、发布权限

配置权限分为编辑和发布:

  • 编辑权限允许用户在Apollo界面上创建、修改、删除配置
    • 配置修改后只在Apollo界面上变化,不会影响到应用实际使用的配置
  • 发布权限允许用户在Apollo界面上发布、回滚配置
    • 配置只有在发布、回滚动作后才会被应用实际使用到
    • Apollo在用户操作发布、回滚动作后实时通知到应用,并使最新配置生效

项目创建完,默认没有分配配置的编辑和发布权限,需要项目管理员进行授权。

  1. 点击application这个namespace的授权按钮
    • namespace-permission-entry
  2. 分配修改权限
    • namespace-permission-edit
  3. 分配发布权限
    • namespace-publish-permission

# 添加配置项

编辑配置需要拥有这个Namespace的编辑权限,如果发现没有新增配置按钮,可以找项目管理员授权。

# 通过表格模式添加配置

  1. 点击新增配置
    • create-item-entry
  2. 输入配置项
    • create-item-detail
  3. 点击提交
    • item-created

# 通过文本模式编辑

Apollo除了支持表格模式,逐个添加、修改配置外,还提供文本模式批量添加、修改。 这个对于从已有的properties文件迁移尤其有用。

  1. 切换到文本编辑模式

    text-mode-config-overview

  2. 点击右侧的修改配置按钮

    text-mode-config-entry

  3. 输入配置项,并点击提交修改

    text-mode-config-submit

# 发布配置

配置只有在发布后才会真的被应用使用到,所以在编辑完配置后,需要发布配置。

发布配置需要拥有这个Namespace的发布权限,如果发现没有发布按钮,可以找项目管理员授权。

  1. 点击“发布按钮” publish-entry

  2. 填写发布相关信息,点击发布

    publish-detail

# 应用读取配置

配置发布成功后,应用就可以通过Apollo客户端读取到配置了。

Apollo目前提供Java客户端,具体信息请点击Java客户端使用文档 (opens new window)

如果应用使用了其它语言,也可以通过直接访问Http接口获取配置,具体可以参考其它语言客户端接入指南 (opens new window)

# 应用接入Apollo

首先需要在Apollo中接入你的应用,具体步骤可以参考应用接入文档 (opens new window)

# 通过带缓存的Http接口从Apollo读取配置

该接口会从缓存中获取配置,适合频率较高的配置拉取请求,如简单的每30秒轮询一次配置。

由于缓存最多会有一秒的延时,所以如果需要配合配置推送通知实现实时更新配置的话,请参考通过不带缓存的Http接口从Apollo读取配置

# Http接口说明

URL: {config_server_url}/configfiles/json/{appId}/{clusterName}/{namespaceName}?ip={clientIp}

Method: GET

参数说明

参数名 是否必须 参数值 备注
config_server_url Apollo配置服务的地址
appId 应用的appId
clusterName 集群名 一般情况下传入 default 即可。 如果希望配置按集群划分,可以参考集群独立配置说明 (opens new window)做相关配置,然后在这里填入对应的集群名。
namespaceName Namespace的名字 如果没有新建过Namespace的话,传入application即可。 如果创建了Namespace,并且需要使用该Namespace的配置,则传入对应的Namespace名字。需要注意的是对于properties类型的namespace,只需要传入namespace的名字即可,如application。对于其它类型的namespace,需要传入namespace的名字加上后缀名,如datasources.json
ip 应用部署的机器ip 这个参数是可选的,用来实现灰度发布。 如果不想传这个参数,请注意URL中从?号开始的query parameters整个都不要出现。

# Http接口返回格式

该Http接口返回的是JSON格式、UTF-8编码,包含了对应namespace中所有的配置项。

返回内容Sample如下:

{
    "portal.elastic.document.type":"biz",
    "portal.elastic.cluster.name":"hermes-es-fws"
}
1
2
3
4

通过{config_server_url}/configfiles/{appId}/{clusterName}/{namespaceName}?ip={clientIp}可以获取到properties形式的配置

# 测试

由于是Http接口,所以在URL组装OK之后,直接通过浏览器、或者相关的http接口测试工具访问即可。

本地测试:

# curl http://192.168.1.5:8080/configfiles/json/1001/default/application

{"redis_ip":"192.168.1.12","redis_passwd":"123456","redis_port":"6379"}
1
2
3

# 通过不带缓存的Http接口从Apollo读取配置

该接口会直接从数据库中获取配置,可以配合配置推送通知实现实时更新配置。

# Http接口说明

URL: {config_server_url}/configs/{appId}/{clusterName}/{namespaceName}?releaseKey={releaseKey}&ip={clientIp}

Method: GET

参数说明

参数名 是否必须 参数值 备注
config_server_url Apollo配置服务的地址
appId 应用的appId
clusterName 集群名 一般情况下传入 default 即可。 如果希望配置按集群划分,可以参考集群独立配置说明 (opens new window)做相关配置,然后在这里填入对应的集群名。
namespaceName Namespace的名字 如果没有新建过Namespace的话,传入application即可。 如果创建了Namespace,并且需要使用该Namespace的配置,则传入对应的Namespace名字。需要注意的是对于properties类型的namespace,只需要传入namespace的名字即可,如application。对于其它类型的namespace,需要传入namespace的名字加上后缀名,如datasources.json
releaseKey 上一次的releaseKey 将上一次返回对象中的releaseKey传入即可,用来给服务端比较版本,如果版本比下来没有变化,则服务端直接返回304以节省流量和运算
ip 应用部署的机器ip 这个参数是可选的,用来实现灰度发布。

# Http接口返回格式

该Http接口返回的是JSON格式、UTF-8编码。

如果配置没有变化(传入的releaseKey和服务端的相等),则返回HttpStatus 304,response body为空。

如果配置有变化,则会返回HttpStatus 200,response body为对应namespace的meta信息以及其中所有的配置项。

返回内容Sample如下:

{
  "appId": "100004458",
  "cluster": "default",
  "namespaceName": "application",
  "configurations": {
    "portal.elastic.document.type":"biz",
    "portal.elastic.cluster.name":"hermes-es-fws"
  },
  "releaseKey": "20170430092936-dee2d58e74515ff3"
}
1
2
3
4
5
6
7
8
9
10

# 测试

由于是Http接口,所以在URL组装OK之后,直接通过浏览器、或者相关的http接口测试工具访问即可。

本地测试

# curl http://192.168.1.5:8080/configs/1001/default/application
{"appId":"1001","cluster":"default","namespaceName":"application","configurations":{"redis_ip":"192.168.1.12","redis_passwd":"123456","redis_port":"6379"},"releaseKey":"20220330100056-d3ee492df675126d"}

# curl http://192.168.1.5:8080/configs/1001/default/application?releaseKey=20220330100056-d3ee492df675126d

1
2
3
4
5

# 应用感知配置更新

Apollo提供了基于Http long polling的配置更新推送通知,第三方客户端可以看自己实际的需求决定是否需要使用这个功能。

如果对配置更新时间不是那么敏感的话,可以通过定时刷新来感知配置更新,刷新频率可以视应用自身情况来定,建议在30秒以上。

如果需要做到实时感知配置更新(1秒)的话,可以参考下面的文档实现配置更新推送的功能。

# 配置更新推送实现思路

这里建议大家可以参考Apollo的Java实现:RemoteConfigLongPollService.java (opens new window),代码量200多行,总体上还是比较简单的。

# 初始化

首先需要确定哪些namespace需要配置更新推送,Apollo的实现方式是程序第一次获取某个namespace的配置时就会来注册一下,我们就知道有哪些namespace需要配置更新推送了。

初始化后的结果就是得到一个notifications的Map,内容是namespaceName -> notificationId(初始值为-1)。

运行过程中如果发现有新的namespace需要配置更新推送,直接塞到notifications这个Map里面即可。

# 请求服务

有了notifications这个Map之后,就可以请求服务了。这里先描述一下请求服务的逻辑,具体的URL参数和说明请参见后面的接口说明。

  1. 请求远端服务,带上自己的应用信息以及notifications信息
  2. 服务端针对传过来的每一个namespace和对应的notificationId,检查notificationId是否是最新的
  3. 如果都是最新的,则保持住请求60秒,如果60秒内没有配置变化,则返回HttpStatus 304。如果60秒内有配置变化,则返回对应namespace的最新notificationId, HttpStatus 200。
  4. 如果传过来的notifications信息中发现有notificationId比服务端老,则直接返回对应namespace的最新notificationId, HttpStatus 200。
  5. 客户端拿到服务端返回后,判断返回的HttpStatus
  6. 如果返回的HttpStatus是304,说明配置没有变化,重新执行第1步
  7. 如果返回的HttpStauts是200,说明配置有变化,针对变化的namespace重新去服务端拉取配置,参见1.3 通过不带缓存的Http接口从Apollo读取配置 (opens new window)。同时更新notifications map中的notificationId。重新执行第1步。

# Http接口说明

URL: {config_server_url}/notifications/v2?appId={appId}&cluster={clusterName}&notifications={notifications}

Method: GET

参数说明

参数名 是否必须 参数值 备注
config_server_url Apollo配置服务的地址
appId 应用的appId
clusterName 集群名 一般情况下传入 default 即可。 如果希望配置按集群划分,可以参考集群独立配置说明 (opens new window)做相关配置,然后在这里填入对应的集群名。
notifications notifications信息 传入本地的notifications信息,注意这里需要以array形式转为json传入,如:[{"namespaceName": "application", "notificationId": 100}, {"namespaceName": "FX.apollo", "notificationId": 200}]。需要注意的是对于properties类型的namespace,只需要传入namespace的名字即可,如application。对于其它类型的namespace,需要传入namespace的名字加上后缀名,如datasources.json

注1:由于服务端会hold住请求60秒,所以请确保客户端访问服务端的超时时间要大于60秒。

注2:别忘了对参数进行url encode (opens new window)

# Http接口返回格式

该Http接口返回的是JSON格式、UTF-8编码,包含了有变化的namespace和最新的notificationId。

返回内容Sample如下:

[
  {
    "namespaceName": "application",
    "notificationId": 101
  }
]
1
2
3
4
5
6

# 测试

由于是Http接口,所以在URL组装OK之后,直接通过浏览器、或者相关的http接口测试工具访问即可。

# 配置访问密钥

Apollo从1.6.0版本开始增加访问密钥机制,从而只有经过身份验证的客户端才能访问敏感配置。如果应用开启了访问密钥,客户端发出请求时需要增加签名,否则无法获取配置。

需要设置的Header信息:

Header Value 备注
Authorization Apollo ${appId}😒{signature} appId: 应用的appId,signature:使用访问密钥对当前时间以及所访问的URL加签后的值,具体实现可以参考Signature.signature (opens new window)
Timestamp 1970-1-1 00:00:00 UTC+0到现在所经过的毫秒数 可以参考System.currentTimeMillis (opens new window)

本地测试

# curl
http://192.168.1.5:8080/configfiles/json/1001/default/application
{"timestamp":"2022-03-30T16:39:11.912+0800","status":401,"error":"Unauthorized","message":"","path":"/configfiles/json/1001/default/application"}
报错 401

密钥: da01f4aab45d4e3c8b8764d99f9a31f5




获取时间戳: Timestamp=`date +%s`

curl http://192.168.1.5:8080/configfiles/json/1001/default/application -X POST -H "Content-type:application/json" -d '{"Authorization":"Apollo 1001:da01f4aab45d4e3c8b8764d99f9a31f5","Timestamp":"1648630422"}'

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 错误码说明

正常情况下,接口返回的Http状态码是200,下面列举了Apollo会返回的非200错误码说明。

# 400 - Bad Request

客户端传入参数的错误,如必选参数没有传入等,客户端需要根据提示信息检查对应的参数是否正确。

# 401 - Unauthorized

客户端未授权,如服务端配置了访问密钥,客户端未配置或配置错误。

# 404 - Not Found

接口要访问的资源不存在,一般是URL或URL的参数错误,或者是对应的namespace还没有发布过配置。

# 405 - Method Not Allowed

接口访问的Method不正确,比如应该使用GET的接口使用了POST访问等,客户端需要检查接口访问方式是否正确。

# 500 - Internal Server Error

其它类型的错误默认都会返回500,对这类错误如果应用无法根据提示信息找到原因的话,可以尝试查看服务端日志来排查问题。

# Apollo使用场景和示例代码

https://github.com/ctripcorp/apollo-use-cases

# Apollo 实践案例

# Apollo 安全相关最佳实践

# 配置查看权限

从1.1.0版本开始,apollo-portal增加了查看权限的支持,可以支持配置某个环境只允许项目成员查看私有Namespace的配置。

这里的项目成员是指:

  1. 项目的管理员
  2. 具备该私有Namespace在该环境下的修改或发布权限

配置方式很简单,用超级管理员账号登录后,进入管理员工具 - 系统参数页面新增或修改configView.memberOnly.envs配置项即可。

configView.memberOnly.envs

# 配置访问密钥

Apollo从1.6.0版本开始增加访问密钥机制,从而只有经过身份验证的客户端才能访问敏感配置。如果应用开启了访问密钥,客户端需要配置密钥,否则无法获取配置。

  1. 项目管理员打开管理密钥页面

    94990081-f4d3cd80-05ab-11eb-9470-fed5ec6de92e-164861936808620

  2. 为项目的每个环境生成访问密钥,注意默认是禁用的,建议在客户端都配置完成后再开启

    94990150-788dba00-05ac-11eb-9a12-727fdb872e42-164861936808621

# 客户端配置访问密钥

适用于1.6.0及以上版本

Apollo从1.6.0版本开始增加访问密钥机制,从而只有经过身份验证的客户端才能访问敏感配置。如果应用开启了访问密钥,客户端需要配置密钥,否则无法获取配置。

配置方式按照优先级从高到低分别为:

1.通过Java System Property

通过Java System Propertyapollo.access-key.secret(1.9.0+) 或者 apollo.accesskey.secret(1.9.0之前)
可以通过Java的System Property apollo.access-key.secret(1.9.0+) 或者 apollo.accesskey.secret(1.9.0之前)来指定
在Java程序启动脚本中,可以指定-Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0+) 或者 -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0之前)
如果是运行jar文件,需要注意格式是java -Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar(1.9.0+) 或者 java -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar(1.9.0之前)

也可以通过程序指定,如System.setProperty("apollo.access-key.secret", "1cf998c4e2ad4704b45a98a509d15719");(1.9.0+) 或者 System.setProperty("apollo.accesskey.secret", "1cf998c4e2ad4704b45a98a509d15719");(1.9.0之前)
1
2
3
4
5
6

2.通过Spring Boot的配置文件

可以在Spring Boot的application.properties或bootstrap.properties中指定apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0+) 或者 apollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0之前)
1

3.通过操作系统的System Environment

还可以通过操作系统的System Environment APOLLO_ACCESS_KEY_SECRET(1.9.0+) 或者 APOLLO_ACCESSKEY_SECRET(1.9.0之前)来指定
注意key为全大写

4.通过app.properties配置文件

可以在classpath:/META-INF/app.properties指定apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0+) 或者 apollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719(1.9.0之前)
1

# 自定义server.properties路径

适用于1.8.0及以上版本

1.8.0版本开始支持以下方式自定义server.properties路径,按照优先级从高到低分别为:

一.通过Java System Property apollo.path.server.properties

1.可以通过Java的System Property apollo.path.server.properties来指定

2.在Java程序启动脚本中,可以指定-Dapollo.path.server.properties=/some-dir/some-file.properties
如果是运行jar文件,需要注意格式是java -Dapollo.path.server.properties=/some-dir/some-file.properties -jar xxx.jar

3.也可以通过程序指定,如System.setProperty("apollo.path.server.properties", "/some-dir/some-file.properties");

1
2
3
4
5
6
7

二、通过操作系统的System EnvironmentAPOLLO_PATH_SERVER_PROPERTIES

可以通过操作系统的System Environment APOLLO_PATH_SERVER_PROPERTIES来指定
注意key为全大写,且中间是_分隔
1
2

# 客户端用法 (opens new window)

Apollo支持API方式和Spring整合方式,该怎么选择用哪一种方式?

  • API方式灵活,功能完备,配置值实时更新(热发布),支持所有Java环境。

  • Spring方式接入简单,结合Spring有N种酷炫的玩法,如

    • Placeholder方式:
      • 代码中直接使用,如:@Value("${someKeyFromApollo:someDefaultValue}")
      • 配置文件中使用替换placeholder,如:spring.datasource.url: ${someKeyFromApollo:someDefaultValue}
      • 直接托管spring的配置,如在apollo中直接配置spring.datasource.url=jdbc:mysql://localhost:3306/somedb?characterEncoding=utf8
    • Spring boot的@ConfigurationProperties (opens new window)方式
    • 从v0.10.0开始的版本支持placeholder在运行时自动更新,具体参见PR #972 (opens new window)。(v0.10.0之前的版本在配置变化后不会重新注入,需要重启才会更新,如果需要配置值实时更新,可以参考后续3.2.2 Spring Placeholder的使用 (opens new window)的说明)
  • Spring方式也可以结合API方式使用,如注入Apollo的Config对象,就可以照常通过API方式获取配置了:

    @ApolloConfig
    private Config config; //inject config for namespace application点击复制错误复制成功
    
    1
    2

# API使用方式

API方式是最简单、高效使用Apollo配置的方式,不依赖Spring框架即可使用。

# 获取默认namespace的配置(application)

Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromDefaultNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);

1
2
3
4
5

通过上述的config.getProperty可以获取到someKey对应的实时最新的配置值。

另外,配置值从内存中获取,所以不需要应用自己做缓存。

# Go、Python、Nodejs、PHP等客户端使用

对应开发语言支持:https://www.apolloconfig.com/#/zh/usage/third-party-sdks-user-guide

# Apollo PHP 客户端 1 (opens new window)

项目地址:apollo-php-client (opens new window)

# Apollo PHP 客户端 2 (opens new window)

项目地址:apollo-sdk-config (opens new window)

项目地址:apollo-sdk-clientd (opens new window)

# 什么是Namespace (opens new window)

Namespace是配置项的集合,类似于一个配置文件的概念。

个人觉得也是Apollo的比较重要和核心的知识点!

# 什么是“application”的Namespace

Apollo在创建项目的时候,都会默认创建一个“application”的Namespace。顾名思义,“application”是给应用自身使用的,熟悉Spring Boot的同学都知道,Spring Boot项目都有一个默认配置文件application.yml。在这里application.yml就等同于“application”的Namespace。对于90%的应用来说,“application”的Namespace已经满足日常配置使用场景了。

# 客户端获取“application” Namespace的代码如下:

  Config config = ConfigService.getAppConfig();
1

# 客户端获取非“application” Namespace的代码如下:

  Config config = ConfigService.getConfig(namespaceName);
1

# Namespace的格式有哪些?

配置文件有多种格式,例如:properties、xml、yml、yaml、json等。同样Namespace也具有这些格式。在Portal UI中可以看到“application”的Namespace上有一个“properties”标签,表明“application”是properties格式的。

注1:非properties格式的namespace,在客户端使用时需要调用ConfigService.getConfigFile(String namespace, ConfigFileFormat configFileFormat)来获取,如果使用Http接口直接调用 (opens new window)时,对应的namespace参数需要传入namespace的名字加上后缀名,如datasources.json。

注2:apollo-client 1.3.0版本开始对yaml/yml做了更好的支持,使用起来和properties格式一致:Config config = ConfigService.getConfig("application.yml");,Spring的注入方式也和properties一致。

# Namespace的获取权限分类

private (私有的)

public (公共的)

这里的获取权限是相对于Apollo客户端来说的。

private权限的Namespace:只能被所属的应用获取到。一个应用尝试获取其它应用private的Namespace,Apollo会报“404”异常。

public权限的Namespace: 能被任何应用获取。

# Namespace的类型

Namespace类型有三种:

# 私有类型

具有private权限。例如上文提到的“application” Namespace就是私有类型。

# 公共类型

具有public权限。公共类型的Namespace相当于游离于应用之外的配置,且通过Namespace的名称去标识公共Namespace,所以公共的Namespace的名称必须全局唯一。

使用场景:部门级别共享的配置、小组级别共享的配置、几个项目之间共享的配置、中间件客户端的配置。

# 关联类型(继承类型)

关联类型又可称为继承类型,关联类型具有private权限。关联类型的Namespace继承于公共类型的Namespace,用于覆盖公共Namespace的某些配置。

例如公共的Namespace有两个配置项

k1 = v1
k2 = v2
1
2

然后应用A有一个关联类型的Namespace关联了此公共Namespace,且覆盖了配置项k1,新值为v3。那么在应用A实际运行时,获取到的公共Namespace的配置为:

k1 = v3
k2 = v2
1
2

关联类型使用场景:

举一个实际使用的场景。假设RPC框架的配置(如:timeout)有以下要求:

  • 提供一份全公司默认的配置且可动态调整
  • RPC客户端项目可以自定义某些配置项且可动态调整
  1. 如果把以上两点要求去掉“动态调整”,那么做法很简单。在rpc-client.jar包里有一份配置文件,每次修改配置文件然后重新发一个版本的jar包即可。同理,客户端项目修改配置也是如此。
  2. 如果只支持客户端项目可动态调整配置。客户端项目可以在Apollo “application” Namespace上配置一些配置项。在初始化service的时候,从Apollo上读取配置即可。这样做的坏处就是,每个项目都要自定义一些key,不统一。
  3. 那么如何完美支持以上需求呢?答案就是结合使用Apollo的公共类型的Namespace和关联类型的Namespace。RPC团队在Apollo上维护一个叫“rpc-client”的公共Namespace,在“rpc-client” Namespace上配置默认的参数值。rpc-client.jar里的代码读取“rpc-client”Namespace的配置即可。如果需要调整默认的配置,只需要修改公共类型“rpc-client” Namespace的配置。如果客户端项目想要自定义或动态修改某些配置项,只需要在Apollo 自己项目下关联“rpc-client”,就能创建关联类型“rpc-client”的Namespace。然后在关联类型“rpc-client”的Namespace下修改配置项即可。这里有一点需要指出的,那就是rpc-client.jar是在应用容器里运行的,所以rpc-client获取到的“rpc-client” Namespace的配置是应用的关联类型的Namespace加上公共类型的Namespace。

# 例子 (opens new window)

如下图所示,有三个应用:应用A、应用B、应用C。

  • 应用A有两个私有类型的Namespace:application和NS-Private,以及一个关联类型的Namespace:NS-Public。

  • 应用B有一个私有类型的Namespace:application,以及一个公共类型的Namespace:NS-Public。

  • 应用C只有一个私有类型的Namespace:application

    Namespace例子

# 应用A获取Apollo配置
  //application 
  Config appConfig = ConfigService.getAppConfig();
  appConfig.getProperty("k1", null); // k1 = v11
  appConfig.getProperty("k2", null); // k2 = v21
  
  //NS-Private
  Config privateConfig = ConfigService.getConfig("NS-Private");
  privateConfig.getProperty("k1", null); // k1 = v3
  privateConfig.getProperty("k3", null); // k3 = v4
  
  //NS-Public,覆盖公共类型配置的情况,k4被覆盖
  Config publicConfig = ConfigService.getConfig("NS-Public");
  publicConfig.getProperty("k4", null); // k4 = v6 cover
  publicConfig.getProperty("k6", null); // k6 = v6
  publicConfig.getProperty("k7", null); // k7 = v7点击复制错误复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 应用B获取Apollo配置
  //application
  Config appConfig = ConfigService.getAppConfig();
  appConfig.getProperty("k1", null); // k1 = v12
  appConfig.getProperty("k2", null); // k2 = null
  appConfig.getProperty("k3", null); // k3 = v32
  
  //NS-Private,由于没有NS-Private Namespace 所以获取到default value
  Config privateConfig = ConfigService.getConfig("NS-Private");
  privateConfig.getProperty("k1", "default value"); 
  
  //NS-Public
  Config publicConfig = ConfigService.getConfig("NS-Public");
  publicConfig.getProperty("k4", null); // k4 = v5
  publicConfig.getProperty("k6", null); // k6 = v6
  publicConfig.getProperty("k7", null); // k7 = v7点击复制错误复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 应用C获取Apollo配置
  //application
  Config appConfig = ConfigService.getAppConfig();
  appConfig.getProperty("k1", null); // k1 = v12
  appConfig.getProperty("k2", null); // k2 = null
  appConfig.getProperty("k3", null); // k3 = v33
  
  //NS-Private,由于没有NS-Private Namespace 所以获取到default value
  Config privateConfig = ConfigService.getConfig("NS-Private");
  privateConfig.getProperty("k1", "default value"); 
  
  //NS-Public,公共类型的Namespace,任何项目都可以获取到
  Config publicConfig = ConfigService.getConfig("NS-Public");
  publicConfig.getProperty("k4", null); // k4 = v5
  publicConfig.getProperty("k6", null); // k6 = v6
  publicConfig.getProperty("k7", null); // k7 = v7点击复制错误复制成功
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ChangeListener

以上代码例子中可以看到,在客户端Namespace映射成一个Config对象。Namespace配置变更的监听器是注册在Config对象上。

所以在应用A中监听application的Namespace代码如下:

Config appConfig = ConfigService.getAppConfig();
appConfig.addChangeListener(new ConfigChangeListener() {
  public void onChange(ConfigChangeEvent changeEvent) {
    //do something
  }
})
1
2
3
4
5
6

在应用A中监听NS-Private的Namespace代码如下:

Config privateConfig = ConfigService.getConfig("NS-Private");
privateConfig.addChangeListener(new ConfigChangeListener() {
  public void onChange(ConfigChangeEvent changeEvent) {
    //do something
  }
})
1
2
3
4
5
6

在应用A、应用B、应用C中监听NS-Public的Namespace代码如下:

Config publicConfig = ConfigService.getConfig("NS-Public");
publicConfig.addChangeListener(new ConfigChangeListener() {
  public void onChange(ConfigChangeEvent changeEvent) {
    //do something
  }
})
1
2
3
4
5
6

# 调整ApolloConfigDB配置 (opens new window)

配置项统一存储在ApolloConfigDB.ServerConfig表中,需要注意每个环境的ApolloConfigDB.ServerConfig都需要单独配置,修改完一分钟实时生效。

# namespace.lock.switch - 一次发布只能有一个人修改开关,用于发布审核 (opens new window)

这是一个功能开关,如果配置为true的话,那么一次配置发布只能是一个人修改,另一个发布。

生产环境建议开启此选项

# 服务端配置说明

以下配置除了支持在数据库中配置以外,也支持通过-D参数、application.properties等配置,且-D参数、application.properties等优先级高于数据库中的配置

# 调整ApolloPortalDB配置

配置项统一存储在ApolloPortalDB.ServerConfig表中,也可以通过管理员工具 - 系统参数页面进行配置,无特殊说明则修改完一分钟实时生效。

# apollo.portal.envs - 可支持的环境列表

默认值是dev,如果portal需要管理多个环境的话,以逗号分隔即可(大小写不敏感),如:

DEV,FAT,UAT,PRO
1

名词解释:

DEV(Development environment)
开发环境,用于开发者调试使用

FAT(Feature Acceptance Test environment)
功能验收测试环境,用于软件测试者测试使用

UAT(User Acceptance Test environment)
用户验收测试环境,用于用户测试验收使用

PRO(Production environment)
生产环境
1
2
3
4
5
6
7
8
9
10
11

修改完需要重启生效。

注1:一套Portal可以管理多个环境,但是每个环境都需要独立部署一套Config Service、Admin Service和ApolloConfigDB,具体请参考:2.1.2 创建ApolloConfigDB (opens new window)3.2 调整ApolloConfigDB配置 (opens new window)2.2.1.1.2 配置数据库连接信息 (opens new window),另外如果是为已经运行了一段时间的Apollo配置中心增加环境,别忘了参考2.1.2.4 从别的环境导入ApolloConfigDB的项目数据 (opens new window)对新的环境做初始化。

注2:只在数据库添加环境是不起作用的,还需要为apollo-portal添加新增环境对应的meta server地址,具体参考:2.2.1.1.2.4 配置apollo-portal的meta service信息 (opens new window)。apollo-client在新的环境下使用时也需要做好相应的配置,具体参考:1.2.2 Apollo Meta Server (opens new window)

注3:如果希望添加自定义的环境名称,具体步骤可以参考Portal如何增加环境 (opens new window)

注4:1.1.0版本增加了系统信息页面(管理员工具 -> 系统信息),可以通过该页面检查配置是否正确

# 多环境部署

# 配置apollo-portal的meta service信息

Apollo Portal需要在不同的环境访问不同的meta service(apollo-configservice)地址,所以我们需要在配置中提供这些信息。默认情况下,meta service和config service是部署在同一个JVM进程,所以meta service的地址就是config service的地址。

对于1.6.0及以上版本,可以通过ApolloPortalDB.ServerConfig中的配置项来配置Meta Service地址,详见apollo.portal.meta.servers - 各环境Meta Service列表 (opens new window)

使用程序员专用编辑器(如vim,notepad++,sublime等)打开apollo-portal-x.x.x-github.zipconfig目录下的apollo-env.properties文件。

假设DEV的apollo-configservice未绑定域名,地址是192.168.1.5:8080,PRO的apollo-configservice绑定了域名apollo.chuanqu.ltd,那么可以如下修改各环境meta service服务地址,格式为${env}.meta=http://${config-service-url:port},如果某个环境不需要,也可以直接删除对应的配置项(如lpt.meta):

dev.meta=http://1.1.1.1:8080
fat.meta=http://apollo.fat.xxx.com
uat.meta=http://apollo.uat.xxx.com
pro.meta=http://apollo.xxx.com
1
2
3
4

除了通过apollo-env.properties方式配置meta service以外,apollo也支持在运行时指定meta service(优先级比apollo-env.properties高):

  1. 通过Java System Property

    ${env}_meta
    
    1
    • 可以通过Java的System Property ${env}_meta来指定
    • java -Ddev_meta=http://config-service-url -jar xxx.jar
    • 也可以通过程序指定,如System.setProperty("dev_meta", "http://config-service-url");
  2. 通过操作系统的System Environment

    ${ENV}_META
    
    1
    • DEV_META=http://config-service-url
    • 注意key为全大写,且中间是_分隔

注1: 为了实现meta service的高可用,推荐通过SLB(Software Load Balancer)做动态负载均衡

注2: meta service地址也可以填入IP,0.11.0版本之前只支持填入一个IP。从0.11.0版本开始支持填入以逗号分隔的多个地址(PR #1214 (opens new window)),如http://1.1.1.1:8080,http://2.2.2.2:8080,不过生产环境还是建议使用域名(走slb),因为机器扩容、缩容等都可能导致IP列表的变化。