摘要: 原创出处 http://www.iocoder.cn/Apollo/portal-publish-namespace-branch-to-master/ 「芋道源码」欢迎转载,保留摘要,谢谢!

  • 1. 概述
  • 2. Portal 侧
    • 2.1 NamespaceBranchController
    • 2.2 NamespaceBranchService
    • 2.3 ReleaseAPI
  • 3. Admin Service 侧
    • 3.1 ReleaseController
    • 3.2 ReleaseService
    • 3.3  NamespaceBranchService
    • 3.4 ClusterService
  • 666. 彩蛋

1. 概述

老艿艿:本系列假定胖友已经阅读过 《Apollo 官方 wiki 文档》  ,特别是 《Apollo 官方 wiki 文档 —— 灰度发布使用指南》。

本文接 《Apollo 源码解析 —— Portal 灰度发布》 ,分享灰度全量发布。

我们先来看看官方文档对灰度全量发布的使用指南,来理解下它的定义和流程。

如果灰度的配置测试下来比较理想,符合预期,那么就可以操作【全量发布】。

全量发布的效果是:

  1. 灰度版本的配置会合并回主版本,在这个例子中,就是主版本的 timeout 会被更新成 3000
  2. 主版本的配置会自动进行一次发布
  3. 在全量发布页面,可以选择是否保留当前灰度版本,默认为不保留。

我选择了不保留灰度版本,所以发布完的效果就是主版本的配置更新、灰度版本删除。点击主版本的实例列表,可以看到10.32.21.22和10.32.21.19都使用了主版本最新的配置。

灰度发布2

灰度全量发布,和 《Apollo 源码解析 —— Portal 发布配置》 ,差异点在于,多了一步配置合并,所以代码实现上,有很多相似度。整体系统流程如下:

流程

2. Portal 侧

2.1 NamespaceBranchController

在 apollo-portal 项目中,com.ctrip.framework.apollo.portal.controller.NamespaceBranchController ,提供 Namespace 分支API 。

#merge(...) 方法,灰度全量发布,合并子 Namespace 变更的配置 Map 到父 Namespace ,并进行一次 Release 。代码如下:

  1@PreAuthorize(value = "@permissionValidator.hasReleaseNamespacePermission(#appId, #namespaceName)")
  2@RequestMapping(value = "/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge", method = RequestMethod.POST)
  3public ReleaseDTO merge(@PathVariable String appId, @PathVariable String env,
  4:                         @PathVariable String clusterName, @PathVariable String namespaceName,
  5:                         @PathVariable String branchName, @RequestParam(value = "deleteBranch", defaultValue = "true")
 boolean deleteBranch,
  6:                         @RequestBody NamespaceReleaseModel model) 
{
  7:     // 若是紧急发布,但是当前环境未允许该操作,抛出 BadRequestException 异常
  8:     if (model.isEmergencyPublish() && !portalConfig.isEmergencyPublishAllowed(Env.fromString(env))) {
  9:         throw new BadRequestException(String.format("Env: %s is not supported emergency publish now", env));
 10:     }
 11:     // 合并子 Namespace 变更的配置 Map 到父 Namespace ,并进行一次 Release
 12:     ReleaseDTO createdRelease = namespaceBranchService.merge(appId, Env.valueOf(env), clusterName, namespaceName, branchName,
 13:             model.getReleaseTitle(), model.getReleaseComment(),
 14:             model.isEmergencyPublish(), deleteBranch);
 15
 16:     // 创建 ConfigPublishEvent 对象
 17:     ConfigPublishEvent event = ConfigPublishEvent.instance();
 18:     event.withAppId(appId)
 19:             .withCluster(clusterName)
 20:             .withNamespace(namespaceName)
 21:             .withReleaseId(createdRelease.getId())
 22:             .setMergeEvent(true)
 23:             .setEnv(Env.valueOf(env));
 24:     // 发布 ConfigPublishEvent 事件
 25:     publisher.publishEvent(event);
 26:     return createdRelease;
 27: }
  • POST /apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge 接口,Request Body 传递 JSON 对象。
  • @PreAuthorize(...) 注解,调用 PermissionValidator#hasReleaseNamespacePermissio(appId, namespaceName) 方法,校验是否有发布配置的权限。后续文章,详细分享。
  • 第 7 至 10 行:校验若是紧急发布,但是当前环境未允许该操作,抛出 BadRequestException 异常。
  • 第 11 至 14 行:调用 NamespaceBranchService#merge(...) 方法,合并子 Namespace 变更的配置 Map 到父 Namespace ,并进行一次 Release 。
  • 第 16 至 25 行:创建 ConfigPublishEvent 对象,并调用 ApplicationEventPublisher#publishEvent(event) 方法,发布 ConfigPublishEvent 事件。这部分,我们在后续文章分享。
  • 第 26 行:返回 ReleaseDTO 对象。

2.2 NamespaceBranchService

在 apollo-portal 项目中,com.ctrip.framework.apollo.portal.service.NamespaceBranchService ,提供 Namespace 分支Service 逻辑。

#merge(...) 方法,调用 Admin Service API ,合并子 Namespace 变更的配置 Map 到父 Namespace ,并进行一次 Release 。代码如下:

  1@Autowired
  2private AdminServiceAPI.NamespaceBranchAPI namespaceBranchAPI;
  3@Autowired
  4private ReleaseService releaseService;
  5
  6public ReleaseDTO merge(String appId, Env env, String clusterName, String namespaceName,
  7:                         String branchName, String title, String comment,
  8:                         boolean isEmergencyPublish, boolean deleteBranch)
 
{
  9:     // 计算变化的 Item 集合
 10:     ItemChangeSets changeSets = calculateBranchChangeSet(appId, env, clusterName, namespaceName, branchName);
 11:     // 合并子 Namespace 变更的配置 Map 到父 Namespace ,并进行一次 Release
 12:     ReleaseDTO mergedResult = releaseService.updateAndPublish(appId, env, clusterName, namespaceName, title, comment,
 13:                     branchName, isEmergencyPublish, deleteBranch, changeSets);
 14:     // 【TODO 6001】Tracer 日志
 15:     Tracer.logEvent(TracerEventType.MERGE_GRAY_RELEASE, String.format("%s+%s+%s+%s", appId, env, clusterName, namespaceName));
 16:     return mergedResult;
 17: }