Externalize Configuration to ConfigMap

We will use the Spring Cloud Kubernetes project’s PropertySource implementations to help read external configuration. We’ll need to add some dependencies to our project as well as some additional JKube resource fragments, but we won’t need to make any changes to the application’s source code.

Open the project’s pom.xml file again. We first need to add the Spring Cloud Bill of Materials to the project:

  1. In the <properties> section, add <spring-cloud.version>2021.0.5</spring-cloud.version>
    • Note: 2021.0.5 was the latest version as of the writing of this article. You can look on Maven Central for the latest version.
  2. After the <properties> section, add a new section:
    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.springframework.cloud</groupId>
          <artifactId>spring-cloud-dependencies</artifactId>
          <version>${spring-cloud.version}</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
  3. In the <dependencies>, add the kubernetes-client-config starter:
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-kubernetes-client-config</artifactId>
    </dependency>

NOTE: The completed pom.xml file containing these changes can be found on the solution branch of the repo.

As a sanity check, you could run./mvnw verify on Linux/macOS or mvnw.cmd verify on Windows to make sure everything still works.

Spring Cloud Kubernetes library needs the view role on the service account running the application in order to read other objects in the namespace. We can instruct JKube to do this for us when we deploy the application.

Add a new file, src/main/jkube/rolebinding.yml, with the following contents:

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: view
subjects:
  - kind: ServiceAccount
    name: default

Additionally, we need to deploy a ConfigMap containing the configuration into the same namespace as our application. By default, the Spring Cloud Kubernetes Config library will look for a ConfigMap in the same namespace with the same name as the application, although its configuration can be altered if needed. We can instruct JKube to do this for us as well.

Add a new file, src/main/jkube/configmap.yml, with the following contents:

data:
  hello.greeting: Hello (from Kubernetes ConfigMap)

Redeploy to minikube

In the same terminal as before, run ./mvnw k8s:deploy -Pk8s on Linux/macOS or mvnw.cmd k8s:deploy -Pk8s on Windows. This will redeploy the application.

Once it finishes, run the command minikube service list. You should see something like this:

|------------------------------|------------------------------|--------------|----------------------------|
|          NAMESPACE           |             NAME             | TARGET PORT  |            URL             |
|------------------------------|------------------------------|--------------|----------------------------|
| default                      | kubernetes                   | No node port |
| kube-system                  | kube-dns                     | No node port |
| spring-jkube-external-config | spring-jkube-external-config | http/8080    | http://192.168.205.5:30526 |
|------------------------------|------------------------------|--------------|----------------------------|

NOTE: Your ip address in the URL will most likely be different than what is shown here.

The URL column should contain a URL for your application that you can now interact with.

Interact with the endpoints again, either by opening a browser window or using the curl command from another terminal. The following table shows what the values of some of the endpoints should look like. The values for podIp, hostIp, and podName will most likely be different for you.

  • http://<your-ip>:30526/hello
    • Hello (from Kubernetes ConfigMap) World
  • http://<your-ip>:30526/hello/Yoda
    • Hello (from Kubernetes ConfigMap) Yoda
  • http://<your-ip>:30526/actuator/info
    {
      "kubernetes": {
        "nodeName": "minikube",
        "podIp": "172.17.0.3",
        "hostIp": "192.168.205.5",
        "namespace": "spring-jkube-external-config",
        "podName": "spring-jkube-external-config-85f8488d6d-5kqrp",
        "serviceAccount": "default",
        "inside": true
      }
    }
  • http://<your-ip>:30526/actuator/env/hello.greeting
    {
      "property": {
         "source": "bootstrapProperties-configmap.spring-jkube-external-config.spring-jkube-external-config",
        "value": "Hello (from Kubernetes ConfigMap)"
      }
    }

NOTE: There is most likely more data in the http://<your-ip>:30526/actuator/env/hello.greeting response. The output is trimmed for brevity.

As you can see, the value of the hello.greeting property is now being read from the ConfigMap named spring-jkube-external-config in the spring-jkube-external-config namespace. Additionally, you see that the /actuator/info endpoint now returns information about the Kubernetes environment the application is running in. The Spring Cloud Kubernetes library adds to the info actuator endpoint.

Eric Deandrea
Eric Deandrea
Sr. Principal Developer Advocate
Eric is a Sr. Principal Developer Advocate at Red Hat, focusing on Application Development technologies such as Quarkus, Spring Boot, as well as the rest of Red Hat's Runtimes portfolio. Prior to joining Red Hat, Eric spent many years in the financial services & insurance industries. Eric also enjoys contributing to various open-source projects, including Quarkus and the Spring ecosystem. Outside of work, Eric enjoys ice hockey and martial arts. He holds a black belt in Kempo Karate.