Skip to content

Commit 5164a85

Browse files
committed
Add example for SC LoadBalancer.
1 parent 07a8748 commit 5164a85

File tree

25 files changed

+1879
-3
lines changed

25 files changed

+1879
-3
lines changed

spring-cloud-kubernetes-core/src/test/java/org/springframework/cloud/kubernetes/KubernetesAutoConfigurationTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@
3333
import static org.assertj.core.api.Assertions.assertThat;
3434

3535
@RunWith(SpringRunner.class)
36-
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = App.class, properties = {
37-
"spring.cloud.kubernetes.client.password=mypassword",
38-
"spring.cloud.kubernetes.client.proxy-password=myproxypassword" })
36+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
37+
classes = App.class,
38+
properties = { "spring.cloud.kubernetes.client.password=mypassword",
39+
"spring.cloud.kubernetes.client.proxy-password=myproxypassword" })
3940
public class KubernetesAutoConfigurationTests {
4041

4142
@ClassRule
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
## Kubernetes Spring Cloud LoadBalancer Example
2+
3+
This example demonstrates how to use [Spring Cloud LoadBalancer](https://github.com/spring-cloud-incubator/spring-cloud-loadbalancer). In our example the REST `greeting service` calls the `name service`.
4+
As the Spring Cloud LoadBalancer for Kubernetes is configured within this example, it will fetch from the Kubernetes API Server the list of the endpoints available for the name service and load-balance the request between the IP addresses available.
5+
6+
### Running the example
7+
8+
This project example runs on ALL the Kubernetes or OpenShift environments, but for development purposes you can use [Minikube - Kubernetes](https://kubernetes.io/docs/getting-started-guides/minikube/) tool
9+
to install the platform locally within a virtual machine managed by VirtualBox, Xhyve or KVM, with no fuss.
10+
11+
IMPORTANT: In order for this setup to work, you need to grant permissions to retrieve "pods", "services" and "enpoints" to the serviceaccont that will be used with the greeting-service.
12+
13+
### Build/Deploy using Minikube
14+
15+
First, create a new virtual machine provisioned with Kubernetes on your laptop using the command `minikube start`.
16+
17+
Next, you can compile your project and generate the Kubernetes resources (yaml files containing the definition of the pod, deployment, build, service and route to be created)
18+
like also to deploy the application on Kubernetes in one maven line by running the following command one by one in both `greeting-service` and `name-service`
19+
20+
```
21+
./mvnw clean install fabric8:deploy -Dfabric8.generator.from=fabric8/java-jboss-openjdk8-jdk -Pkubernetes
22+
```
23+
24+
### Call the Greeting service
25+
26+
When maven has finished to compile the code but also to call the platform in order to deploy the yaml files generated and tell to the platform to start the process
27+
to build/deploy the docker image and create the containers where the Spring Boot application will run 'greeting-service" and "name-service", you will be able to
28+
check if the pods have been created using this command :
29+
30+
```
31+
kc get pods
32+
```
33+
34+
If the status of the Spring Boot pod application is `running` and ready state `1`, then you can
35+
get the external address IP/Hostname to be used to call the service from your laptop
36+
37+
```
38+
minikube service --url greeting-service
39+
```
40+
41+
and then call the service using the curl client
42+
43+
```
44+
curl https://IP_OR_HOSTNAME/greeting
45+
```
46+
47+
to get a response as such
48+
49+
```
50+
Hello from name-service-1-0dzb4!d
51+
```
52+
53+
### Verify the load balancing
54+
55+
First, scale the number of pods of the `name service` to 2
56+
57+
```
58+
kc scale --replicas=2 deployment name-service
59+
```
60+
61+
Wait a few minutes before to issue the curl request to call the Greeting Service to let the platform to create the new pod.
62+
63+
```
64+
kc get pods --selector=project=name-service
65+
NAME READY STATUS RESTARTS AGE
66+
name-service-1652024859-fsnfw 1/1 Running 0 33s
67+
name-service-1652024859-wrzjs 1/1 Running 0 6m
68+
```
69+
70+
If you issue the curl request to access the greeting service, you should see that the message response
71+
contains a different id end of the message which corresponds to the name of the pod.
72+
73+
```
74+
Hello from name-service-1-0ss0r!
75+
```
76+
77+
As Spring Cloud LoadBalancer will question the Kubernetes API to get, base on the `name-service` name, the list of IP Addresses assigned to the service as endpoints,
78+
you should see that you will get a response from one of the 2 pods running
79+
80+
```
81+
kc get endpoints/name-service
82+
NAME ENDPOINTS AGE
83+
name-service 172.17.0.5:8080,172.17.0.6:8080 40m
84+
```
85+
86+
Here is an example about what you will get
87+
88+
```
89+
curl https://IP_OR_HOSTNAME/greeting
90+
Hello from name-service-1652024859-hf3xv!
91+
curl https://IP_OR_HOSTNAME/greeting
92+
Hello from name-service-1652024859-426kv!
93+
...
94+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
* Copyright 2007-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
import java.net.*;
17+
import java.io.*;
18+
import java.nio.channels.*;
19+
import java.util.Properties;
20+
21+
public class MavenWrapperDownloader {
22+
23+
private static final String WRAPPER_VERSION = "0.5.5";
24+
/**
25+
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
26+
*/
27+
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
28+
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
29+
30+
/**
31+
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
32+
* use instead of the default one.
33+
*/
34+
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
35+
".mvn/wrapper/maven-wrapper.properties";
36+
37+
/**
38+
* Path where the maven-wrapper.jar will be saved to.
39+
*/
40+
private static final String MAVEN_WRAPPER_JAR_PATH =
41+
".mvn/wrapper/maven-wrapper.jar";
42+
43+
/**
44+
* Name of the property which should be used to override the default download url for the wrapper.
45+
*/
46+
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
47+
48+
public static void main(String args[]) {
49+
System.out.println("- Downloader started");
50+
File baseDirectory = new File(args[0]);
51+
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
52+
53+
// If the maven-wrapper.properties exists, read it and check if it contains a custom
54+
// wrapperUrl parameter.
55+
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
56+
String url = DEFAULT_DOWNLOAD_URL;
57+
if(mavenWrapperPropertyFile.exists()) {
58+
FileInputStream mavenWrapperPropertyFileInputStream = null;
59+
try {
60+
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
61+
Properties mavenWrapperProperties = new Properties();
62+
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
63+
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
64+
} catch (IOException e) {
65+
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
66+
} finally {
67+
try {
68+
if(mavenWrapperPropertyFileInputStream != null) {
69+
mavenWrapperPropertyFileInputStream.close();
70+
}
71+
} catch (IOException e) {
72+
// Ignore ...
73+
}
74+
}
75+
}
76+
System.out.println("- Downloading from: " + url);
77+
78+
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
79+
if(!outputFile.getParentFile().exists()) {
80+
if(!outputFile.getParentFile().mkdirs()) {
81+
System.out.println(
82+
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
83+
}
84+
}
85+
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
86+
try {
87+
downloadFileFromURL(url, outputFile);
88+
System.out.println("Done");
89+
System.exit(0);
90+
} catch (Throwable e) {
91+
System.out.println("- Error downloading");
92+
e.printStackTrace();
93+
System.exit(1);
94+
}
95+
}
96+
97+
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
98+
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
99+
String username = System.getenv("MVNW_USERNAME");
100+
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
101+
Authenticator.setDefault(new Authenticator() {
102+
@Override
103+
protected PasswordAuthentication getPasswordAuthentication() {
104+
return new PasswordAuthentication(username, password);
105+
}
106+
});
107+
}
108+
URL website = new URL(urlString);
109+
ReadableByteChannel rbc;
110+
rbc = Channels.newChannel(website.openStream());
111+
FileOutputStream fos = new FileOutputStream(destination);
112+
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
113+
fos.close();
114+
rbc.close();
115+
}
116+
117+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.1/apache-maven-3.6.1-bin.zip
2+
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar

0 commit comments

Comments
 (0)