Spring Boot & Kubernetes
Spring Boot integrates with Spring Cloud Kubernetes and Spring Cloud Kubernetes Config to make instances of ConfigMaps
available at runtime to be injected as any other Spring Boot configuration property.
Spring Cloud Kubernetes Config
Registering
Let’s register the Spring Cloud Kubernetes Config dependency in the build tool:
Open pom.xml
file and add the following dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
<version>2.1.4</version>
</dependency>
Code
Then let’s create a Java class that reads Spring Boot config properties:
package org.acme.hellokubernetes;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration (1)
@ConfigurationProperties(prefix = "greeting") (2)
public class HelloConfig {
private String message; (3)
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
1 | Sets this POJO as configuration class |
2 | Sets the prefix of the properties (greeting ) |
3 | Sets the property name (message ) |
So any property value set in the application.properties
with key greeting.message
will be injected in the message
field.
Create a new endpoint in the HelloController
class that uses this class:
@Autowired
private HelloConfig helloConfig;
@GetMapping("/greeting/{name}")
public String greeting(@PathVariable("name") String name) {
return helloConfig.getMessage() + " " + name;
}
Configuration
But since we are in Kubernetes, instead of set this property in application.properties
, let’s set it in a ConfigMap
:
apiVersion: v1
kind: ConfigMap
metadata:
name: hello-kubernetes (1)
data: (2)
application.properties: |-
greeting.message: Aloha
1 | ConfigMap name should be the same as spring application name by default. |
2 | Creates an application.properties entry in the ConfigMap to be appended in application.properties set in the project. |
Then we need to configure the Spring Cloud Kubernetes Config setting the name of ConfigMaps
to load during bootstrap or the namespace where the ConfigMaps
are placed:
spring.application.name=hello-kubernetes (1)
spring.cloud.kubernetes.config.name=hello-kubernetes (2)
spring.cloud.kubernetes.config.namespace=default (3)
spring.cloud.kubernetes.config.sources[0].name=hello-kubernetes (4)
spring.cloud.kubernetes.config.enabled=true
1 | By default ConfigMap must be named with the name of the Spring application. |
2 | Sets the ConfigMap name to look up. |
3 | Sets the namespace where ConfigMap is deployed. |
4 | In the case of multiple ConfigMaps you can set them using sources array. |
The last step before deploying the application is to configure a ServiceAccount
with the correct Kubernetes Roles so Spring Cloud Kubernetes Config can query the ConfigMap
content using the Kubernetes API.
Let’s use one of the features of JKube, that let you define fragments of Kubernetes objects and Jkube will merge all of them during generation phase.
Create a new directory at src/main/jkube
and place the following files:
A fragment of a Deployment file that sets the number of replicas and the service account to run the application. JKube will automatically merge these properties with the autogenerated deployment file.
spec:
replicas: 1
template:
spec:
serviceAccount: spring-boot
Then create another file that creates the service account:
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: spring-boot
The definition of the role binding:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: spring-boot-view
roleRef:
kind: Role
apiGroup: rbac.authorization.k8s.io
name: spring-boot-view
subjects:
- kind: ServiceAccount
name: spring-boot
And finally the role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: spring-boot-view
rules:
- apiGroups: [""]
resources: ["pods","configmaps", "services"]
verbs: ["get", "watch", "list"]
Deploying
Before deplpoying the application, we need to crete the ConfigMap
in the Kubernetes cluster:
kubectl apply -f src/main/resources/k8s/hello-kube-cm.yaml -n default
configmap/hello-kubernetes created
And we can now create the container image and deploy it to the cluster.
Create and push the container image of the application:
./mvnw clean package k8s:build k8s:push -DskipTests
Generate the resources:
./mvnw k8s:resource
And finally deploy the application:
kubectl apply -f target/classes/META-INF/jkube/kubernetes.yml -n default
kubectl get pods
NAME READY STATUS RESTARTS AGE
hello-kubernetes-96c8574d6-cnbsp 1/1 Running 0 18s
Then port forward the service so it’s accessible from localhost.
kubectl port-forward -n default hello-kubernetes-96c8574d6-cnbsp 8080:8080
serviceaccount/spring-boot created
service/hello-kubernetes created
role.rbac.authorization.k8s.io/spring-boot-view created
rolebinding.rbac.authorization.k8s.io/spring-boot-view created
deployment.apps/hello-kubernetes created
Finally we can curl
the service:
curl localhost:8080/greeting/alex
Aloha alex