|
Note
|
This repository contains the guide documentation source. To view the guide in published form, view it on the Open Liberty website. |
Explore how to externalize configuration using MicroProfile Config and configure your microservices using Kubernetes ConfigMaps and Secrets.
You will learn how and why to externalize your microservice’s configuration. Externalized configuration is useful because configuration usually changes depending on your environment. You will also learn how to configure the environment by providing required values to your application using Kubernetes.
MicroProfile Config provides useful annotations that you can use to inject configured values into your code. These values can come from any configuration source, such as environment variables. Using environment variables allows for easier deployment to different environments. To learn more about MicroProfile Config, read the Configuring microservices guide.
Furthermore, you’ll learn how to set these environment variables with ConfigMaps and Secrets. These resources are provided by Kubernetes and act as a data source for your environment variables. You can use a ConfigMap or Secret to set environment variables for any number of containers.
The two microservices you will deploy are called system and inventory. The system microservice returns the JVM system properties of the running container. The inventory microservice adds the properties from the system microservice to the inventory. This demonstrates how communication can be established between pods inside a cluster. To build these applications, navigate to the start directory and run the following command.
cd start
mvnw.cmd clean packagecd start
./mvnw clean packagecd start
./mvnw clean packageNext, run the docker build commands to build container images for your application:
docker build -t system:1.0-SNAPSHOT system/.
docker build -t inventory:1.0-SNAPSHOT inventory/.The -t flag in the docker build command allows the Docker image to be labeled (tagged) in the name[:tag] format. The tag for an image describes the specific image version. If the optional [:tag] tag is not specified, the latest tag is created by default.
Run the following command to deploy the necessary Kubernetes resources to serve the applications.
kubectl apply -f kubernetes.yamlWhen this command finishes, wait for the pods to be in the Ready state. Run the following command to view the status of the pods.
kubectl get podsWhen the pods are ready, the output shows 1/1 for READY and Running for STATUS.
NAME READY STATUS RESTARTS AGE
system-deployment-6bd97d9bf6-6d2cj 1/1 Running 0 34s
inventory-deployment-645767664f-7gnxf 1/1 Running 0 34sAfter the pods are ready, you will make requests to your services.
The default host name for Docker Desktop is localhost.
The default host name for minikube is 192.168.99.100. Otherwise it can be found using the minikube ip command.
Navigate to http://[hostname]:31000/system/properties and use the username bob and the password bobpwd to authenticate. Replace [hostname] with the IP address or host name of your Kubernetes cluster. Open your browser’s developer console and examine the response headers.
You can also run the curl command to make requests to your microservices. Use the -u option to pass in the username bob and the password bobpwd.
curl http://localhost:31000/system/properties -u bob:bobpwdIf the curl command is unavailable, then use Postman. Postman enables you to make requests using a graphical interface. To make a request with Postman, enter http://localhost:31000/system/properties into the URL bar. Next, set the Authorization with Basic Auth type. Set the Username field to bob and the Password field to bobpwd. Read the Authorizing requests document for more details. Finally, click the blue Send button to make the request.
curl http://localhost:31000/system/properties -u bob:bobpwdcurl http://$(minikube ip):31000/system/properties -u bob:bobpwdSimilarly, navigate to http://[hostname]:32000/inventory/systems/system-service, or use the following curl command to add the system to your inventory.
curl http://localhost:32000/inventory/systems/system-servicecurl http://$(minikube ip):32000/inventory/systems/system-serviceThe system service is hardcoded to use a single forward slash as the context root. The context root is set in the webApplication
element, where the contextRoot attribute is specified as "/". You’ll make the value of the contextRoot attribute configurable by implementing it as a variable.
Replace theserver.xmlfile.system/src/main/liberty/config/server.xml
server.xml
link:finish/system/src/main/liberty/config/server.xml[role=include]The contextRoot attribute in the webApplication element now gets its value from the context.root variable. To find a value for the context.root variable, Open Liberty looks for the following environment variables, in order:
-
context.root -
context_root -
CONTEXT_ROOT
The inventory service is hardcoded to use bob and bobpwd as the credentials to authenticate against the system service. You’ll make these credentials configurable.
Replace theSystemClientclass.inventory/src/main/java/io/openliberty/guides/inventory/client/SystemClient.java
SystemClient.java
link:finish/inventory/src/main/java/io/openliberty/guides/inventory/client/SystemClient.java[role=include]The changes introduced here use MicroProfile Config and CDI to inject the value of the environment variables CONTEXT_ROOT, SYSTEM_APP_USERNAME and SYSTEM_APP_PASSWORD into the SystemClient class.
Several options exist to configure an environment variable in a Docker container. You can set it directly in the Dockerfile with the ENV command. You can also set it in your kubernetes.yaml file by specifying a name and a value for the environment variable that you want to set for a specific container. With these options in mind, you’re going to use a ConfigMap and Secret to set these values. These are resources provided by Kubernetes as a way to provide configuration values to your containers. A benefit is that they can be reused across many different containers, even if they all require different environment variables to be set with the same value.
Create a ConfigMap to configure the app name with the following kubectl command.
kubectl create configmap sys-app-root --from-literal contextRoot=/devThis command deploys a ConfigMap named sys-app-root to your cluster. It has a key called contextRoot with a value of /dev. The --from-literal flag allows you to specify individual key-value pairs to store in this ConfigMap. Other available options, such as --from-file and --from-env-file, provide more versatility as to what you want to configure. Details about these options can be found in the Kubernetes CLI documentation.
Run the following command to display details of the ConfigMap.
kubectl describe configmaps sys-app-rootCreate a Secret to configure the new credentials that inventory uses to authenticate against system with the following kubectl command.
kubectl create secret generic sys-app-credentials --from-literal username=alice --from-literal password=wonderlandThis command looks similar to the command to create a ConfigMap, but one difference is the word generic. This word creates a Secret that doesn’t store information in any specialized way. Different types of secrets are available, such as secrets to store Docker credentials and secrets to store public and private key pairs.
Run the following command to display details of the Secret.
kubectl describe secrets/sys-app-credentialsA Secret is similar to a ConfigMap. A key difference is that a Secret is used for confidential information such as credentials. One of the main differences is that you must explicitly tell kubectl to show you the contents of a Secret. Additionally, when it does show you the information, it only shows you a Base64 encoded version so that a casual onlooker doesn’t accidentally see any sensitive data. Secrets don’t provide any encryption by default, that is something you’ll either need to do yourself or find an alternate option to configure. Encryption is not required for the application to run.
kubernetes.yaml
link:finish/kubernetes.yaml[role=include]Dockerfile
link:finish/system/Dockerfile[role=include]Next, you will update your Kubernetes deployments to set the environment variables in your containers based on the values that are configured in the ConfigMap and Secret that you created previously.
Replace the kubernetes file.
kubernetes.yaml
kubernetes.yaml
link:finish/kubernetes.yaml[role=include]The CONTEXT_ROOT, SYSTEM_APP_USERNAME, and SYSTEM_APP_PASSWORD environment variables are set in the env sections of system-container and inventory-container.
Using the valueFrom field, you can specify the value of an environment variable from various sources. These sources include a ConfigMap, a Secret, and information about the cluster. In this example configMapKeyRef gets the value contextRoot from the sys-app-root ConfigMap. Similarly, secretKeyRef gets the values username and password from the sys-app-credentials Secret.
Rebuild the application using Maven clean and package goals.
https://raw.githubusercontent.com/OpenLiberty/guides-common/prod/os-tabs.adoc
mvnw.cmd clean package./mvnw clean package./mvnw clean packageRun the docker build commands to rebuild container images for your application:
docker build -t system:1.0-SNAPSHOT system/.
docker build -t inventory:1.0-SNAPSHOT inventory/.Run the following command to deploy your changes to the Kubernetes cluster.
kubectl replace --force -f kubernetes.yamlWhen this command finishes, wait for the pods to be in the Ready state. Run the following command to view the status of the pods.
kubectl get podsWhen the pods are ready, the output shows 1/1 for READY and Running for STATUS.
Your application will now be available at the http://[hostname]:31000/dev/system/properties URL. You now need to use the new username, alice, and the new password, wonderland, to log in. Alternatively, you can run the following command:
curl http://localhost:31000/dev/system/properties -u alice:wonderlandIf the curl command is unavailable, then use Postman. To make a request with Postman, enter http://localhost:31000/dev/system/properties into the URL bar. Next, set the Authorization with Basic Auth type, and set the Username field to alice and Password field to wonderland. Finally, click the blue Send button to make the request.
curl http://localhost:31000/dev/system/properties -u alice:wonderlandcurl http://$(minikube ip):31000/dev/system/properties -u alice:wonderlandNotice that the URL you are using to reach the application now has /dev as the context root.
Verify that http://[hostname]:32000/inventory/systems/system-service is working as intended. If it is not working, then check the configuration of the credentials.
Run the integration tests:
mvnw.cmd failsafe:integration-test -Dsystem.context.root=/devRun the integration tests:
./mvnw failsafe:integration-test -Dsystem.context.root=/devRun the integration tests against a cluster running at Minikube’s IP address:
./mvnw failsafe:integration-test -Dsystem.context.root=/dev -Dsystem.service.root=$(minikube ip):31000 -Dinventory.service.root=$(minikube ip):32000The tests for inventory verify that the service can communicate with system using the configured credentials. If the credentials are misconfigured, then the inventory test fails, so the inventory test indirectly verifies that the credentials are correctly configured.
After the tests succeed, you should see output similar to the following in your console.
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.system.SystemEndpointIT
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.706 s - in it.io.openliberty.guides.system.SystemEndpointIT
Results:
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running it.io.openliberty.guides.inventory.InventoryEndpointIT
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.696 s - in it.io.openliberty.guides.inventory.InventoryEndpointIT
Results:
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0Run the following commands to delete all the resources that you created.
kubectl delete -f kubernetes.yaml
kubectl delete configmap sys-app-root
kubectl delete secret sys-app-credentialsYou have used MicroProfile Config to externalize the configuration of two microservices, and then you configured them by creating a ConfigMap and Secret in your Kubernetes cluster.