一文搞定:SpringBoot 集成 Apollo 配置中心

3,581 阅读10分钟

目录

. 一、基本概念

. 1、背景

. 2、简介

. 3、特点

. 4、基础模型

. 5、架构模块

. 6、Apollo 核心概念

. 7、Apollo 和Spring cloud Config对比

. 二、Apollo 配置中心创建项目与配置

. 1、登录 Apollo

. 2、修改与增加部门数据

. 3、创建一个项目

. 4、创建一个配置参数

. 三、创建 Apollo 客户端测试项目

. 1、Mavne 添加 Apollo 依赖

. 2、配置文件添加参数

. 3、创建测试 Controller 类

. 4、创建启动类

. 5、配置一个常量参数类

. 6、客户端监听配置变化

. 7、跳过Apollo Meta Server服务发现

目录

系统环境

  • SpringBoot 版本:2.2.6.RELEASE
  • apollo-client 版本:1.5.0

参考地址

一、基本概念

由于 Apollo 概念比较多,刚开始使用比较复杂,最好先过一遍概念再动手实践尝试使用。

1、背景

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

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

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

2、简介

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

3、特点

  • 统一管理不通环境、不同集群的配置
  • 配置修改实时生效
  • 版本发布管理
  • 灰度发布
  • 权限管理、发布审核、操作审计
  • 部署简单

4、基础模型

如下即是 Apollo 的基础模型:

  • 用户在配置中心对配置进行修改并发布
  • 配置中心通知Apollo客户端有配置更新
  • Apollo客户端从配置中心拉取最新的配置、更新本地配置并通知到应用

img

5、架构模块

下图是Apollo架构模块的概览,详细说明可以参考Apollo配置中心架构剖析

overall-architecture

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

6、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的初始数据库连接数

7、Apollo 和Spring cloud Config对比

img

结论: Apollo相对于Spring Cloud Config的生态支持更广,在配置管理流程上做的更好。

二、普通应用接入指南

1.1 创建项目

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

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

create-app-entry

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

create-app

Apollo没有提供新增部门的选项,修改或者添加部门只能通过修改数据库实现,这里打开 ApolloPortalDB 对应的数据库中的表 ServerConfig 修改 keyorganizationsvalue 的 json 数据,改成自己对于的部门信息。

img

  1. 点击提交

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

app-created

1.2 项目权限分配

1.2.1 项目管理员权限

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

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

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

  1. 点击页面左侧的“管理项目”
    • app-permission-entry
  2. 搜索需要添加的成员并点击添加
    • app-permission-search-user
    • app-permission-user-added

1.2.1 配置编辑、发布权限

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

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

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

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

1.3 添加配置项

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

1.3.1 通过表格模式添加配置

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

1.3.2 通过文本模式编辑

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

  1. 切换到文本编辑模式
    text-mode-config-overview
  2. 点击右侧的修改配置按钮
    text-mode-config-entry
  3. 输入配置项,并点击提交修改
    text-mode-config-submit

1.4 发布配置

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

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

  1. 点击“发布按钮”
    publish-entry
  2. 填写发布相关信息,点击发布
    publish-detail

更多配置信息参考Apollo使用指南

三、创建 Apollo 客户端测试项目

这里创建一个 SpringBoot 项目,引入 Apollo 客户端来来实现与 Apollo 配置中心服务端交互。

1、Maven 添加 Apollo 依赖

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>rock-apollo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>rock-apollo</name>
  <description>Demo project for Spring Boot</description>

  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.2.6.RELEASE</spring-boot.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>com.ctrip.framework.apollo</groupId>
      <artifactId>apollo-client</artifactId>
      <version>1.5.0</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.10</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
        <exclusion>
          <groupId>org.junit.vintage</groupId>
          <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
  </dependencies>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <version>2.2.6.RELEASE</version>
      </plugin>
    </plugins>
  </build>

</project>

2、配置文件添加参数

在/resources下添加META-INF文件夹以及在META-INF下新增app.properties文件,参数如下:

  • app.id : Apollo配置的AppId唯一标识
  • applo.meta: Apollo 配置中心地址
app.id=85648775
apollo.meta=http://localhost:8080

在 application.yml 配置文件中添加下面参数,这里简单介绍下 Apollo 参数作用:

  • apollo.cluster: 指定使用某个集群下的配置。
  • apollo.bootstrap.enabled: 是否开启 Apollo。
  • apollo.bootstrap.namespaces : 指定使用哪个 Namespace 的配置,默认 application。
  • apollo.bootstrap.eagerLoad.enabled : 将 Apollo 加载提到初始化日志系统之前,如果设置为 false,那么将打印出 Apollo 的日志信息,但是由于打印 Apollo 日志信息需要日志先启动,启动后无法对日志配置进行修改,所以 Apollo 不能管理应用的日志配置,如果设置为 true,那么 Apollo 可以管理日志的配置,但是不能打印出 Apollo 的日志信息。
server:
  port: 8888
spring:
  application:
    name: rock-apollo
#Apollo配置
apollo:
  cluster: default                        #指定使用哪个集群的配置
  bootstrap:
    enabled: true                         #是否开启Apollo
    namespace: application.notice         #设置namespace
    eagerLoad:
      enabled: false                      #将Apollo 加载提到初始化日志系统之前

3、创建测试 Controller 类

 package com.example.rockapollo.controller;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigService;
import com.example.rockapollo.config.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ApolloController {

  @Value("${name:test}")
  private String name;

  @Autowired
  private Constant constant;

  @GetMapping("/getName")
  public String getName(){
    return name;
  }

  @GetMapping("/config")
  public String config(){
    return ConfigService.getAppConfig().getProperty("name",null);
  }

  @GetMapping("/getNoticeName")
  public String getNoticeName(){
    Config notice = ConfigService.getConfig("notice");
    return notice.getProperty("address",null);
  }

  @GetMapping("/constant")
  public Constant getConstant(){
    return constant;
  }

}

4、创建启动类

package com.example.rockapollo;

import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableApolloConfig
public class RockApolloApplication {

  public static void main(String[] args) {
    SpringApplication.run(RockApolloApplication.class, args);
  }

}

5、配置一个常量参数类

package com.example.rockapollo.config;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Data
@Component
public class Constant {

  @Value("${name}")
  private String name;

  @Value("${age}")
  private int age;

  @Value("${address}")
  private String address;
}

6、客户端监听配置变化

在某些场景下,应用还需要在配置变化时获得通知,比如数据库连接的切换等,所以Apollo还提供了监听配置变化的功能,Java示例如下:

package com.example.rockapollo.listener;

import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.model.ConfigChange;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class ApolloChangeListenerImpl implements ConfigChangeListener {

  /**
   * .监听Apollo 配置变化
   * @ApolloConfigChangeListener 监听指定namespace的配置
   * @param configChangeEvent
   */
  @Override
  @ApolloConfigChangeListener("notice")
  public void onChange(ConfigChangeEvent configChangeEvent) {
    for (String changedKey : configChangeEvent.changedKeys()) {
      ConfigChange change = configChangeEvent.getChange(changedKey);
      log.warn("found change - key:{},oldValue:{},newValue:{},changeType:{}",
          change.getPropertyName(), change.getOldValue(), change.getNewValue(),change.getChangeType());
    }
  }
}

7、跳过Apollo Meta Server服务发现

一般情况下都建议使用Apollo的Meta Server机制来实现Config Service的服务发现,从而可以实现Config Service的高可用。不过apollo-client也支持跳过Meta Server服务发现,主要用于以下场景:

Config Service部署在公有云上,注册到Meta Server的是内网地址,本地开发环境无法直接连接

Config Service部署在docker环境中,注册到Meta Server的是docker内网地址,本地开发环境无法直接连接

Config Service部署在kubernetes中,希望使用kubernetes自带的服务发现能力(Service)

针对以上场景,可以通过直接指定Config Service地址的方式来跳过Meta Server服务发现,按照优先级从高到低分别为:

  1. 通过Java System Property

    apollo.configService
    
    • 可以通过Java的System Property apollo.configService来指定

    • 在Java程序启动脚本中,可以指定

      -Dapollo.configService=http://config-service-url:port
      
      • 如果是运行jar文件,需要注意格式是java -Dapollo.configService=http://config-service-url:port -jar xxx.jar
    • 也可以通过程序指定,如System.setProperty("apollo.configService", "http://config-service-url:port");

    Intellij IDEA 内可以通过VM配置启动

  2. 通过操作系统的System Environment

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

    server.properties
    

    配置文件

    • 可以在server.properties配置文件中指定apollo.configService=http://config-service-url:port
    • 对于Mac/Linux,文件位置为/opt/settings/server.properties
    • 对于Windows,文件位置为C:\opt\settings\server.properties