spring-cloud-zuul 结合Apollo使用实战

  • 项目背景
  • Apollo配置
  • Apollo简介
  • Apollo操作
  • 本地应用配置
  • 应用部署K8s配置
  • 结语


项目背景

目前,我司的spring-cloud-zuul 服务采用传统的静态配置方法,针对不同环境写不同的yml配置文件,运行时无法动态修改,每次新增服务,都要在zuul中增加服务映射,重启服务。为了实现不需停服增加服务映射,引入apollo配置。

Apollo配置

Apollo简介

Apollo(阿波罗)是写成框架部门研发的开源配置管理中心,能够集中化管理应用各不同环境、不同集群的配置,配置修改后能够实时的推送到应用端,并且具备规范的权限、流程治理等特性。
Apollo支持4个维度管理Key-Value格式的配置:application(应用)、environment(环境)、cluster(集群)、namespace(命名空间)

Apollo操作

  1. 登录apollo
  2. SpringCloud整合Security整合oauth2 springcloud整合apollo_环境变量

  3. 填写项目信息
  4. SpringCloud整合Security整合oauth2 springcloud整合apollo_配置文件_02

  5. 新增命名空间
    创建项目后,apollo会默认在所有环境都创建一个application的命名空间,类型为properties;由于项目中使用的配置文件是yml类型的,方便直接拷贝配置,可以新建一个yml类型的命名空间。
    点击左下角的“添加Namespace”,新建一个名为“faceBootStrap.yml”的命名空间。创建完成后,每一个环境都会新增一个命名空间。
  6. SpringCloud整合Security整合oauth2 springcloud整合apollo_环境变量_03

  7. 配置编辑与发布
    选择需要配置的环境,这里以DEV为例,将本地bootstrap-dev.yml内容拷贝过来,完成后点击发布,即完成应用的dev环境配置。
  8. SpringCloud整合Security整合oauth2 springcloud整合apollo_配置文件_04

本地应用配置

  1. 配置apollo客户端依赖
<dependency>
			<groupId>com.ctrip.framework.apollo</groupId>
			<artifactId>apollo-client</artifactId>
			<version>${apollo-client-version}</version>
   </dependency>
  1. 主入口程序
@Configuration
@EnableApolloConfig("faceBootStrap.yml")
public class SsoWsGatewayApp extends WebSecurityConfigurerAdapter {
}
  1. 配置文件配置
    删除不同环境的配置文件,只需一个bootstrap.yml配置文件,内容如下:
app:
  id: face-recognize  #指定应用id
apollo:
  bootstrap:
    enabled: true
    namespaces: faceBootStrap.yml #指定命名空间
    eagerLoad:
      enabled: false
  1. 动态路由
    创建zuul路由规则刷新类ZuulProxyRefresher,具体代码如下。实现在apollo配置中增加新的服务映射,无需重启zuul。
@Component
public class ZuulProxyRefresher implements ApplicationContextAware {
	private ApplicationContext applicationContext;

	@Autowired
	private RouteLocator routeLocator;

	@ApolloConfigChangeListener(value = "faceBootStrap.yml")
	public void onChange(ConfigChangeEvent changeEvent) {
		boolean zuulProxyChanged = false;
		for (String changedKey : changeEvent.changedKeys()) {
			if (changedKey.startsWith("zuul.")) {
				zuulProxyChanged = true;
				break;
			}
		}
		if (zuulProxyChanged) {
			refreshZuulProxy(changeEvent);
		}
	}

	private void refreshZuulProxy(ConfigChangeEvent changeEvent) {
		this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
		this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator));
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
}
  1. 本地环境变量配置
    本地启动时,配置两个环境变量,JAVA_TOOL_OPTIONS 配置apollo的configService的url。 env 指定使用apollo的DEV环境上的配置。

    通过apollo配置和本地应用配置,完成了zuul服务在apollo的配置,启动相关服务,可以正常访问,在apollo配置上动态新增服务也可以直接访问新服务。

应用部署K8s配置

由于apollo的环境变量env在K8s的上被占用,导致直接采用env做apollo的环境变量部署到k8s会出错。解决方法如下,自定义环境变量和配置加载类,。

  1. K8s环境变量配置
  2. K8s自定义配置加载类
public class MyEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
 
	public static final int DEFAULT_ORDER = ConfigFileApplicationListener.DEFAULT_ORDER + 1;

	private int order = DEFAULT_ORDER;

	public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		String property = environment.getProperty("apolloenv");
		System.setProperty("env", property);
	}

	@Override
	public int getOrder() {
		return order;
	}
}
  1. K8s环境变量配置
env: 
- name: apolloenv
  value: DEV
- name: JAVA_TOOL_OPTIONS
  value: -Dapollo.configService=https://apollodev.utyun.com

结语

通过以上步骤,通过zuul与apollo的结合,实现zuul服务配置的动态修改。