Spinnaker的Clouddriver如何支持Istio
目录实现思路需要扩展的类型核心代码KubernetesApiGroupKubernetesKindKubernetesKindPropertiesKubernetesHandler效果图:deploypatch更复杂的类型Spinnaker的clouddriver对kubernetes支持本质是将UI入参转化到代码最终转换成本地kuber命令来实现的,因为其是通过“白名单”的策略来实现的,所以对k
目录
Spinnaker的clouddriver对kubernetes支持本质是将UI入参转化到代码最终转换成本地kuber命令来实现的,因为其是通过“白名单”的策略来实现的,所以对k8s的支持比较有限,不在白名单内的资源类型是无法被spinnaker执行的。像Istio这么火的云原生技术竟然在spinnaker体系中应用不起来,这是不能容忍的,所以经过对clouddriver代码的研究终于找到了破解之法。
实现思路
既然是“白名单”策略,那我们就按照clouddriver框架仿照其它资源把该实现的接口和方法实现掉好了。
需要扩展的类型
先看下跟spinnaker有关涉及到的istio类型吧。
其中绿色部分跟部署计算节点相关,这部分spinnaker已经很完美的实现了,我们需要解决的是入口蓝色部分和网格内流量调度黄色部分,因为这些部分是我们自动化发布流程金丝雀部分需要用到的。
核心代码
spinnaker中对于k8s的支持核心有4个类:KubernetesApiGroup、KubernetesKind、KubernetesKindProperties、KubernetesHandler
KubernetesApiGroup
Spinnaker中支持的k8sAPIGroup的白名单,所以为了支持istio我们需要添加
public static final KubernetesApiGroup NETWORKING_ISTIO_IO = new KubernetesApiGroup("networking.istio.io");
KubernetesKind
Spinnaker中支持的k8s资源类型的白名单,如果manifest的kind不在这个白名单中spinnaker是无法管理的。
private static KubernetesKind createWithAlias(
String name, @Nullable String alias, @Nullable KubernetesApiGroup apiGroup) {
KubernetesKind kind = new KubernetesKind(name, apiGroup);
aliasMap.put(kind, kind);
if (alias != null) {
aliasMap.put(new KubernetesKind(alias, apiGroup), kind);
}
return kind;
}
Kind有3个属性,第一个对应资源类型也就是manifest中的kind;第二个是别名,非必填;第三个是api组,对应前面的KubernetesApiGroup
这里我们需要补充spinnaker中用到的3个跟istio相关的kind:
public static final KubernetesKind VIRTUAL_SERVICE =
createWithAlias(
"virtualService", null, KubernetesApiGroup.NETWORKING_ISTIO_IO);
public static final KubernetesKind DESTINATION_RULE =
createWithAlias(
"destinationRule", null, KubernetesApiGroup.NETWORKING_ISTIO_IO);
public static final KubernetesKind GATEWAY =
createWithAlias(
"gateway", null, KubernetesApiGroup.NETWORKING_ISTIO_IO);
KubernetesKindProperties
类型相关的配置
private KubernetesKindProperties(
KubernetesKind kubernetesKind, boolean isNamespaced, boolean hasClusterRelationship) {
this.kubernetesKind = kubernetesKind;
this.isNamespaced = isNamespaced;
this.hasClusterRelationship = hasClusterRelationship;
}
kubernetesKind对应前面的KubernetesKind;isNamespaced表示资源是否受命名空间的隔离约束,除开高级的管理资源类型基本都是false;hasClusterRelationship这个没看明道,我看现在的类型都是false。
这里我们需要补充istio相关的kindProperties:
new KubernetesKindProperties(KubernetesKind.GATEWAY, true, false),
new KubernetesKindProperties(KubernetesKind.DESTINATION_RULE, true, false),
new KubernetesKindProperties(KubernetesKind.VIRTUAL_SERVICE, true, false),
KubernetesHandler
对每种kind的自定义部分,每个kind必须配备一个handler,以KubernetesVirtualServiceHandler为例:
package com.netflix.spinnaker.clouddriver.kubernetes.v2.op.handler;
import com.netflix.spinnaker.clouddriver.kubernetes.description.SpinnakerKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.agent.KubernetesCoreCachingAgent;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.caching.agent.KubernetesV2CachingAgentFactory;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesKind;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.description.manifest.KubernetesManifest;
import com.netflix.spinnaker.clouddriver.kubernetes.v2.model.Manifest;
import org.springframework.stereotype.Component;
import javax.annotation.Nonnull;
@Component
public class KubernetesVirtualServiceHandler extends KubernetesHandler {
@Override
public int deployPriority() {
return DeployPriority.MOUNTABLE_DATA_PRIORITY.getValue();
}
@Nonnull
@Override
public KubernetesKind kind() {
return KubernetesKind.VIRTUAL_SERVICE;
}
@Override
public boolean versioned() {
return false;
}
@Nonnull
@Override
public SpinnakerKind spinnakerKind() {
return SpinnakerKind.CONFIGS;
}
@Override
public Manifest.Status status(KubernetesManifest manifest) {
return Manifest.Status.defaultStatus();
}
@Override
protected KubernetesV2CachingAgentFactory cachingAgentFactory() {
return KubernetesCoreCachingAgent::new;
}
}
deployPriority()定义kind执行时的优先级,因为istio相关的都属于配置类的,所以我们可以参考configMap的优先级。
versioned()定义kind执行时是否有版本的概念,方便历史记录管理和回滚。
spinnakerKind()定义的是在spinnaker中的归类,用于前端deck加载,像pod定义成instance、ingress定义成loadBalancer,istio中如果不做展示可以把资源定义成config,如果前端要看到他们的关联关系就要严格按照spinnaker的类型来定义了。
INSTANCES("instances"),
CONFIGS("configs"),
SERVER_GROUPS("serverGroups"),
LOAD_BALANCERS("loadBalancers"),
SECURITY_GROUPS("securityGroups"),
SERVER_GROUP_MANAGERS("serverGroupManagers"),
UNCLASSIFIED("unclassified");
status(KubernetesManifest manifest)和cachingAgentFactory()我们也沿用configMap的,主要用于状态判断和缓存管理。
效果图:
deploy
执行结果
patch
patch时需要注意因为istio是CRD实现的,默认的type(strategic)会报错,所以patch时type要选择merge
更复杂的类型
很幸运istio的这些KubernetesKind不需要关心执行结果,像deployment这样的就复杂多了,因为spinnaker不仅需要关心kuber apply命令的结果,还需要去判断有没有达到预期。
private Status status(V1Deployment deployment) {
V1DeploymentStatus status = deployment.getStatus();
if (status == null) {
return Status.noneReported();
}
if (!generationMatches(deployment, status)) {
return Status.defaultStatus().unstable(UnstableReason.OLD_GENERATION.getMessage());
}
List<V1DeploymentCondition> conditions =
Optional.ofNullable(status.getConditions()).orElse(ImmutableList.of());
Status result = Status.defaultStatus();
getPausedReason(conditions).ifPresent(result::paused);
getUnavailableReason(conditions)
.ifPresent(reason -> result.unstable(reason).unavailable(reason));
getFailedReason(conditions).ifPresent(result::failed);
checkReplicaCounts(deployment, status)
.ifPresent(reason -> result.unstable(reason.getMessage()));
return result;
}
注意checkReplicaCounts()这个地方就是去检查有没有开出理想中的pod数量。
更多推荐
所有评论(0)