最近公司在做边缘计算相关的事情,让我负责云平台的开发。云边协同使用的是华为开源的kubeedge,为了更好的支持云平台开发,我开始自己开发基础框架:spring cloud kubeedge。
华为的kubeedge开源的时间并不长,spring cloud 官方还没有集成它。但是spring cloud 家族已经有spring cloud k8s了,该框架封装了io.fabric8。该开源框架对kubernetes的 API server跟随性不强,华为的kubeedge却紧跟kubernetes的版本。所以我决定自己封装另一个开源组件kubernetes client。
提供标准接口,屏蔽复杂的函数调用和参数设置。
子项目spring cloud kubeedge web 实际上是一个测试项目,使用集成的spring-cloud-kubeedge-core来访问搭建好的kubeedge平台。
部分代码如下:
配置文件:
package com.miller.springcloudkubeedgeweb.config;
import com.miller.springcloudkubeedgeweb.common.StandardNamespaceUtils;
import com.miller.springcloudkubeedgeweb.util.ResourceRenderer;
import io.kubernetes.client.ApiClient;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.util.Config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import io.kubernetes.client.Configuration;
import java.io.IOException;
import java.io.InputStream;
/**
* @program: spring-cloud-kubeedge
* @description: cfg
* @author: Miller.FAN
* @create: 2019-12-09 15:32
**/
@org.springframework.context.annotation.Configuration
@EnableAutoConfiguration
public class NeedConfig {
@Bean
public CoreV1Api coreV1Api() {
String fileName = "classpath:/k8s/controller-manager.conf";
InputStream inputStream = null;
try {
inputStream = ResourceRenderer.resourceLoader(fileName);
} catch (
IOException e) {
e.printStackTrace();
}
ApiClient client = null;
try {
client = Config.fromConfig(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
client.setConnectTimeout(5 * 60 * 1000);
Configuration.setDefaultApiClient(client);
return new CoreV1Api();
}
@Bean
public StandardNamespaceUtils standardNamespaceUtils() {
return new StandardNamespaceUtils();
}
}
service层:
package com.miller.springcloudkubeedgeweb.service;
import com.miller.springcloudkubeedgecore.namespace.StandardNamespaceUtils;
import io.kubernetes.client.apis.CoreV1Api;
import io.kubernetes.client.models.V1Namespace;
import io.kubernetes.client.models.V1NamespaceList;
import org.springframework.stereotype.Service;
/**
* @program: spring-cloud-kubeedge
* @description: namespace
* @author: Miller.FAN
* @create: 2019-12-09 11:58
**/
@Service
public class NamespaceService implements NamespaceRepository{
/* @Autowired
StandardNamespaceUtils standardNamespaceUtils;*/
private CoreV1Api coreV1Api = new CoreV1Api();
private StandardNamespaceUtils standardNamespaceUtils = new StandardNamespaceUtils(coreV1Api);
//返回分区列表
public V1NamespaceList getNamespace(){
return standardNamespaceUtils.getNamespaceList();
}
//创建分区
public V1Namespace createNamespace() {
return standardNamespaceUtils.createNamespace();
}
//删除分区
public Boolean deleteNamespace(String namespace) {
return standardNamespaceUtils.deleteNamespace(namespace);
}
//查询指定的分区信息
public V1Namespace queryNamespace(String namespace) {
return standardNamespaceUtils.queryNamespace(namespace);
}
//替换分区内容
public V1Namespace replaceNamespace(String name, V1Namespace body) {
return standardNamespaceUtils.replaceNamespace(name,body);
}
}
controller层:
package com.miller.springcloudkubeedgeweb.controller;
import com.miller.springcloudkubeedgeweb.service.NamespaceService;
import io.kubernetes.client.models.V1Namespace;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import static com.miller.springcloudkubeedgeweb.common.Commons.SUCCESS;
/**
* @program: spring-cloud-kubeedge
* @description: c
* @author: Miller.FAN
* @create: 2019-12-09 14:26
**/
@RestController
@RequestMapping(path = "/namespace")
@Api(value = "NamespaceController", description = "命名空间信息接口")
public class NamespaceController {
@Autowired
private NamespaceService namespaceService;
@RequestMapping(value ="/get/list" , method = RequestMethod.GET)
@ApiOperation(value = "get/list", notes = "getNamespaceList")
public HashMap getNamespaceList() {
HashMap ret = new HashMap<>();
ret.put(SUCCESS,namespaceService.getNamespace());
return ret;
}
@RequestMapping(value ="/creat" , method = RequestMethod.POST)
@ApiOperation(value = "creat", notes = "creatNamespace")
public HashMap creatNamespace() {
HashMap ret = new HashMap<>();
ret.put(SUCCESS,namespaceService.createNamespace());
return ret;
}
@RequestMapping(value ="/delete/{namespace}" , method = RequestMethod.DELETE)
@ApiOperation(value = "delete", notes = "deleteNamespace")
public HashMap deleteNamespace(@PathVariable String namespace) {
HashMap ret = new HashMap<>();
ret.put(SUCCESS,namespaceService.deleteNamespace(namespace));
return ret;
}
@RequestMapping(value ="/query/{namespace}" , method = RequestMethod.GET)
@ApiOperation(value = "query", notes = "queryNamespace")
public HashMap queryNamespace(@PathVariable String namespace) {
HashMap ret = new HashMap<>();
ret.put(SUCCESS,namespaceService.queryNamespace(namespace));
return ret;
}
@RequestMapping(value ="/update/{namespace}" , method = RequestMethod.PUT)
@ApiOperation(value = "update", notes = "creatNamespace")
public HashMap creatNamespace(@PathVariable String namespace, @RequestBody V1Namespace body) {
HashMap ret = new HashMap<>();
ret.put(SUCCESS,namespaceService.replaceNamespace(namespace,body));
return ret;
}
}
在swagger的UI页面测试:
返回的结果:
{
"ok": {
"apiVersion": "v1",
"items": [
{
"apiVersion": null,
"kind": null,
"metadata": {
"annotations": null,
"clusterName": null,
"creationTimestamp": {
"year": 2019,
"dayOfMonth": 10,
"dayOfWeek": 2,
"era": 1,
"dayOfYear": 344,
"hourOfDay": 19,
"yearOfCentury": 19,
"weekyear": 2019,
"centuryOfEra": 20,
"yearOfEra": 2019,
"monthOfYear": 12,
"minuteOfHour": 0,
"weekOfWeekyear": 50,
"millisOfSecond": 0,
"secondOfMinute": 30,
"millisOfDay": 68430000,
"minuteOfDay": 1140,
"secondOfDay": 68430,
"millis": 1575975630000,
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
},
"chronology": {
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
}
},
"beforeNow": true,
"equalNow": false,
"afterNow": false
},
"deletionGracePeriodSeconds": null,
"deletionTimestamp": null,
"finalizers": null,
"generateName": null,
"generation": null,
"initializers": null,
"labels": null,
"managedFields": null,
"name": "default",
"namespace": null,
"ownerReferences": null,
"resourceVersion": "148",
"selfLink": "/api/v1/namespaces/default",
"uid": "9c1a0018-ce47-4229-a32e-b675b33d7056"
},
"spec": {
"finalizers": [
"kubernetes"
]
},
"status": {
"phase": "Active"
}
},
{
"apiVersion": null,
"kind": null,
"metadata": {
"annotations": null,
"clusterName": null,
"creationTimestamp": {
"year": 2019,
"dayOfMonth": 10,
"dayOfWeek": 2,
"era": 1,
"dayOfYear": 344,
"hourOfDay": 19,
"yearOfCentury": 19,
"weekyear": 2019,
"centuryOfEra": 20,
"yearOfEra": 2019,
"monthOfYear": 12,
"minuteOfHour": 0,
"weekOfWeekyear": 50,
"millisOfSecond": 0,
"secondOfMinute": 27,
"millisOfDay": 68427000,
"minuteOfDay": 1140,
"secondOfDay": 68427,
"millis": 1575975627000,
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
},
"chronology": {
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
}
},
"beforeNow": true,
"equalNow": false,
"afterNow": false
},
"deletionGracePeriodSeconds": null,
"deletionTimestamp": null,
"finalizers": null,
"generateName": null,
"generation": null,
"initializers": null,
"labels": null,
"managedFields": null,
"name": "kube-node-lease",
"namespace": null,
"ownerReferences": null,
"resourceVersion": "38",
"selfLink": "/api/v1/namespaces/kube-node-lease",
"uid": "2fa58c84-63ed-4b66-9a1b-896da7d8a7d0"
},
"spec": {
"finalizers": [
"kubernetes"
]
},
"status": {
"phase": "Active"
}
},
{
"apiVersion": null,
"kind": null,
"metadata": {
"annotations": null,
"clusterName": null,
"creationTimestamp": {
"year": 2019,
"dayOfMonth": 10,
"dayOfWeek": 2,
"era": 1,
"dayOfYear": 344,
"hourOfDay": 19,
"yearOfCentury": 19,
"weekyear": 2019,
"centuryOfEra": 20,
"yearOfEra": 2019,
"monthOfYear": 12,
"minuteOfHour": 0,
"weekOfWeekyear": 50,
"millisOfSecond": 0,
"secondOfMinute": 27,
"millisOfDay": 68427000,
"minuteOfDay": 1140,
"secondOfDay": 68427,
"millis": 1575975627000,
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
},
"chronology": {
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
}
},
"beforeNow": true,
"equalNow": false,
"afterNow": false
},
"deletionGracePeriodSeconds": null,
"deletionTimestamp": null,
"finalizers": null,
"generateName": null,
"generation": null,
"initializers": null,
"labels": null,
"managedFields": null,
"name": "kube-public",
"namespace": null,
"ownerReferences": null,
"resourceVersion": "37",
"selfLink": "/api/v1/namespaces/kube-public",
"uid": "0964a321-07c2-45ff-8ffa-f3438e9d2d4a"
},
"spec": {
"finalizers": [
"kubernetes"
]
},
"status": {
"phase": "Active"
}
},
{
"apiVersion": null,
"kind": null,
"metadata": {
"annotations": null,
"clusterName": null,
"creationTimestamp": {
"year": 2019,
"dayOfMonth": 10,
"dayOfWeek": 2,
"era": 1,
"dayOfYear": 344,
"hourOfDay": 19,
"yearOfCentury": 19,
"weekyear": 2019,
"centuryOfEra": 20,
"yearOfEra": 2019,
"monthOfYear": 12,
"minuteOfHour": 0,
"weekOfWeekyear": 50,
"millisOfSecond": 0,
"secondOfMinute": 27,
"millisOfDay": 68427000,
"minuteOfDay": 1140,
"secondOfDay": 68427,
"millis": 1575975627000,
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
},
"chronology": {
"zone": {
"fixed": false,
"uncachedZone": {
"fixed": false,
"cachable": true,
"id": "Asia/Shanghai"
},
"id": "Asia/Shanghai"
}
},
"beforeNow": true,
"equalNow": false,
"afterNow": false
},
"deletionGracePeriodSeconds": null,
"deletionTimestamp": null,
"finalizers": null,
"generateName": null,
"generation": null,
"initializers": null,
"labels": null,
"managedFields": null,
"name": "kube-system",
"namespace": null,
"ownerReferences": null,
"resourceVersion": "36",
"selfLink": "/api/v1/namespaces/kube-system",
"uid": "5e6cbd2f-a2b5-4315-a50e-6d2fd52ab8b7"
},
"spec": {
"finalizers": [
"kubernetes"
]
},
"status": {
"phase": "Active"
}
}
],
"kind": "NamespaceList",
"metadata": {
"resourceVersion": "109495",
"selfLink": "/api/v1/namespaces",
"continue": null
}
}
}
上面的返回数据是json格式的,包含了kubeedge的所有namespace的信息。
大家看到import com.miller.***这样的导入,不要被误导,这是我自己开发的starter,在自己本地仓库中,网上是没有的,我的英文名:miller,所有我没有成立的公司叫com.miller。欢迎各路神仙来访,留言、讨论、学习。