From 2df54be0c77d9bb747c1999f978f4482228e632a Mon Sep 17 00:00:00 2001 From: WindSearcher Date: Tue, 15 Oct 2024 18:01:56 +0800 Subject: [PATCH] K8s register (#5679) * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * dynamic register * k8s register * k8s register * dynamic register * dynamic register --------- Co-authored-by: aias00 Co-authored-by: yunlongn --- shenyu-registry/pom.xml | 1 + shenyu-registry/shenyu-registry-core/pom.xml | 5 + .../shenyu-registry-kubernetes/pom.xml | 43 ++++ .../registry/kubernetes/KubernetesClient.java | 61 ++++++ .../registry/kubernetes/KubernetesConfig.java | 81 +++++++ .../kubernetes/KubernetesInstance.java | 207 ++++++++++++++++++ .../KubernetesInstanceRegisterRepository.java | 80 +++++++ ...istry.api.ShenyuInstanceRegisterRepository | 17 ++ 8 files changed, 495 insertions(+) create mode 100644 shenyu-registry/shenyu-registry-kubernetes/pom.xml create mode 100644 shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesClient.java create mode 100644 shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesConfig.java create mode 100644 shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstance.java create mode 100644 shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstanceRegisterRepository.java create mode 100644 shenyu-registry/shenyu-registry-kubernetes/src/main/resources/META-INF/shenyu/org.apache.shenyu.registry.api.ShenyuInstanceRegisterRepository diff --git a/shenyu-registry/pom.xml b/shenyu-registry/pom.xml index 2841f36688b0..227ea56fa1c7 100644 --- a/shenyu-registry/pom.xml +++ b/shenyu-registry/pom.xml @@ -36,6 +36,7 @@ shenyu-registry-apollo shenyu-registry-eureka shenyu-registry-polaris + shenyu-registry-kubernetes diff --git a/shenyu-registry/shenyu-registry-core/pom.xml b/shenyu-registry/shenyu-registry-core/pom.xml index 74107a71d1ee..2b36e3258d96 100644 --- a/shenyu-registry/shenyu-registry-core/pom.xml +++ b/shenyu-registry/shenyu-registry-core/pom.xml @@ -61,6 +61,11 @@ shenyu-registry-eureka ${project.version} + + org.apache.shenyu + shenyu-registry-kubernetes + ${project.version} + diff --git a/shenyu-registry/shenyu-registry-kubernetes/pom.xml b/shenyu-registry/shenyu-registry-kubernetes/pom.xml new file mode 100644 index 000000000000..9c828a998bce --- /dev/null +++ b/shenyu-registry/shenyu-registry-kubernetes/pom.xml @@ -0,0 +1,43 @@ + + + + + + org.apache.shenyu + shenyu-registry + 2.7.0-SNAPSHOT + + + 4.0.0 + shenyu-registry-kubernetes + + + + org.apache.shenyu + shenyu-registry-api + ${project.version} + + + + org.springframework + spring-web + provided + + + diff --git a/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesClient.java b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesClient.java new file mode 100644 index 000000000000..fb1c206085ff --- /dev/null +++ b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesClient.java @@ -0,0 +1,61 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shenyu.registry.kubernetes; + +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * kubernetes client. + */ +public class KubernetesClient { + + private RestTemplate rest; + + private KubernetesConfig kubernetesConfig; + + public KubernetesClient(final KubernetesConfig kubernetesConfig) { + this.kubernetesConfig = kubernetesConfig; + this.rest = new RestTemplate(); + } + + /** + * get all serviceInstance. + * @param serviceId service identifier + * @return list of serviceInstance + */ + public List selectInstances(final String serviceId) { + List response = Collections.emptyList(); + KubernetesInstance[] responseBody = (KubernetesInstance[]) this.rest.getForEntity(this.kubernetesConfig.getDiscoveryServerUrl() + "/apps/" + serviceId, + KubernetesInstance[].class, new Object[0]).getBody(); + if (responseBody != null && responseBody.length > 0) { + response = (List) Arrays.stream(responseBody).filter(this::matchNamespaces).collect(Collectors.toList()); + } + + return response; + } + + private boolean matchNamespaces(final KubernetesInstance kubernetesInstance) { + return CollectionUtils.isEmpty(this.kubernetesConfig.getNamespaces()) ? true : this.kubernetesConfig.getNamespaces().contains(kubernetesInstance.getNamespace()); + } +} diff --git a/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesConfig.java b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesConfig.java new file mode 100644 index 000000000000..17dacd730084 --- /dev/null +++ b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesConfig.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shenyu.registry.kubernetes; + +import java.util.ArrayList; +import java.util.List; + +public class KubernetesConfig { + + private String discoveryServerUrl; + + private boolean enabled = true; + + private List namespaces = new ArrayList(); + + public KubernetesConfig() { + } + + /** + * get discoveryServer url. + * @return discoveryServer url. + */ + public String getDiscoveryServerUrl() { + return this.discoveryServerUrl; + } + + /** + * set discoveryServer url. + * @param discoveryServerUrl discoveryServer url. + */ + public void setDiscoveryServerUrl(final String discoveryServerUrl) { + this.discoveryServerUrl = discoveryServerUrl; + } + + /** + * get enable status. + * @return enable status. + */ + public boolean isEnabled() { + return this.enabled; + } + + /** + * set registry enable status. + * @param enabled enable status. + */ + public void setEnabled(final boolean enabled) { + this.enabled = enabled; + } + + /** + * get namespaces. + * @return namespaces. + */ + List getNamespaces() { + return this.namespaces; + } + + /** + * set kubernetes namespace. + * @param namespaces list of namespace. + */ + public void setNamespaces(final List namespaces) { + this.namespaces = namespaces; + } +} diff --git a/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstance.java b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstance.java new file mode 100644 index 000000000000..d8878b1513e1 --- /dev/null +++ b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstance.java @@ -0,0 +1,207 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shenyu.registry.kubernetes; + +import java.net.URI; +import java.util.Map; + +/** + * kubernetes instance. + */ +public class KubernetesInstance { + + private String instanceId; + + private String serviceId; + + private String host; + + private int port; + + private boolean secure; + + private URI uri; + + private Map metadata; + + private String scheme; + + private String namespace; + + public KubernetesInstance() { + } + + public KubernetesInstance(final String instanceId, final String serviceId, final String host, + final int port, final boolean secure, final URI uri, + final Map metadata, final String scheme, final String namespace) { + this.instanceId = instanceId; + this.serviceId = serviceId; + this.host = host; + this.port = port; + this.secure = secure; + this.uri = uri; + this.metadata = metadata; + this.scheme = scheme; + this.namespace = namespace; + } + + /** + * get instanceId. + * @return instanceId. + */ + public String getInstanceId() { + return this.instanceId; + } + + /** + * get serviceId. + * @return serviceId. + */ + public String getServiceId() { + return this.serviceId; + } + + /** + * get host. + * @return host. + */ + public String getHost() { + return this.host; + } + + /** + * get port. + * @return port. + */ + public int getPort() { + return this.port; + } + + /** + * get secure. + * @return secure. + */ + public boolean isSecure() { + return this.secure; + } + + /** + * get uri. + * @return uri. + */ + public URI getUri() { + return this.uri; + } + + /** + * get metadata. + * @return metadata. + */ + public Map getMetadata() { + return this.metadata; + } + + /** + * get scheme. + * @return scheme. + */ + public String getScheme() { + return this.scheme; + } + + /** + * get namespace. + * @return namespace. + */ + public String getNamespace() { + return this.namespace; + } + + /** + * set instanceId. + * @param instanceId instance identifier. + */ + public void setInstanceId(final String instanceId) { + this.instanceId = instanceId; + } + + /** + * set serviceId. + * @param serviceId service identifier. + */ + public void setServiceId(final String serviceId) { + this.serviceId = serviceId; + } + + /** + * set host. + * @param host ipaddress. + */ + public void setHost(final String host) { + this.host = host; + } + + /** + * set port. + * @param port port. + */ + public void setPort(final int port) { + this.port = port; + } + + /** + * set secure. + * @param secure secure. + */ + public void setSecure(final boolean secure) { + this.secure = secure; + } + + /** + * set uri. + * @param uri uri. + */ + public void setUri(final URI uri) { + this.uri = uri; + } + + /** + * set metadata. + * @param metadata metadata. + */ + public void setMetadata(final Map metadata) { + this.metadata = metadata; + } + + /** + * set scheme. + * @param scheme scheme. + */ + public void setScheme(final String scheme) { + this.scheme = scheme; + } + + /** + * set namespace. + * @param namespace namespace. + */ + public void setNamespace(final String namespace) { + this.namespace = namespace; + } + +} diff --git a/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstanceRegisterRepository.java b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstanceRegisterRepository.java new file mode 100644 index 000000000000..25e4f487e6e4 --- /dev/null +++ b/shenyu-registry/shenyu-registry-kubernetes/src/main/java/org/apache/shenyu/registry/kubernetes/KubernetesInstanceRegisterRepository.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.shenyu.registry.kubernetes; + +import org.apache.shenyu.registry.api.ShenyuInstanceRegisterRepository; +import org.apache.shenyu.registry.api.config.RegisterConfig; +import org.apache.shenyu.registry.api.entity.InstanceEntity; +import org.apache.shenyu.spi.Join; + +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + +/** + * The type kubernetes instance register repository. + */ +@Join +public class KubernetesInstanceRegisterRepository implements ShenyuInstanceRegisterRepository { + + private KubernetesClient kubernetesClient; + + @Override + public void init(final RegisterConfig config) { + Properties properties = config.getProps(); + KubernetesConfig kubernetesConfig = new KubernetesConfig(); + kubernetesConfig.setDiscoveryServerUrl(config.getServerLists()); + kubernetesConfig.setEnabled(config.getEnabled()); + kubernetesConfig.setNamespaces(Arrays.asList(properties.getProperty("namespaces").split(","))); + this.kubernetesClient = new KubernetesClient(kubernetesConfig); + } + + @Override + public void persistInstance(final InstanceEntity instance) { + + } + + @Override + public List selectInstances(final String selectKey) { + List instanceList = kubernetesClient.selectInstances(selectKey); + return instanceList.stream().map(instance -> InstanceEntity.builder() + .appName(instance.getServiceId()) + .host(instance.getHost()) + .port(instance.getPort()) + .uri(getURI(instance)) + .build()).collect(Collectors.toList()); + } + + private URI getURI(final KubernetesInstance instance) { + boolean secure = instance.isSecure(); + String scheme = secure ? "https" : "http"; + int port = instance.getPort(); + if (port <= 0) { + port = secure ? 443 : 80; + } + String uri = String.format("%s://%s:%s", scheme, instance.getHost(), port); + return URI.create(uri); + } + + @Override + public void close() { + ShenyuInstanceRegisterRepository.super.close(); + } +} diff --git a/shenyu-registry/shenyu-registry-kubernetes/src/main/resources/META-INF/shenyu/org.apache.shenyu.registry.api.ShenyuInstanceRegisterRepository b/shenyu-registry/shenyu-registry-kubernetes/src/main/resources/META-INF/shenyu/org.apache.shenyu.registry.api.ShenyuInstanceRegisterRepository new file mode 100644 index 000000000000..7e39842875af --- /dev/null +++ b/shenyu-registry/shenyu-registry-kubernetes/src/main/resources/META-INF/shenyu/org.apache.shenyu.registry.api.ShenyuInstanceRegisterRepository @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +kubernetes=org.apache.shenyu.registry.kubernetes.KubernetesInstanceRegisterRepository