Loadbalancer Module Using Kubernetes Java Client (#700)
Loadbalancer implementation using Kuberentes Java Client
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
This project includes Spring Cloud Load Balancer for load balancing based on Kubernetes Endpoints and provides implementation of load balancer based on Kubernetes Service.
|
||||
To include it to your project add the following dependency.
|
||||
====
|
||||
Fabric8 Implementation
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
@@ -11,6 +12,17 @@ To include it to your project add the following dependency.
|
||||
----
|
||||
====
|
||||
|
||||
====
|
||||
Kubernetes Java Client Implementation
|
||||
[source,xml]
|
||||
----
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
----
|
||||
====
|
||||
|
||||
To enable load balancing based on Kubernetes Service name use the following property. Then load balancer would try to call application using address, for example `service-a.default.svc.cluster.local`
|
||||
====
|
||||
[source]
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -90,6 +90,7 @@
|
||||
<module>spring-cloud-kubernetes-test-support</module>
|
||||
<module>spring-cloud-kubernetes-client-autoconfig</module>
|
||||
<module>spring-cloud-kubernetes-client-config</module>
|
||||
<module>spring-cloud-kubernetes-client-loadbalancer</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-autoconfig</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-config</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-discovery</module>
|
||||
@@ -99,6 +100,7 @@
|
||||
<module>spring-cloud-starter-kubernetes-fabric8-all</module>
|
||||
<module>spring-cloud-starter-kubernetes-client</module>
|
||||
<module>spring-cloud-starter-kubernetes-client-config</module>
|
||||
<module>spring-cloud-starter-kubernetes-client-loadbalancer</module>
|
||||
<module>spring-cloud-starter-kubernetes-client-all</module>
|
||||
<module>spring-cloud-kubernetes-examples</module>
|
||||
<module>spring-cloud-kubernetes-fabric8-leader</module>
|
||||
|
||||
@@ -11,11 +11,6 @@
|
||||
|
||||
<artifactId>spring-cloud-kubernetes-client-config</artifactId>
|
||||
|
||||
<properties>
|
||||
<wiremock.version>2.26.3</wiremock.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
@@ -81,7 +76,6 @@
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-jre8</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
@@ -37,8 +37,6 @@ import org.springframework.cloud.client.CommonsClientAutoConfiguration;
|
||||
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
|
||||
import org.springframework.cloud.client.discovery.simple.SimpleDiscoveryClientAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.client.KubernetesClientAutoConfiguration;
|
||||
import org.springframework.cloud.kubernetes.client.discovery.gson.EndpointsTrimmingStrategy;
|
||||
import org.springframework.cloud.kubernetes.client.discovery.gson.ServiceTrimmingStrategy;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -64,10 +62,6 @@ public class KubernetesDiscoveryClientAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public CatalogSharedInformerFactory catalogSharedInformerFactory(ApiClient apiClient) {
|
||||
apiClient.getJSON()
|
||||
.setGson(apiClient.getJSON().getGson().newBuilder()
|
||||
.addDeserializationExclusionStrategy(new ServiceTrimmingStrategy())
|
||||
.addDeserializationExclusionStrategy(new EndpointsTrimmingStrategy()).create());
|
||||
return new CatalogSharedInformerFactory();
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class KubernetesInformerDiscoveryClient implements DiscoveryClient, InitializingBean {
|
||||
|
||||
@@ -80,6 +81,10 @@ public class KubernetesInformerDiscoveryClient implements DiscoveryClient, Initi
|
||||
public List<ServiceInstance> getInstances(String serviceId) {
|
||||
Assert.notNull(serviceId, "[Assertion failed] - the object argument must not be null");
|
||||
|
||||
if (StringUtils.hasText(namespace) && !properties.isAllNamespaces()) {
|
||||
log.warn("Namespace is null or empty, this may cause issues looking up services");
|
||||
}
|
||||
|
||||
V1Service service = properties.isAllNamespaces() ? this.serviceLister.list().stream()
|
||||
.filter(svc -> serviceId.equals(svc.getMetadata().getName())).findFirst().orElse(null)
|
||||
: this.serviceLister.namespace(this.namespace).get(serviceId);
|
||||
|
||||
@@ -121,7 +121,7 @@ public class KubernetesInformerDiscoveryClientTests {
|
||||
|
||||
assertThat(discoveryClient.getInstances("test-svc-1"))
|
||||
.containsOnly(new KubernetesServiceInstance("", "test-svc-1", "2.2.2.2", 8080, new HashMap<>(), false));
|
||||
verify(kubernetesDiscoveryProperties, times(1)).isAllNamespaces();
|
||||
verify(kubernetesDiscoveryProperties, times(2)).isAllNamespaces();
|
||||
}
|
||||
|
||||
private Lister<V1Service> setupServiceLister(V1Service... services) {
|
||||
|
||||
61
spring-cloud-kubernetes-client-loadbalancer/pom.xml
Normal file
61
spring-cloud-kubernetes-client-loadbalancer/pom.xml
Normal file
@@ -0,0 +1,61 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-kubernetes-client-loadbalancer</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-discovery</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-jre8</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.ConditionalOnKubernetesEnabled;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(KubernetesLoadBalancerProperties.class)
|
||||
@ConditionalOnKubernetesEnabled
|
||||
@ConditionalOnProperty(value = "spring.cloud.kubernetes.loadbalancer.enabled", matchIfMissing = true)
|
||||
@LoadBalancerClients(defaultConfiguration = KubernetesClientLoadBalancerClientConfiguration.class)
|
||||
public class KubernetesClientLoadBalancerAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
KubernetesClientServiceInstanceMapper mapper(KubernetesLoadBalancerProperties properties,
|
||||
KubernetesDiscoveryProperties discoveryProperties) {
|
||||
return new KubernetesClientServiceInstanceMapper(properties, discoveryProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServicesListSupplier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientLoadBalancerClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(name = "spring.cloud.kubernetes.loadbalancer.mode", havingValue = "SERVICE")
|
||||
KubernetesServicesListSupplier kubernetesServicesListSupplier(Environment environment, CoreV1Api coreV1Api,
|
||||
KubernetesClientServiceInstanceMapper mapper, KubernetesDiscoveryProperties discoveryProperties,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
return new KubernetesClientServicesListSupplier(environment, mapper, discoveryProperties, coreV1Api,
|
||||
kubernetesClientProperties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMeta;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import io.kubernetes.client.openapi.models.V1ServicePort;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServiceInstanceMapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientServiceInstanceMapper implements KubernetesServiceInstanceMapper<V1Service> {
|
||||
|
||||
private KubernetesLoadBalancerProperties properties;
|
||||
|
||||
private KubernetesDiscoveryProperties discoveryProperties;
|
||||
|
||||
public KubernetesClientServiceInstanceMapper(KubernetesLoadBalancerProperties properties,
|
||||
KubernetesDiscoveryProperties discoveryProperties) {
|
||||
this.properties = properties;
|
||||
this.discoveryProperties = discoveryProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KubernetesServiceInstance map(V1Service service) {
|
||||
final V1ObjectMeta meta = service.getMetadata();
|
||||
|
||||
final List<V1ServicePort> ports = service.getSpec().getPorts();
|
||||
V1ServicePort port = null;
|
||||
if (ports.size() == 1) {
|
||||
port = ports.get(0);
|
||||
}
|
||||
else if (ports.size() > 1 && StringUtils.hasText(this.properties.getPortName())) {
|
||||
Optional<V1ServicePort> optPort = ports.stream()
|
||||
.filter(it -> properties.getPortName().endsWith(it.getName())).findAny();
|
||||
if (optPort.isPresent()) {
|
||||
port = optPort.get();
|
||||
}
|
||||
}
|
||||
if (port == null) {
|
||||
return null;
|
||||
}
|
||||
final String host = KubernetesServiceInstanceMapper.createHost(service.getMetadata().getName(),
|
||||
service.getMetadata().getNamespace(), properties.getClusterDomain());
|
||||
final boolean secure = KubernetesServiceInstanceMapper.isSecure(service.getMetadata().getLabels(),
|
||||
service.getMetadata().getAnnotations(), port.getName(), port.getPort());
|
||||
return new KubernetesServiceInstance(meta.getUid(), meta.getName(), host, port.getPort(),
|
||||
getServiceMetadata(service), secure);
|
||||
}
|
||||
|
||||
private Map<String, String> getServiceMetadata(V1Service service) {
|
||||
final Map<String, String> serviceMetadata = new HashMap<>();
|
||||
KubernetesDiscoveryProperties.Metadata metadataProps = this.discoveryProperties.getMetadata();
|
||||
if (metadataProps.isAddLabels()) {
|
||||
Map<String, String> labelMetadata = KubernetesServiceInstanceMapper
|
||||
.getMapWithPrefixedKeys(service.getMetadata().getLabels(), metadataProps.getLabelsPrefix());
|
||||
serviceMetadata.putAll(labelMetadata);
|
||||
}
|
||||
if (metadataProps.isAddAnnotations()) {
|
||||
Map<String, String> annotationMetadata = KubernetesServiceInstanceMapper.getMapWithPrefixedKeys(
|
||||
service.getMetadata().getAnnotations(), metadataProps.getAnnotationsPrefix());
|
||||
serviceMetadata.putAll(annotationMetadata);
|
||||
}
|
||||
|
||||
return serviceMetadata;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServiceInstanceMapper;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesServicesListSupplier;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class KubernetesClientServicesListSupplier extends KubernetesServicesListSupplier {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(KubernetesClientServicesListSupplier.class);
|
||||
|
||||
private CoreV1Api coreV1Api;
|
||||
|
||||
private KubernetesClientProperties kubernetesClientProperties;
|
||||
|
||||
public KubernetesClientServicesListSupplier(Environment environment, KubernetesServiceInstanceMapper mapper,
|
||||
KubernetesDiscoveryProperties discoveryProperties, CoreV1Api coreV1Api,
|
||||
KubernetesClientProperties kubernetesClientProperties) {
|
||||
super(environment, mapper, discoveryProperties);
|
||||
this.coreV1Api = coreV1Api;
|
||||
this.kubernetesClientProperties = kubernetesClientProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<List<ServiceInstance>> get() {
|
||||
LOG.info("Getting services with id " + this.getServiceId());
|
||||
List<ServiceInstance> result = new ArrayList<>();
|
||||
List<V1Service> services = null;
|
||||
try {
|
||||
if (discoveryProperties.isAllNamespaces()) {
|
||||
services = coreV1Api.listServiceForAllNamespaces(null, null, "metadata.name=" + this.getServiceId(),
|
||||
null, null, null, null, null, null).getItems();
|
||||
}
|
||||
else {
|
||||
services = coreV1Api.listNamespacedService(kubernetesClientProperties.getNamespace(), null, null, null,
|
||||
"metadata.name=" + this.getServiceId(), null, null, null, null, null).getItems();
|
||||
}
|
||||
services.forEach(service -> result.add(mapper.map(service)));
|
||||
}
|
||||
catch (ApiException e) {
|
||||
LOG.warn("Error retrieving service with name " + this.getServiceId(), e);
|
||||
}
|
||||
LOG.info("Returning services: " + result);
|
||||
return Flux.defer(() -> Flux.just(result));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.kubernetes.client.loadbalancer.KubernetesClientLoadBalancerAutoConfiguration
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.mock.http.client.MockClientHttpResponse;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = KubernetesClientLoadBalancerPodModeTests.App.class,
|
||||
properties = { "spring.cloud.kubernetes.client.namespace=default" })
|
||||
public class KubernetesClientLoadBalancerPodModeTests {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
|
||||
@Test
|
||||
public void testLoadBalancer() {
|
||||
ResponseEntity<String> map = rest.getForEntity("/servicea", String.class);
|
||||
assertThat(map.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
static class App {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(App.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiClient apiClient() {
|
||||
return new ClientBuilder().build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BlockingLoadBalancerClient blockingLoadBalancerClient() {
|
||||
BlockingLoadBalancerClient client = mock(BlockingLoadBalancerClient.class);
|
||||
try {
|
||||
ClientHttpResponse response = new MockClientHttpResponse("hello".getBytes(), HttpStatus.OK);
|
||||
when(client.execute(eq("servicea-wiremock"), any(LoadBalancerRequest.class))).thenReturn(response);
|
||||
when(client.execute(eq("servicea-wiremock"), any(ServiceInstance.class),
|
||||
any(LoadBalancerRequest.class))).thenReturn(response);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient() {
|
||||
KubernetesInformerDiscoveryClient client = mock(KubernetesInformerDiscoveryClient.class);
|
||||
ServiceInstance instance = new DefaultServiceInstance("servicea-wiremock1", "servicea-wiremock", "fake",
|
||||
8888, false);
|
||||
given(client.getInstances(eq("servicea-wiremock"))).willReturn(Collections.singletonList(instance));
|
||||
return client;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplateBuilder().build();
|
||||
}
|
||||
|
||||
@GetMapping("/servicea")
|
||||
public String greeting() {
|
||||
return restTemplate().getForObject("http://servicea-wiremock", String.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceList;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceListBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServicePortBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRequest;
|
||||
import org.springframework.cloud.kubernetes.client.discovery.KubernetesInformerDiscoveryClient;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.mock.http.client.MockClientHttpResponse;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
classes = KubernetesClientLoadBalancerServiceModeTests.App.class,
|
||||
properties = { "spring.cloud.kubernetes.loadbalancer.mode=SERVICE",
|
||||
"spring.cloud.kubernetes.client.namespace=default" })
|
||||
public class KubernetesClientLoadBalancerServiceModeTests {
|
||||
|
||||
private static final V1ServiceList SERVICE_LIST = new V1ServiceListBuilder()
|
||||
.addToItems(
|
||||
new V1ServiceBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("servicea-wiremock")
|
||||
.withNamespace("default").withResourceVersion("1").addToLabels("beta", "true")
|
||||
.addToAnnotations("org.springframework.cloud", "true").withUid("0").build())
|
||||
.withSpec(new V1ServiceSpecBuilder().withClusterIP("10.96.0.1").withSessionAffinity("None")
|
||||
.withType("ClusterIP")
|
||||
.addToPorts(new V1ServicePortBuilder().withPort(80).withName("http")
|
||||
.withProtocol("TCP").withNewTargetPort(8080).build())
|
||||
.build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate rest;
|
||||
|
||||
@Test
|
||||
public void testLoadBalancer() {
|
||||
ResponseEntity<String> map = rest.getForEntity("/servicea", String.class);
|
||||
assertThat(map.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
static class App {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(App.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiClient apiClient() {
|
||||
return new ClientBuilder().build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CoreV1Api coreV1Api() {
|
||||
CoreV1Api coreV1Api = mock(CoreV1Api.class);
|
||||
try {
|
||||
when(coreV1Api.listNamespacedService(eq("default"), eq(null), eq(null), eq(null),
|
||||
eq("metadata.name=servicea-wiremock"), eq(null), eq(null), eq(null), eq(null), eq(null)))
|
||||
.thenReturn(SERVICE_LIST);
|
||||
}
|
||||
catch (ApiException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return coreV1Api;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BlockingLoadBalancerClient blockingLoadBalancerClient() {
|
||||
BlockingLoadBalancerClient client = mock(BlockingLoadBalancerClient.class);
|
||||
try {
|
||||
ClientHttpResponse response = new MockClientHttpResponse("hello".getBytes(), HttpStatus.OK);
|
||||
when(client.execute(eq("servicea-wiremock"), any(LoadBalancerRequest.class))).thenReturn(response);
|
||||
when(client.execute(eq("servicea-wiremock"), any(ServiceInstance.class),
|
||||
any(LoadBalancerRequest.class))).thenReturn(response);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KubernetesInformerDiscoveryClient kubernetesInformerDiscoveryClient() {
|
||||
// Mock this so the real implementation does not try to connect to the K8S API
|
||||
// Server
|
||||
KubernetesInformerDiscoveryClient client = mock(KubernetesInformerDiscoveryClient.class);
|
||||
return client;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplateBuilder().build();
|
||||
}
|
||||
|
||||
@GetMapping("/servicea")
|
||||
public String greeting() {
|
||||
return restTemplate().getForObject("http://servicea-wiremock", String.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServicePortBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientServiceInstanceMapperTests {
|
||||
|
||||
@Test
|
||||
void basicMap() {
|
||||
KubernetesLoadBalancerProperties loadBalancerProperties = new KubernetesLoadBalancerProperties();
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties();
|
||||
KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper(loadBalancerProperties,
|
||||
kubernetesDiscoveryProperties);
|
||||
|
||||
V1Service service = new V1ServiceBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("database").withUid("0").withResourceVersion("0")
|
||||
.withNamespace("default").addToAnnotations("org.springframework.cloud", "true")
|
||||
.addToLabels("beta", "true").build())
|
||||
.withSpec(new V1ServiceSpecBuilder()
|
||||
.addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build()).build())
|
||||
.build();
|
||||
|
||||
KubernetesServiceInstance serviceInstance = mapper.map(service);
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("org.springframework.cloud", "true");
|
||||
metadata.put("beta", "true");
|
||||
KubernetesServiceInstance result = new KubernetesServiceInstance("0", "database",
|
||||
"database.default.svc.cluster.local", 80, metadata, false);
|
||||
assertThat(serviceInstance).isEqualTo(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
void multiportMap() {
|
||||
KubernetesLoadBalancerProperties loadBalancerProperties = new KubernetesLoadBalancerProperties();
|
||||
loadBalancerProperties.setPortName("https");
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties();
|
||||
KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper(loadBalancerProperties,
|
||||
kubernetesDiscoveryProperties);
|
||||
|
||||
V1Service service = new V1ServiceBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("database").withUid("0").withResourceVersion("0")
|
||||
.withNamespace("default").build())
|
||||
.withSpec(new V1ServiceSpecBuilder()
|
||||
.addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build(),
|
||||
new V1ServicePortBuilder().withPort(443).withName("https").build())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
KubernetesServiceInstance serviceInstance = mapper.map(service);
|
||||
KubernetesServiceInstance result = new KubernetesServiceInstance("0", "database",
|
||||
"database.default.svc.cluster.local", 443, new HashMap(), true);
|
||||
assertThat(serviceInstance).isEqualTo(result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
import com.github.tomakehurst.wiremock.client.WireMock;
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.Configuration;
|
||||
import io.kubernetes.client.openapi.JSON;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.models.V1ObjectMetaBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceList;
|
||||
import io.kubernetes.client.openapi.models.V1ServicePortBuilder;
|
||||
import io.kubernetes.client.openapi.models.V1ServiceSpecBuilder;
|
||||
import io.kubernetes.client.util.ClientBuilder;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.KubernetesClientProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
|
||||
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesServiceInstance;
|
||||
import org.springframework.cloud.kubernetes.commons.loadbalancer.KubernetesLoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.mock.env.MockEnvironment;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.get;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
|
||||
import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching;
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
class KubernetesClientServicesListSupplierTests {
|
||||
|
||||
private static final V1ServiceList SERVICE_LIST = new V1ServiceList().addItemsItem(new V1ServiceBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("service1").withNamespace("default")
|
||||
.withResourceVersion("1").addToLabels("beta", "true")
|
||||
.addToAnnotations("org.springframework.cloud", "true").withUid("0").build())
|
||||
.withSpec(new V1ServiceSpecBuilder()
|
||||
.addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build()).build())
|
||||
.build());
|
||||
|
||||
private static final V1ServiceList SERVICE_LIST_ALL_NAMESPACE = new V1ServiceList()
|
||||
.addItemsItem(new V1ServiceBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("service1").withNamespace("default")
|
||||
.withResourceVersion("1").addToLabels("beta", "true")
|
||||
.addToAnnotations("org.springframework.cloud", "true").withUid("0").build())
|
||||
.withSpec(new V1ServiceSpecBuilder()
|
||||
.addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build()).build())
|
||||
.build())
|
||||
.addItemsItem(new V1ServiceBuilder()
|
||||
.withMetadata(new V1ObjectMetaBuilder().withName("service1").withNamespace("test")
|
||||
.withResourceVersion("1").withUid("1").build())
|
||||
.withSpec(new V1ServiceSpecBuilder()
|
||||
.addToPorts(new V1ServicePortBuilder().withPort(80).withName("http").build(),
|
||||
new V1ServicePortBuilder().withPort(443).withName("https").build())
|
||||
.build())
|
||||
.build());
|
||||
|
||||
private static WireMockServer wireMockServer;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
wireMockServer = new WireMockServer(options().dynamicPort());
|
||||
|
||||
wireMockServer.start();
|
||||
WireMock.configureFor("localhost", wireMockServer.port());
|
||||
|
||||
ApiClient client = new ClientBuilder().setBasePath("http://localhost:" + wireMockServer.port()).build();
|
||||
client.setDebugging(true);
|
||||
Configuration.setDefaultApiClient(client);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
wireMockServer.stop();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void afterEach() {
|
||||
WireMock.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getList() {
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
env.setProperty(LoadBalancerClientFactory.PROPERTY_NAME, "service1");
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace("default");
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties();
|
||||
CoreV1Api coreV1Api = new CoreV1Api();
|
||||
KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper(
|
||||
new KubernetesLoadBalancerProperties(), kubernetesDiscoveryProperties);
|
||||
KubernetesClientServicesListSupplier listSupplier = new KubernetesClientServicesListSupplier(env, mapper,
|
||||
kubernetesDiscoveryProperties, coreV1Api, kubernetesClientProperties);
|
||||
|
||||
stubFor(get(urlMatching("^/api/v1/namespaces/default/services.*"))
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SERVICE_LIST))));
|
||||
|
||||
Flux<List<ServiceInstance>> instances = listSupplier.get();
|
||||
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("org.springframework.cloud", "true");
|
||||
metadata.put("beta", "true");
|
||||
KubernetesServiceInstance service1 = new KubernetesServiceInstance("0", "service1",
|
||||
"service1.default.svc.cluster.local", 80, metadata, false);
|
||||
List<ServiceInstance> services = new ArrayList<>();
|
||||
services.add(service1);
|
||||
|
||||
StepVerifier.create(instances).expectNext(services).verifyComplete();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getListAllNamespaces() {
|
||||
MockEnvironment env = new MockEnvironment();
|
||||
env.setProperty(LoadBalancerClientFactory.PROPERTY_NAME, "service1");
|
||||
KubernetesClientProperties kubernetesClientProperties = new KubernetesClientProperties();
|
||||
kubernetesClientProperties.setNamespace("default");
|
||||
KubernetesDiscoveryProperties kubernetesDiscoveryProperties = new KubernetesDiscoveryProperties();
|
||||
kubernetesDiscoveryProperties.setAllNamespaces(true);
|
||||
CoreV1Api coreV1Api = new CoreV1Api();
|
||||
KubernetesClientServiceInstanceMapper mapper = new KubernetesClientServiceInstanceMapper(
|
||||
new KubernetesLoadBalancerProperties(), kubernetesDiscoveryProperties);
|
||||
KubernetesClientServicesListSupplier listSupplier = new KubernetesClientServicesListSupplier(env, mapper,
|
||||
kubernetesDiscoveryProperties, coreV1Api, kubernetesClientProperties);
|
||||
|
||||
stubFor(get(urlMatching("^/api/v1/services.*"))
|
||||
.willReturn(aResponse().withStatus(200).withBody(new JSON().serialize(SERVICE_LIST_ALL_NAMESPACE))));
|
||||
|
||||
Flux<List<ServiceInstance>> instances = listSupplier.get();
|
||||
|
||||
Map<String, String> metadata = new HashMap<>();
|
||||
metadata.put("org.springframework.cloud", "true");
|
||||
metadata.put("beta", "true");
|
||||
KubernetesServiceInstance service1 = new KubernetesServiceInstance("0", "service1",
|
||||
"service1.default.svc.cluster.local", 80, metadata, false);
|
||||
KubernetesServiceInstance service2 = new KubernetesServiceInstance("1", "service1",
|
||||
"service1.test.svc.cluster.local", 80, new HashMap<>(), false);
|
||||
List<ServiceInstance> services = new ArrayList<>();
|
||||
services.add(service1);
|
||||
services.add(service2);
|
||||
|
||||
StepVerifier.create(instances).expectNext(services).verifyComplete();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -132,6 +132,13 @@ public class KubernetesServiceInstance implements ServiceInstance {
|
||||
&& Objects.equals(metadata, that.metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "KubernetesServiceInstance{" + "instanceId='" + instanceId + '\'' + ", serviceId='" + serviceId + '\''
|
||||
+ ", host='" + host + '\'' + ", port=" + port + ", uri=" + uri + ", secure=" + secure + ", metadata="
|
||||
+ metadata + '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(instanceId, serviceId, host, port, uri, secure, metadata);
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<istio-client.version>1.5.5</istio-client.version>
|
||||
<mockwebserver.version>0.1.2</mockwebserver.version>
|
||||
<okhttp.version>3.14.4</okhttp.version>
|
||||
<wiremock.version>2.26.3</wiremock.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -133,6 +134,13 @@
|
||||
<artifactId>spring-cloud-kubernetes-fabric8-loadbalancer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-loadbalancer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
@@ -170,6 +178,12 @@
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-loadbalancer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId>
|
||||
@@ -259,6 +273,13 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.tomakehurst</groupId>
|
||||
<artifactId>wiremock-jre8</artifactId>
|
||||
<version>${wiremock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
|
||||
@@ -24,6 +24,7 @@ ALL_INTEGRATION_PROJECTS=(
|
||||
"spring-cloud-kubernetes-core-k8s-client-it"
|
||||
"spring-cloud-kubernetes-client-config-it"
|
||||
"spring-cloud-kubernetes-configuration-watcher-it"
|
||||
"spring-cloud-kubernetes-client-loadbalancer-it"
|
||||
)
|
||||
INTEGRATION_PROJECTS=(${INTEGRATION_PROJECTS:-${ALL_INTEGRATION_PROJECTS[@]}})
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it-deployment
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
strategy: {}
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-loadbalancer-it:2.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
resources: {}
|
||||
status: {}
|
||||
@@ -0,0 +1,18 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
ports:
|
||||
- name: 80-8080
|
||||
port: 80
|
||||
protocol: TCP
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
type: ClusterIP
|
||||
status:
|
||||
loadBalancer: {}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-integration-tests</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-kubernetes-client-loadbalancer-it</artifactId>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-test-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.kubernetes</groupId>
|
||||
<artifactId>client-java-extended</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.docker-java</groupId>
|
||||
<artifactId>docker-java-transport-httpclient5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<image>
|
||||
<name>${env.IMAGE}</name>
|
||||
</image>
|
||||
<goal>build-image</goal>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>build-image</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>imagename</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>!env.IMAGE</name>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<env.IMAGE>springcloud/${project.artifactId}:${project.version}</env.IMAGE>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,19 @@
|
||||
apiVersion: skaffold/v2alpha3
|
||||
kind: Config
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
build:
|
||||
artifacts:
|
||||
- image: springcloud/spring-cloud-kubernetes-client-loadbalancer-it
|
||||
custom:
|
||||
buildCommand: "../../mvnw clean install"
|
||||
dependencies:
|
||||
paths:
|
||||
- src
|
||||
- pom.xml
|
||||
deploy:
|
||||
kubectl:
|
||||
manifests:
|
||||
- k8s/deployment-it.yaml
|
||||
- k8s/service-it.yaml
|
||||
- ../permissions.yaml
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer.it;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
|
||||
@SpringBootApplication
|
||||
@RestController
|
||||
public class KubernetesClientLoadBalancerApplicationIt {
|
||||
|
||||
@Autowired
|
||||
DiscoveryClient discoveryClient;
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(KubernetesClientLoadBalancerApplicationIt.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@LoadBalanced
|
||||
RestTemplate restTemplate() {
|
||||
return new RestTemplateBuilder().build();
|
||||
}
|
||||
|
||||
@GetMapping("/servicea")
|
||||
public Map<String, Object> greeting() {
|
||||
return restTemplate().getForObject("http://servicea-wiremock/__admin/mappings", Map.class);
|
||||
}
|
||||
|
||||
@GetMapping("/services")
|
||||
public List<String> services() {
|
||||
return discoveryClient.getServices();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
debug: true
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed 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
|
||||
*
|
||||
* https://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.springframework.cloud.kubernetes.client.loadbalancer.it;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import io.kubernetes.client.openapi.ApiClient;
|
||||
import io.kubernetes.client.openapi.ApiException;
|
||||
import io.kubernetes.client.openapi.apis.AppsV1Api;
|
||||
import io.kubernetes.client.openapi.apis.CoreV1Api;
|
||||
import io.kubernetes.client.openapi.apis.NetworkingV1beta1Api;
|
||||
import io.kubernetes.client.openapi.models.NetworkingV1beta1Ingress;
|
||||
import io.kubernetes.client.openapi.models.V1Deployment;
|
||||
import io.kubernetes.client.openapi.models.V1Service;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.client.ResponseErrorHandler;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.springframework.cloud.kubernetes.integration.tests.commons.K8SUtils.createApiClient;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public class LoadBalancerIT {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(LoadBalancerIT.class);
|
||||
|
||||
private static final String WIREMOCK_DEPLOYMENT_NAME = "servicea-wiremock-deployment";
|
||||
|
||||
private static final String WIREMOCK_APP_NAME = "servicea-wiremock";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_LOADBALANCER_DEPLOYMENT_NAME = "spring-cloud-kubernetes-client-loadbalancer-it-deployment";
|
||||
|
||||
private static final String SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME = "spring-cloud-kubernetes-client-loadbalancer-it";
|
||||
|
||||
private static final String WIREMOCK_HOST = "localhost";
|
||||
|
||||
private static final String WIREMOCK_PATH = "/wiremock";
|
||||
|
||||
private static final int WIREMOCK_PORT = 80;
|
||||
|
||||
private static final String NAMESPACE = "default";
|
||||
|
||||
private ApiClient client;
|
||||
|
||||
private CoreV1Api api;
|
||||
|
||||
private AppsV1Api appsApi;
|
||||
|
||||
private NetworkingV1beta1Api networkingApi;
|
||||
|
||||
private K8SUtils k8SUtils;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
this.client = createApiClient();
|
||||
this.api = new CoreV1Api();
|
||||
this.appsApi = new AppsV1Api();
|
||||
this.networkingApi = new NetworkingV1beta1Api();
|
||||
this.k8SUtils = new K8SUtils(api, appsApi);
|
||||
|
||||
deployWiremock();
|
||||
|
||||
// Check to make sure the wiremock deployment is ready
|
||||
k8SUtils.waitForDeployment(WIREMOCK_DEPLOYMENT_NAME, NAMESPACE);
|
||||
|
||||
// Check to see if endpoint is ready
|
||||
k8SUtils.waitForEndpointReady(WIREMOCK_APP_NAME, NAMESPACE);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadBalancerServiceMode() throws Exception {
|
||||
try {
|
||||
deployLoadbalancerServiceIt();
|
||||
testLoadBalancer();
|
||||
}
|
||||
finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadBalancerPodMode() throws Exception {
|
||||
try {
|
||||
deployLoadbalancerPodIt();
|
||||
testLoadBalancer();
|
||||
}
|
||||
finally {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup() throws ApiException {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + SPRING_CLOUD_K8S_LOADBALANCER_DEPLOYMENT_NAME, null, null, null, null, null, null,
|
||||
null, null);
|
||||
api.deleteNamespacedService(SPRING_CLOUD_K8S_LOADBALANCER_APP_NAME, NAMESPACE, null, null, null, null, null,
|
||||
null);
|
||||
networkingApi.deleteNamespacedIngress("it-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
private void testLoadBalancer() throws Exception {
|
||||
// Check to make sure the controller deployment is ready
|
||||
k8SUtils.waitForDeployment(SPRING_CLOUD_K8S_LOADBALANCER_DEPLOYMENT_NAME, NAMESPACE);
|
||||
RestTemplate rest = new RestTemplateBuilder().build();
|
||||
rest.setErrorHandler(new ResponseErrorHandler() {
|
||||
@Override
|
||||
public boolean hasError(ClientHttpResponse clientHttpResponse) throws IOException {
|
||||
LOG.warn("Received response status code: " + clientHttpResponse.getRawStatusCode());
|
||||
if (clientHttpResponse.getRawStatusCode() == 503) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleError(ClientHttpResponse clientHttpResponse) throws IOException {
|
||||
|
||||
}
|
||||
});
|
||||
// Sometimes the NGINX ingress takes a bit to catch up and realize the service is
|
||||
// available and we get a 503, we just need to wait a bit
|
||||
await().timeout(Duration.ofSeconds(60))
|
||||
.until(() -> rest.getForEntity("http://localhost:80/loadbalancer-it/servicea", String.class)
|
||||
.getStatusCode().is2xxSuccessful());
|
||||
Map<String, Object> result = rest.getForObject("http://localhost:80/loadbalancer-it/servicea", Map.class);
|
||||
assertThat(result.containsKey("mappings")).isTrue();
|
||||
assertThat(result.containsKey("meta")).isTrue();
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
appsApi.deleteCollectionNamespacedDeployment(NAMESPACE, null, null, null,
|
||||
"metadata.name=" + WIREMOCK_DEPLOYMENT_NAME, null, null, null, null, null, null, null, null);
|
||||
|
||||
api.deleteNamespacedService(WIREMOCK_APP_NAME, NAMESPACE, null, null, null, null, null, null);
|
||||
networkingApi.deleteNamespacedIngress("wiremock-ingress", NAMESPACE, null, null, null, null, null, null);
|
||||
|
||||
}
|
||||
|
||||
private void deployLoadbalancerServiceIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getLoadbalancerServiceItDeployment(), null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getLoadbalancerItService(), null, null, null);
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, getLoadbalancerItIngress(), null, null, null);
|
||||
}
|
||||
|
||||
private void deployLoadbalancerPodIt() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getLoadbalancerPodItDeployment(), null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getLoadbalancerItService(), null, null, null);
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, getLoadbalancerItIngress(), null, null, null);
|
||||
}
|
||||
|
||||
private V1Service getLoadbalancerItService() throws Exception {
|
||||
V1Service service = (V1Service) k8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-it-service.yaml");
|
||||
return service;
|
||||
}
|
||||
|
||||
private V1Deployment getLoadbalancerServiceItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) k8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-service-it-deployment.yaml");
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private V1Deployment getLoadbalancerPodItDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) k8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-service-it-deployment.yaml");
|
||||
return deployment;
|
||||
}
|
||||
|
||||
private NetworkingV1beta1Ingress getLoadbalancerItIngress() throws Exception {
|
||||
NetworkingV1beta1Ingress ingress = (NetworkingV1beta1Ingress) k8SUtils
|
||||
.readYamlFromClasspath("spring-cloud-kubernetes-client-loadbalancer-it-ingress.yaml");
|
||||
return ingress;
|
||||
}
|
||||
|
||||
private void deployWiremock() throws Exception {
|
||||
appsApi.createNamespacedDeployment(NAMESPACE, getWireockDeployment(), null, null, null);
|
||||
api.createNamespacedService(NAMESPACE, getWiremockAppService(), null, null, null);
|
||||
networkingApi.createNamespacedIngress(NAMESPACE, getWiremockIngress(), null, null, null);
|
||||
}
|
||||
|
||||
private NetworkingV1beta1Ingress getWiremockIngress() throws Exception {
|
||||
NetworkingV1beta1Ingress ingress = (NetworkingV1beta1Ingress) k8SUtils
|
||||
.readYamlFromClasspath("wiremock-ingress.yaml");
|
||||
return ingress;
|
||||
}
|
||||
|
||||
private V1Service getWiremockAppService() throws Exception {
|
||||
V1Service service = (V1Service) k8SUtils.readYamlFromClasspath("wiremock-service.yaml");
|
||||
return service;
|
||||
}
|
||||
|
||||
private V1Deployment getWireockDeployment() throws Exception {
|
||||
V1Deployment deployment = (V1Deployment) k8SUtils.readYamlFromClasspath("wiremock-deployment.yaml");
|
||||
return deployment;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: it-ingress
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /loadbalancer-it(/|$)(.*)
|
||||
backend:
|
||||
serviceName: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
servicePort: 8080
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
type: ClusterIP
|
||||
@@ -0,0 +1,31 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
env:
|
||||
- name: SPRING_CLOUD_KUBERNETES_LOADBALANCER_MODE
|
||||
value: POD
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-client-loadbalancer-it:2.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -0,0 +1,31 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: spring-cloud-kubernetes-client-loadbalancer-it-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
spec:
|
||||
serviceAccountName: spring-cloud-kubernetes-serviceaccount
|
||||
containers:
|
||||
- name: spring-cloud-kubernetes-client-loadbalancer-it
|
||||
env:
|
||||
- name: SPRING_CLOUD_KUBERNETES_LOADBALANCER_MODE
|
||||
value: SERVICE
|
||||
image: docker.io/springcloud/spring-cloud-kubernetes-client-loadbalancer-it:2.0.0-SNAPSHOT
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/readiness
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /actuator/health/liveness
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -0,0 +1,27 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: servicea-wiremock-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: servicea-wiremock
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
spec:
|
||||
containers:
|
||||
- name: servicea-wiremock
|
||||
image: rodolpheche/wiremock
|
||||
imagePullPolicy: IfNotPresent
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
port: 8080
|
||||
path: /__admin/mappings
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: wiremock-ingress
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /$2
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /wiremock(/|$)(.*)
|
||||
backend:
|
||||
serviceName: servicea-wiremock
|
||||
servicePort: 8080
|
||||
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
labels:
|
||||
app: servicea-wiremock
|
||||
name: servicea-wiremock
|
||||
spec:
|
||||
ports:
|
||||
- name: http
|
||||
port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: servicea-wiremock
|
||||
type: ClusterIP
|
||||
30
spring-cloud-starter-kubernetes-client-loadbalancer/pom.xml
Normal file
30
spring-cloud-starter-kubernetes-client-loadbalancer/pom.xml
Normal file
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-cloud-kubernetes</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-starter-kubernetes-client-loadbalancer</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-autoconfig</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-kubernetes-client-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user