介绍
在首次发行时Fabric8 2版使用的是基于JAX-RS已经Kubernetes这是使用客户ApacheCXF 。 客户端很棒,但是我们一直想提供更薄的东西,更少的依赖(以便更容易采用) 。 我们还想给它一个功能,并围绕它构建一个DSL,以使其更易于使用和阅读。
新客户端当前位于: https : //github.com/fabric8io/kubernetes-client ,它提供以下模块:
- Kubernetes客户
- 一个Openshift客户。
- 以上所有功能的模拟框架(基于EasyMock )
乍一看客户
让我们快速了解如何使用客户端创建,列出和删除内容:
//Instantiate the client
KubernetesClient client = new DefaultKubernetesClient();
//Create a service
Service myservice = ...;
client.services().inNamespace("fabric8").create(myservice);
//Create a service inline
Service jenkins = client.services().inNamespace("fabric8").createNew()
.withNewMetadata()
.withName("jenkins")
.addToLabels("component", "jenkins")
.endMetadata()
.done();
//List services
ServiceList serviceList = client.services().inNamespace("fabric8").list();
//Watch services
client.services().inNamespace("fabric8").watch(new Watcher<Service>() {
@Override
public void eventReceived(Action action, Service resource) {
logger.info("{}: {}", action, resource);
}
});
//Delete by label
Boolean deleted = client.services().withLabel("component", "jenkins").delete();
//Close client
client.close();
上面的代码片段几乎可以自我解释(这就是使用DSL的美妙之处),但是我仍然有一个博客文章可以填写,因此我将提供尽可能多的细节。
客户端域模型
您可以将客户视为两件事的结合:
- Kubernetes域模型。
- 模型周围的DSL。
域模型是一组对象,这些对象表示在客户端与Kubernetes / Openshift之间交换的数据。 数据的原始格式为JSON。 这些JSON对象非常复杂,其结构也很严格,因此手工制作它们并不是一件容易的事。
我们需要一种在Java中操作这些JSON对象的方法(并能够利用代码完成等功能),但还应尽可能地保持原始格式。 使用JSON对象的POJO表示形式可以进行操作,但是感觉不太像JSON,也不能真正用于具有深度嵌套的JSON。 因此,我们决定在那些使用与原始JSON完全相同的结构的POJO之上生成流畅的生成器。
例如,这里是Kubernetes服务的JSON对象:
{
"kind": "Service",
"metadata": {
"name": "kubernetes",
"namespace": "default",
"labels": {
"component": "apiserver",
"provider": "kubernetes"
}
},
"spec": {
"ports": [
{
"name": "",
"protocol": "TCP",
"port": 443,
"targetPort": 443
}
],
"selector": null,
"portalIP": "172.30.17.2",
"sessionAffinity": "None"
},
"status": {}
}
使用Fluent Builders的Java等效项可能是:
Service srv = new ServiceBuilder()
.withNewMetadata()
.withName("kubernetes")
.addToLabels("component", "apiserver")
.addToLabels("provider", "kubernetes")
.endMetadata()
.withNewSpec()
.addNewPort()
.withProtocol("TCP")
.withPort(443)
.withNewTargetPort(443)
.endPort()
.withPortalIP("172.30.17.2")
.withSessionAffinity("None")
.endSpec()
.build();
域模型依赖于其自己的项目: Fabric8的Kubernetes模型 。 经过很长的过程,该模型是从Kubernetes和Openshift代码生成的:
- 进行源转换JSON模式
- JSON模式转换POJO
- 一代流利的建设者
流利的构建者是由一个名为sundrio的小项目生成的,我将在以后的文章中介绍。
获取客户端实例
由于提供了一个空的构造函数,因此获取默认客户端实例的实例非常简单。 使用空的构造函数时,客户端将使用以下默认设置:
- Kubernetes URL
- 系统属性“ kubernetes.master ”
- 环境变量“ KUBERNETES_MASTER ”
- 来自用户主目录中的“ .kube / config ”文件。
- 使用DNS:“ https://kubernetes.default.svc ”
- 服务帐户路径“ /var/run/secrets/kubernetes.io/serviceaccount/ ”
//Client with custom config
Config config = new ConfigBuilder()
.withMasterUrl(url)
.withTrustCerts(true)
.withOauthToken(mytoken)
.build();
KubernetesClient = new DefaultKubernetesClient(config);
客户端扩展和适配器
为了支持Kubernetes扩展(例如Openshift ),客户端使用Extension和Adapter的概念。 这个想法很简单。 扩展客户端扩展默认客户端并实现Extension 。 只要可以通过Java的ServiceLoader找到一个适配器,每个客户端实例都可以适应该扩展 (请原谅)。
这是一个如何使客户端的任何实例适应OpenshiftClient实例的示例 :
KubernetesClient client = new DefaultKubernetesClinet();
OpenShiftClient oc = client.adapt(OpenShiftClient.class);
仅当Kubernetes客户端返回的根路径列表中存在/ oapi时,以上代码才有效(即,该客户端指向开放式移位安装)。 如果不是,它将抛出IllegalArugementException。
如果用户正在编写绑定到Openshift的代码,则他总是可以直接实例化默认openshift客户端的实例。
//Openshift client with custom config
OpenshiftConfig config = new OpenshiftConfigBuilder()
.withMasterUrl(url)
.withOpenShiftUrl(openshiftUrl)
.withTrustCerts(true)
.build();
OpenshiftClient client = new DefaultOpenshiftClient(config);
测试和模拟
模拟与外部系统对话的客户端是很常见的情况。 当客户平时
(不支持方法链接)模拟很简单,并且有大量的框架可用于这项工作。 但是,当使用DSL时,事情变得更加复杂,并且需要大量样板代码才能将各个部分连接在一起。 如果原因不明显,我们可以说使用模拟方法定义每次方法调用时模拟方法的行为。 与等效的Flat对象相比,DSL倾向于拥有更多的方法(带有更少的参数)。 仅此一项就增加了定义行为所需的工作。 而且,这些方法通过返回中间对象链接在一起,这意味着它们也需要被模拟,这进一步增加了工作量和复杂性。
为了删除所有样板并简化使用客户端的过程,我们将客户端的DSL与模拟框架EasyMock的DSL相结合。 这意味着该DSL的入口点是Kubernetes客户端DSL本身,但是终端方法已经过修改,因此它们返回“期望设置器”。 一个例子应该使它更容易理解。
KubernetesMockClient mock = new KubernetesMockClient();
//Define the behaviour
mock.services().inNamespace(or("default","fabric8")).withName("fabric8-console-service").get().andReturn(
new ServiceBuilder()
.withNewMetadata().withName("fabric8-console-service").endMetadata()
.withNewSpec()
.addNewPort()
.withProtocol("TCP")
.withPort(80)
.withNewTargetPort(9090)
.endPort()
.endSpec()
.build()
).anyTimes();
//Get an instance of the client mock
KubernetesClient client = mock.replay();
//Use the client
Assert.assertNotNull(client.services().inNamespace("fabric8").withName("fabric8-console-service").get());
Assert.assertNotNull(client.services().inNamespace("default").withName("fabric8-console-service").get());
//Verify the client
EasyMock.verify(client);
该模拟框架可以轻松地与其他Fabric8组件结合,例如CDI扩展 。 您只需要创建@Produces方法即可返回模拟。
请享用!
翻译自: https://www.javacodegeeks.com/2015/08/fabric8-kubernetes-and-openshift-java-dsl.html