前面几篇比较枯燥的介绍了orca、clouddriver、deck目录结构和核心代码,本篇将会作为这一系列的终篇为大家分享下如何在spinnaker中开发一个自定义的环节。
需求背景:
Spinnaker对于镜像自带了FindImageByTags环节,可以让我们在pipeline中通过tag为条件选中想要发布的镜像,流转到后续的deploy环节。但是腾讯云镜像不支持tag功能,所以为了达到同样的效果我们需要自开发一个findImageByName环节。
开发deck-(angular)
1 core部分:
说明:core解决的是parent级别的环节问题,每个环节都必须从parent中继承,因为本次开发的环节是全新环节,parent也没有,所以需要先修改core
1.1 先从core中添加parent环节:
modules\core\src\pipeline\config\stages\findImageFromName
以及相关的文件findImageFromNameStage.js 和 findImageFromNameStage.module.js
1.2 修改stageConstants (个人觉得可能不是必须的)
modules\core\src\pipeline\config\stages\stageConstants.ts
修改IMAGE_PRODUCING_STAGES部分
1.3 修改pipeline.module注册
modules\core\src\pipeline\pipeline.module.ts
1.4 修改Deploy环节的前置条件
modules\core\src\pipeline\config\stages\deploy\deployStage.js
因为deploy环节需要输入一个镜像id作为环节的前置条件,目前已知的有findImageByTag和bake,本次添加的环节也属于deploy的前置条件,所以此处需要修改。关键字"stageBeforeType"
2 tencent部分:
说明:解决的是厂商sub级别的环节问题,只有注册过的环节才可以在deck中被看到
2.1 厂商实现core中剩余部分
modules\tencent\src\pipeline\stages\findImageFromName
以及相关文件:
tencentFindImageFromNameStage.js 自定义注册
findImageFromNameExecutionDetails.html pipeline中看到的页面
findImageFromNameStage.html stage的详细页面
2.2 添加进厂商配置文件
modules\tencent\src\tencent.module.ts
3 前端效果
到目前位置可以重启deck,可以看到基本的效果了。
4 核心问题思考
Q1:stage页面中,初始数据从哪来?
A1:两层:
第一层:modules\core\src\pipeline\config\stages\stage.module.js中controller('StageConfigCtrl')
第二层:modules\tencent\src\pipeline\stages\findImageFromName\tencentFindImageFromNameStage.js中又设置了一次,基本就是透传的第一层
第一层没找到,合理的猜测:pipeline执行后相关的json保留在了redis中,所以此处不需要关心,先忽略。
Q2:stage的表单最终提交到哪里去?
A2:通过API这个module调用了gateway流入到了orca中,后面重点会去开发orca
开发orca-(java+groovy)
1 先开发公共部分:
1.1 先创建一个对应的stage
FindImageFromNameStage.java,内容很简单,对task的组装,因为task对我们来说也是新的,所以要自己再创建task。
注意:stage一定要实现StageDefinitionBuilder,具体原因后面详解
1.2 再创建一个对应的task
FindImageFromNameTask.java 需要继承AbstractCloudProviderAwareTask并根据是否可以重复执行选择性的实现RetryableTask
跟入AbstractCloudProviderAwareTask中
abstract class AbstractCloudProviderAwareTask implements CloudProviderAware, Task {}
其中CloudProviderAware中都有default的实现,此处可以暂时不管;
Task中TaskResult execute(@Nonnull Stage stage)方法需要实现掉
1.3 扩展Reader和Writer
发现task最终调用的Reader和Writer来做的业务处理,但是现有的接口方法不支持我的业务,所以需要添加方法,进行扩展.
注意扩展时给自己新方法添加default实现,不要影响现有功能。
2 再开发云厂商部分
云厂商实现在com\netflix\spinnaker\orca\clouddriver\tasks\providers下
3 核心问题思考
Q:deck中环节如何与orca映射起来的?
A:前文说过stage一定要实现StageDefinitionBuilder,核心代码在StageDefinitionBuilder中getType方法:
static String getType(Class<? extends StageDefinitionBuilder> clazz) {
String className = clazz.getSimpleName();
return className.substring(0, 1).toLowerCase() + className.substring(1).replaceFirst("StageDefinitionBuilder$", "").replaceFirst("Stage$", "");
}
然后DefaultStageDefinitionBuilderFactory中builderFor方法:
@Override
public @Nonnull StageDefinitionBuilder builderFor(
@Nonnull Stage stage) throws NoSuchStageDefinitionBuilder {
return stageDefinitionBuilders
.stream()
.filter((it) -> it.getType().equals(stage.getType()) || it.getType().equals(stage.getContext().get("alias")))
.findFirst()
.orElseThrow(() -> {
List<String> knownTypes = stageDefinitionBuilders.stream().map(it -> it.getType()).sorted().collect(toList());
return new NoSuchStageDefinitionBuilder(stage.getType(), knownTypes);
});
}
其中stageDefinitionBuilders来在springIoc框架,所有子类或实现类的集合
private final Collection<StageDefinitionBuilder> stageDefinitionBuilders;
总结:只要实现了stageDefinitionBuilders并且按照命名规则定义类名,就会被认为是后端的一个stage。
开发clouddriver-(groovy)
1 controller层修改
找到orca中reader请求clouddriver的restful对应的controller,根据业务需求选择原基础上改造还是重新做一个restful入口
TencentNamedImageLookupController
2 编写核心业务逻辑
本次涉及到的是镜像查询逻辑变更,查询是直接从cache中获取的,cache的存储逻辑在TencentImageCachingAgent,根据需求进行改造,在查找后需要按照orca接收的json格式进行封装。
FindImageByName环节代码列表:
Deck:
新增:
modules/core/src/pipeline/config/stages/findImageFromName/findImageFromNameStage.js
modules/core/src/pipeline/config/stages/findImageFromName/findImageFromNameStage.module.js
modules/tencent/src/pipeline/stages/findImageFromName/findImageFromNameStage.html
modules/tencent/src/pipeline/stages/findImageFromName/findImageFromNameExecutionDetails.html
modules/tencent/src/pipeline/stages/findImageFromName/tencentFindImageFromNameStage.js
修改:
modules/core/src/pipeline/config/stages/deploy/deployStage.js
modules/tencent/src/aws.module.ts
modules/core/src/pipeline/config/stages/stageConstants.ts
modules/core/src/pipeline/pipeline.module.ts
Orca:
新增:
com.netflix.spinnaker.orca.clouddriver.pipeline.image.FindImageFromNameStage.java
com.netflix.spinnaker.orca.clouddriver.tasks.image.FindImageFromNameTask.java
com.netflix.spinnaker.orca.clouddriver.tasks.providers.tencent.TencentImageFinder.groovy
修改:
com.netflix.spinnaker.orca.clouddriver.tasks.image.ImageFinder.java
CloudDriver:
新增:
com.netflix.spinnaker.clouddriver.tencent.controllers.TencentNamedImageLookupController.groovy
修改:
com.netflix.spinnaker.clouddriver.tencent.provider.agent.TencentImageCachingAgent.groovy
本文的项目地址:https://github.com/spinnaker-cn