Spring Cloud(Kilburn 2022.0.2版本)系列教程(六) 分布式配置中心(Apollo)
一、安装说明
安装Apollo必须有Java环境。
- Apollo服务端:1.8+
- Apollo客户端:1.8+
#安装jdk8很简单,就一行命令即可
apt install openjdk-8-jdk
#查看java版本
java -version
安装Apollo必须有数据库,MySQL、H2内存数据库、H2文件数据库三者选其一。为了更好的安全性与性能,建议使用MySQL。
#我们是在Ubuntu24.04上安装的MySQL8,先获取deb安装包
wget https://dev.mysql.com/get/mysql-apt-config_0.8.17-1_all.deb
#安装
sudo dpkg -i mysql-apt-config_0.8.17-1_all.deb
#选择 ubuntu focal
#选择 MySQL Server & Cluster (Currently selected: mysql-8.0)
#安装
apt-get install mysql-server
#查看状态
systemctl status mysql
#登录MySQL
mysql -uroot -p
#修改root密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY '123456';
#如果修改不成功,可以执行下面这一句
create user 'root'@'%' identified by '123456';
#授权所有操作权限给root
grant all privileges on *.* to 'root'@'%';
#创建一个hep用户,并授权所有操作权限
create user 'hep'@'%' identified by '123456';
grant all privileges on *.* to 'hep'@'%';
#刷新权限
flush privileges;
#退出
exit;
#使得mysql可以远程登陆
vim /etc/mysql/mysql.conf.d/mysqld.cnf
#注释掉这一行
#bind-address = 127.0.0.1
#重启mysql
service mysql restart;
#开放3306端口
ufw allow 3306
#查看3306端口是否被监听
netstat -anp | grep mysql
下面即可用navicat类似的软件连接并进行创建数据库了,我们创建了两个数据库ApolloConfigDB
和ApolloPortalDB
。
二、下载apollo-quick-start
下载地址:https://github.com/apolloconfig/apollo-quick-start
-
apollo 服务端进程需要分别使用8070, 8080, 8090端口,请确保这3个端口当前没有被使用。
ufw allow 8070 ufw allow 8080 ufw allow 8090
-
脚本中的
SPRING_PROFILES_ACTIVE
环境变量中的github
是必须的 profile,database-discovery
指定使用数据库服务发现,auth
是 portal 提供简单认证的 profile,不需要认证或者使用其它认证方式时可以去掉
三、使用 mysql 数据库,自动初始化
脚本环境变量中的 your-mysql-server:3306
需要替换为实际的 mysql 服务器地址和端口,ApolloConfigDB
和 ApolloPortalDB
需要替换为实际的数据库名称,脚本环境变量中的 "apollo-username"
和 "apollo-password"
需要填写实际的用户名和密码。
3.1 首次启动
首次启动使用 SPRING_SQL_INIT_MODE="always"
环境变量来进行初始化
export SPRING_PROFILES_ACTIVE="github,database-discovery,auth"
# config db
export SPRING_SQL_CONFIG_INIT_MODE="always"
export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://192.168.31.111:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8"
export SPRING_CONFIG_DATASOURCE_USERNAME="hep"
export SPRING_CONFIG_DATASOURCE_PASSWORD="123456"
# portal db
export SPRING_SQL_PORTAL_INIT_MODE="always"
export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://192.168.31.111:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8"
export SPRING_PORTAL_DATASOURCE_USERNAME="hep"
export SPRING_PORTAL_DATASOURCE_PASSWORD="123456"
java -jar apollo-all-in-one.jar
3.2 后续启动
后续启动去掉 SPRING_SQL_CONFIG_INIT_MODE
和 SPRING_SQL_PORTAL_INIT_MODE
环境变量来避免重复初始化
export SPRING_PROFILES_ACTIVE="github,database-discovery,auth"
# config db
unset SPRING_SQL_CONFIG_INIT_MODE
export SPRING_CONFIG_DATASOURCE_URL="jdbc:mysql://192.168.31.111:3306/ApolloConfigDB?useUnicode=true&characterEncoding=UTF8"
export SPRING_CONFIG_DATASOURCE_USERNAME="hep"
export SPRING_CONFIG_DATASOURCE_PASSWORD="123456"
# portal db
unset SPRING_SQL_PORTAL_INIT_MODE
export SPRING_PORTAL_DATASOURCE_URL="jdbc:mysql://192.168.31.111:3306/ApolloPortalDB?useUnicode=true&characterEncoding=UTF8"
export SPRING_PORTAL_DATASOURCE_USERNAME="hep"
export SPRING_PORTAL_DATASOURCE_PASSWORD="123456"
#你可能并不想看后台输出的代码,也不想没法敲其他的命令行了,下面一条命令让Apollo后台运行
nohup java -jar /usr/software/apollo-quick-start-master/apollo-all-in-one.jar > /usr/software/apollo-quick-start-master/apollo.log 2>&1 &
并且,我把上面的内容写入了自启动文件/root/.bashrc的最后面,这样开机就可以自启动这条命令,这样Apollo开机就自动运行了,再也不用我们进入到特定目录,还要执行java -jar的命令了。
#后台运行Apollo命令
nohup java -jar /usr/software/apollo-quick-start-master/apollo-all-in-one.jar > /usr/software/apollo-quick-start-master/apollo.log 2>&1 &
四、使用Apollo配置中心
4.1 初始化配置
我们把阿波罗安装到了一台Ubuntu24.04的机器上了,其IP地址为192.168.31.111
,打开http://192.168.31.111:8070
,输入用户名apollo密码admin后登录。
五、分布式部署
5.1 架构配置与设计
我们准备了6台机器,来部署Apollo配置中心,开发环境配置一台,测试环境配置两台,生产环境配置两台,portal配置一台,一共六台,当然这些并没有把mysql数据库算作其中,数据库是之前就搭建好的,开发、测试、生产都有。
环境 | 主机 | IP |
---|---|---|
开发 | hep-apollo-server-admin-config-dev | 192.168.31.51 |
测试 | hep-apollo-server-admin-config-test-01 | 192.168.31.52 |
测试 | hep-apollo-server-admin-config-test-02 | 192.168.31.53 |
生产 | hep-apollo-server-admin-config-prd-01 | 192.168.31.54 |
生产 | hep-apollo-server-admin-config-prd-02 | 192.168.31.55 |
生产 | hep-apollo-server-portal-prd | 192.168.31.56 |
总体的架构图如下。
5.2 数据库脚本与Apollo安装包下载
Apollo目前支持以下环境:
- DEV开发环境
- FAT测试环境,相当于alpha环境(功能测试)
- UAT集成环境,相当于beta环境(回归测试)
- PRO生产环境
Apollo服务端共需要两个数据库:ApolloPortalDB
和ApolloConfigDB
,ApolloPortalDB
只需要在生产环境部署一个即可,而ApolloConfigDB
需要在每个环境部署一套,如fat、uat和pro分别部署3套ApolloConfigDB
。我们这里使用的是开发dev、测试test、生产prd一共三个环境,各配置了一套ApolloConfigDB
,只配置了生产一套ApolloPortalDB
。
通过各种MySQL客户端导入apolloportaldb.sql即可。
#apolloportaldb.sql下载地址:
https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloportaldb.sql
#apolloconfigdb.sql下载地址:
https://github.com/apolloconfig/apollo/blob/master/scripts/sql/profiles/mysql-default/apolloconfigdb.sql
获取apollo-configservice
、apollo-adminservice
、apollo-portal
安装包,从GitHub Release页面下载最新版本的apollo-configservice-x.x.x-github.zip
、apollo-adminservice-x.x.x-github.zip
和apollo-portal-x.x.x-github.zip
即可。
5.3 开发环境
把下载好的apollo-configservice-2.3.0-github.zip
、apollo-adminservice-2.3.0-github.zip
两个文件上传到hep-apollo-server-admin-config-dev(192.168.31.51)
这台机器,并解压缩,在cofig和admin两个文件夹下,分别有config和scripts两个文件夹。
config
目录下的application-github.properties
文件中有mysql数据库的配置项,把数据库地址、用户名、密码改成对应的开发环境的,注意用户名和密码后面不要有空格。
spring.datasource.url = jdbc:mysql://192.168.31.79:3306/ApolloConfigDB?characterEncoding=utf8
spring.datasource.username = hepadmin
spring.datasource.password = admin123
scripts下有startup.sh和shutdown.sh两个文件,分别对应着启动和关闭的脚本。使用下面命令启动admin和config服务,当然也要放行一下端口号,这三个端口号是有用于通信的。
#开放端口
ufw allow 8070
ufw allow 8080
ufw allow 8090
cd apollo-adminservice-2.3.0/scripts
nohup ./startup.sh &
cd apollo-configservice-2.3.0/scripts
nohup ./startup.sh &
5.4 测试环境
把下载好的apollo-configservice-2.3.0-github.zip
、apollo-adminservice-2.3.0-github.zip
两个文件都上传到hep-apollo-server-admin-config-test-01(192.168.31.52)
和hep-apollo-server-admin-config-test-02(192.168.31.53)
这两台机器,并解压缩,在cofig和admin两个文件夹下,分别有config和scripts两个文件夹。
config
目录下的application-github.properties
文件有mysql数据库的配置,修改成测试环境的数据库ApolloConfigDB
的。两台机器都要做。
spring.datasource.url = jdbc:mysql://192.168.31.4:6446/ApolloConfigDB?characterEncoding=utf8
spring.datasource.username = hepadmin
spring.datasource.password = admin123
用Navicat连接到测试环境数据库ApolloConfigDB
,把ServerConfig
表中的eureka.service.url
字段修改成http://192.168.31.52:8080/eureka/,http://192.168.31.53:8080/eureka/
。eureka.service.url
字段用于存储 Eureka 服务注册中心的地址,这意味着 Apollo 配置中心自身作为一个微服务,可能会将自己的服务信息注册到 Eureka 服务注册中心,以便其他服务(如 Apollo 客户端)能够通过 Eureka 发现 Apollo 配置中心的位置,从而获取配置信息。
scripts下有startup.sh和shutdown.sh两个文件,分别对应着启动和关闭的脚本。使用下面命令启动admin和config服务,两台机器都要做。
#开放端口
ufw allow 8070
ufw allow 8080
ufw allow 8090
cd apollo-configservice-2.3.0/scripts
nohup ./startup.sh &
cd apollo-adminservice-2.3.0/scripts
nohup ./startup.sh &
5.5 生产环境
把下载好的apollo-configservice-2.3.0-github.zip
、apollo-adminservice-2.3.0-github.zip
两个文件上传到hep-apollo-server-admin-config-prd-01(192.168.31.54)
和hep-apollo-server-admin-config-prd-02(192.168.31.55)
这两台机器,并解压缩,在cofig和admin两个文件夹下,分别有config和scripts两个文件夹。
config
目录下的application-github.properties
文件有mysql数据库的配置,修改成生产环境的数据库ApolloConfigDB
的。两台机器都要做。
spring.datasource.url = jdbc:mysql://192.168.31.14:6446/ApolloConfigDB?characterEncoding=utf8
spring.datasource.username = hepadmin
spring.datasource.password = admin123
用Navicat连接到生产环境数据库ApolloConfigDB
,把ServerConfig
表中的eureka.service.url
字段修改成http://192.168.31.54:8080/eureka/,http://192.168.31.55:8080/eureka/
。eureka.service.url
字段用于存储 Eureka 服务注册中心的地址,这意味着 Apollo 配置中心自身作为一个微服务,可能会将自己的服务信息注册到 Eureka 服务注册中心,以便其他服务(如 Apollo 客户端)能够通过 Eureka 发现 Apollo 配置中心的位置,从而获取配置信息。
scripts下有startup.sh和shutdown.sh两个文件,分别对应着启动和关闭的脚本。使用下面命令启动admin和config服务,两台机器都要做。
#开放端口
ufw allow 8070
ufw allow 8080
ufw allow 8090
cd apollo-configservice-2.3.0/scripts
nohup ./startup.sh &
cd apollo-adminservice-2.3.0/scripts
nohup ./startup.sh &
把下载好的apollo-portal-2.3.0-github.zip
文件上传到hep-apollo-server-portal-prd(192.168.31.56)
,并解压缩,在cofig和admin两个文件夹下,分别有config和scripts两个文件夹。
config
目录下的application-github.properties
文件有mysql数据库的配置,修改成生产环境的数据库ApolloPortalDB
的。
spring.datasource.url = jdbc:mysql://192.168.31.14:6446/ApolloPortalDB?characterEncoding=utf8
spring.datasource.username = hepadmin
spring.datasource.password = admin123
修改apollo-env.properties配置文件,保留了开发、测试、生产三个环境,并且对应meta地址就是上面配置的Admin服务地址,多个地址之间用英文逗号隔开。
dev.meta=http://192.168.31.51:8080
test.meta=http://192.168.31.52:8080,http://192.168.31.53:8080
#uat.meta=http://fill-in-uat-meta-server:8080
#lpt.meta=${lpt_meta}
prd.meta=http://192.168.31.54:8080,http://192.168.31.55:8080
Apollo Portal
需要在不同的环境访问不同的meta service(apollo-configservice)
地址,所以我们需要在配置中提供这些信息。为了实现meta service的高可用,推荐通过SLB(Software Load Balancer)
做动态负载均衡。meta service地址也可以填入IP,0.11.0版本之前只支持填入一个IP。从0.11.0版本开始支持填入以逗号分隔的多个地址,如http://192.168.31.52:8080,http://192.168.31.53:8080
。
用Navicat连接到生产环境数据库ApolloPortalDB
,把ServerConfig
表中的apollo.portal.meta.servers
修改成
{
"DEV":"http://192.168.31.51:8080",
"TEST":"http://192.168.31.52:8080,http://192.168.31.53:8080",
"PRD":"http://192.168.31.54:8080,http://192.168.31.55:8080"
}
把apollo.portal.envs
修改成DEV,TEST,PRD
,把organizations
修改成[{"orgId":"hep01","orgName":"沪尓浦开发一部"},{"orgId":"hep02","orgName":"沪尓浦开发二部"}]
,把configView.memberOnly.envs
修改成DEV,TEST,PRD
。
最后启动portal
cd apollo-portal-2.3.0/scripts
nohup ./startup.sh &
当然后面那几项也可以启动portal之后,通过操作界面进行修改,都可。
六、牛刀小试
想必搞微服务的小伙伴都看腻了网上的Apollo配置中心的第一个ConfigService.getConfig
样例,这种演示性的Demo确实让人很反感,除了演示没啥用,我们今天就来点不一样的。前面的教程里有部署Eureka到三台服务器上,从而形成了一个注册中心的集群,测试环境和生产环境各有三台机器,不熟悉的可以去瞄一眼前面的教程哈,我们每次打个jar包放到服务器上,每台机器上Eureka的注册地址都不一样,而每次都手动去改然后再打包有点繁琐,我们今天就用一个Apollo进行这个eureka.client.serviceUrl.defaultZone
的配置,并且实现实时生效,相比这个好玩的功能很多小伙伴在心里乐开了花,确实很实用的哈。
首先创建一个应用,id为hep-eureka-server
,并且上面我们也配置好了开发、测试、生产的环境,因为开发环境就给了一台Eureka,所以就不建集群了,测试和生产各有三台机器,所以创建了三个集群,分别取名01、02、03,并且增加了一个配置项eureka.client.serviceUrl.defaultZone
。
首先在eurekaServer
的项目中增加Apollo客户端的依赖。
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
Spring Boot
启动类,添加 @EnableApolloConfig
@SpringBootApplication
@EnableEurekaServer
@EnableApolloConfig
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
增加一个EurekaConfigFromApollo
配置项,这个是可以动态监测到Eureka变化,立即生效,不用重启Eureka机器。
package cc.huerpu.eurekaserver.security;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class EurekaConfigFromApollo {
private static final Logger logger = LoggerFactory.getLogger(EurekaConfigFromApollo.class);
@ApolloConfig
private Config config;
private static final String EUREKA_CLIENT_SERVICE_URL_DEFAULT_ZONE_KEY = "eureka.client.serviceUrl.defaultZone";
@Autowired
private org.springframework.cloud.netflix.eureka.EurekaClientConfigBean eurekaClientConfigBean;
@PostConstruct
public void init() {
updateEurekaServiceUrl();
}
@ApolloConfigChangeListener
private void onChange(ConfigChangeEvent changeEvent) {
ConfigChange change = changeEvent.getChange(EUREKA_CLIENT_SERVICE_URL_DEFAULT_ZONE_KEY);
if (change!= null) {
updateEurekaServiceUrl();
}
}
private void updateEurekaServiceUrl() {
String eurekaServiceUrl = config.getProperty(EUREKA_CLIENT_SERVICE_URL_DEFAULT_ZONE_KEY, "");
if (!StringUtils.isEmpty(eurekaServiceUrl)) {
Map<String, String> defaultZoneUrls = new HashMap<>();
defaultZoneUrls.put("defaultZone", eurekaServiceUrl);
eurekaClientConfigBean.setServiceUrl(defaultZoneUrls);
logger.trace("eurekaServiceUrl:" + eurekaServiceUrl);
} else {
logger.error("Failed to get the value of 'eureka.client.serviceUrl.defaultZone' from Apollo configuration.");
}
}
}
开发环境application.yml增加下面配置,app.id就是Apollo上面创建的应用ID,全局唯一,Apollo.meta就是上面配置的Apollo Config Service
对应的地址,每个环境的都对应好即可。
#注释掉eureka.client.serviceUrl.defaultZone,并增加下面配置
app:
id: hep-eureka-server
apollo:
meta: http://192.168.31.51:8080
bootstrap:
enabled: true
测试环境application-test.yml
#注释掉eureka.client.serviceUrl.defaultZone,并增加下面配置
app:
id: hep-eureka-server
apollo:
meta: http://192.168.31.52:8080,http://192.168.31.53:8080
bootstrap:
enabled: true
生产环境application-prd.yml
#注释掉eureka.client.serviceUrl.defaultZone,并增加下面配置
app:
id: hep-eureka-server
apollo:
meta: http://192.168.31.54:8080,http://192.168.31.55:8080
bootstrap:
enabled: true
在机器上面我们写了一个脚本让它开机自启动Eureka服务,因为测试环境和生产环境配置了集群,所以在脚本中指定一下export APOLLO_CLUSTER=01
、export APOLLO_CLUSTER=02
、export APOLLO_CLUSTER=03
属于哪一个集群就行了,就这么简单。
vim /etc/rc.local
#!/bin/bash
export APOLLO_CLUSTER=01
nohup java -jar /usr/software/eurekaServer-auth-prd-03.jar > /usr/software/log.log 2>&1 &
exit 0
chmod +x /etc/rc.local
启动之后可以看到每个集群对应的机器,每个机器的配置项也不同,是相互注册的配置项
-
192.168.31.34
向192.168.31.35
、192.168.31.36
注册 -
192.168.31.35
向192.168.31.34
、192.168.31.36
注册 -
192.168.31.36
向192.168.31.34
、192.168.31.35
注册
生产环境也是相互注册的配置项
-
192.168.31.31
向192.168.31.32
、192.168.31.33
注册 -
192.168.31.32
向192.168.31.31
、192.168.31.33
注册 -
192.168.31.33
向192.168.31.31
、192.168.31.32
注册
现在当你修改了这个配置项,并且发布了,eureka就会立即生效,再也不用去手动配置再打包了,可以愉快地玩耍了。
七、最后
按照Apollo的文档顺序启动服务,一般先启动数据库、Eureka(如果有)、Apollo Config Service
、Apollo Admin Service
,最后启动Apollo Portal
。
也可以添加几个用户,从而进行各种权限的管理工作。
Reference:
携程Apollo官网:https://www.apolloconfig.com/#/
Apollo quick start:https://github.com/apolloconfig/apollo-quick-start
一步到位讲解ubuntu安装MySql:https://blog.csdn.net/zhiqingcn/article/details/140794841
Apollo 配置中心详细教程:https://xie.infoq.cn/article/eb8b8c2d63f86ac26fae23692
Apollo分布式集群部署:https://www.cnblogs.com/jluo/p/16985091.html
Apollo配置中心解惑:关于一个portal管理多个环境,要求环境相互之间不影响,独立:https://www.cnblogs.com/xiaohouzai/p/8923463.html
2023年最新版Apollo保姆级使用手册(超级详尽版本):https://www.cnblogs.com/liuyangfirst/p/17726702.html