Service Foundry for Backend - Building Scalable and Resilient Cloud-Native Applications
- Introduction
- Runtime Environment of Service Foundry for Backend
- Getting Started with Service Foundry for Backend
- Load Balancing with Kubernetes Gateway and HttpRoute
- OAuth 2.0 Authentication and Authorization
- Distributed Tracing with Jaeger
- Centralized Logging with OpenSearch
- Dynamic Configuration with Spring Config Watcher
- Consolidated API Documentation with Swagger
- Scalability
- Service Discovery with Kubernetes Service
- Metrics Collection with Prometheus
- Metrics Collection with Grafana
- Helm Charts for Microservices
- Clean up Kubernetes Resources
- Conclusion

Introduction
Service Foundry for Backend is a comprehensive solution that provides a suite of tools and services for building and managing cloud-native applications. It is designed to help developers and architects create scalable, resilient, and secure backend services by leveraging modern technologies and industry best practices.
Microservices developed using Service Foundry for Backend are expected to adhere to key cloud-native architecture principles, including:
Core Cloud-Native Principles
-
Containerization: Each microservice is packaged as a container image, enabling independent deployment and scaling.
-
Centralized Configuration: Configuration settings are managed centrally, allowing updates without requiring redeployment.
-
Service Discovery: Microservices can dynamically locate and communicate with each other through service discovery mechanisms.
-
Load Balancing: Traffic is intelligently distributed across multiple instances to ensure high availability and optimal performance.
-
Centralized Logging: Logs from all microservices are aggregated in a central repository for efficient monitoring and troubleshooting.
-
Distributed Tracing: End-to-end tracing provides visibility into requests flowing through multiple microservices, helping identify performance bottlenecks and failures.
-
Metrics Collection: Key performance indicators (KPIs) are collected and monitored to assess the health and efficiency of microservices.
-
Security: Robust authentication, authorization, and encryption mechanisms ensure secure communication and protect sensitive data.
-
API Documentation: APIs are documented using OpenAPI specifications, making it easy for other services and developers to integrate.
-
Scalability: Microservices can scale horizontally, adapting to increased traffic and workload demands without downtime.
Observability Enablement
Service Foundry for Backend seamlessly integrates with Service Foundry for Observability, providing a complete observability solution for microservices. This integration enables:
-
Real-time monitoring of microservice performance and health
-
Comprehensive logging for centralized visibility and debugging
-
Distributed tracing to analyze request flows across microservices
For more details on observability enablement, refer to:
Runtime Environment of Service Foundry for Backend
The Service Foundry for Backend provides a fully integrated runtime environment designed to support scalable, secure, and observable microservices. This environment consists of several key components that ensure smooth operation, dynamic configuration, and seamless service discovery.

The runtime environment provided by 'Service Foundry for Backend' consists of the following components:
-
Observability Enablement: A comprehensive suite of tools for monitoring, logging, and distributed tracing, ensuring the health, performance, and reliability of microservices.
-
Security Server: A centralized authentication and authorization service that manages user identities, access control policies, and security tokens, ensuring secure communication between microservices.
-
API Gateway: A single entry point for all incoming requests, responsible for routing, load balancing, authentication, and authorization across microservices.
-
Spring Config Watcher: A configuration management service that continuously monitors changes in centralized configurations and dynamically updates microservices without requiring redeployment.
-
Service Discovery: A service registry that enables microservices to dynamically locate and communicate with each other, ensuring seamless interaction and scalability.
-
Kubernetes Gateway and HttpRoute: A high-performance load balancer that efficiently distributes incoming HTTP requests across multiple microservice instances to ensure high availability and fault tolerance.
This runtime environment provides a fully automated and scalable foundation for deploying and managing cloud-native microservices. Would you like to include a diagram or additional details on any specific component?
Getting Started with Service Foundry for Backend
In this section, we will create a new Spring Boot project using the Service Foundry for Backend template. This template provides a well-structured project setup with all the necessary components and configurations required to build microservices following cloud-native architecture principles.
As part of the initialization process, the following three projects will be generated: * {domain-name}-auth-server – A centralized authentication and authorization server managing user identities, access control policies, and security tokens for microservices. * {domain-name}-gateway – A centralized API gateway responsible for routing, load balancing, authentication, and authorization across microservices. * {domain-name}-resource-server-example – A sample microservice exposing REST APIs to manage resources.
Project Setup Procedure
Following the same steps as we did for Observability Enablement, we will now set up a new Spring Boot project using the Service Foundry for Backend template.
Steps to Create and Deploy Microservices
-
Create a directory (used as the project domain) for Spring Boot projects.
-
Initialize the project using the Service Foundry for Backend template.
-
Generate the project structure with pre-configured components.
-
Build the microservices locally.
-
Deploy the microservices to Kubernetes.
Project Initialization
We use Yeoman as the scaffolding tool to generate the project structure. Yeoman takes user inputs and creates the required components based on predefined templates.
$ mkdir raincity
$ yo nsa2:backend-foundry init
? Project Domain: raincity
? Base Domain: nsalexamy.com <-- your domain name
? Maven Group ID: com.company.raincity
? Base Java Package: com.company.raincity
? Azure Container Registry Name: my-acr <- your ACR name for storing Docker images
This command generates the nsa2-backend-foundry-build-config.yaml file, which stores the configuration settings provided during initialization.
For example, if you specify the values above, the following Kubernetes Gateway routes will be created: * raincity-auth-server.nsalexamy.com * raincity-gateway.nsalexamy.com
These routes allow access to the microservices using their respective domain names.
Configuration Files
The initialization process also generates: * configmap.properties – Stores non-sensitive configuration settings. * secret.properties – Stores sensitive credentials and secrets.
Both files are mounted as ConfigMaps and Secrets in the Kubernetes cluster and used to create: * raincity-configmap – Shared across all microservices for dynamic configuration. * raincity-secret – Stores sensitive data securely.
These configurations will be discussed further in the section on **Dynamic Configuration using Spring.
Generating the Project Structure
After reviewing the configurations, we generate the complete project structure using:
$ yo nsa2:backend-foundry generate
To verify the generated files:
# to see what is generated
$ tree -L 1
.
├── build-backend-foundry.sh
├── configmap.properties
├── deploy-backend-foundry.sh
├── helm-charts
├── install-postgresql.sh
├── k8s
├── nsa2-backend-foundry-build-config.yaml
├── raincity-auth-server
├── raincity-gateway
├── raincity-resource-server-example
├── secret.properties
├── undeploy-backend-foundry.sh
└── uninstall-postgresql.sh
Key Components
-
build-backend-foundry.sh – Script to build microservices and Docker images.
-
deploy-backend-foundry.sh – Script to deploy microservices to Kubernetes.
-
undeploy-backend-foundry.sh – Script to remove deployed microservices from Kubernetes.
-
uninstall-postgresql.sh – Script to uninstall PostgreSQL and clean up Persistent Volumes (PVC/PV).
-
raincity-auth-server/ – Spring Boot project for the centralized authentication server.
-
raincity-gateway/ – Spring Boot project for the configuration and API gateway.
-
raincity-resource-server-example/ – Sample Spring Boot microservice.
Build Microservices locally
To build the microservices and generate the necessary Kubernetes Helm charts, run:
$ ./build-backend-foundry.sh
Deploying Microservices to Kubernetes
I deploy the microservices to Kubernetes using the following command:
$ ./deploy-backend-foundry.sh
Deployment process
Deployment Process * The script builds Docker images and pushes them to the Azure Container Registry (ACR). * It then deploys the microservices to the Kubernetes cluster using Helm charts. * The deployment process may take a few minutes until all resources are up and running. * All Kubernetes resources will be created under the raincity namespace.
Load Balancing with Kubernetes Gateway and HttpRoute
Kubernetes Gateway, combined with HttpRoute, provides seamless load balancing and routing for microservices. During deployment, all microservices are automatically registered with the Kubernetes Gateway using HttpRoute resources, ensuring efficient traffic distribution and high availability.
For more details, refer to:

Routing and Load Balancing
During deployment, the HttpRoute resource defines routing rules for handling incoming HTTP requests. You can list the registered routes using:
$ kubectl -n raincity get httproutes
# output
NAME HOSTNAMES AGE
raincity-auth-server-route ["raincity-auth-server.nsalexamy.com"] 12h
raincity-gateway-route ["raincity-gateway.nsalexamy.com"] 12h
raincity-resource-server-example-route ["raincity-resource-server-example.nsalexamy.com"] 12h
DNS Configuration for Domain Resolution
To enable domain name resolution, add the following entries to your DNS server or /etc/hosts file:
your-k8s-gateway-ip raincity-gateway.nsalexamy.com
your-k8s-gateway-ip raincity-auth-server.nsalexamy.com
You can retrieve the Kubernetes Gateway IP address using the following command:
$ fqdn$(kubectl get gateway your-k8s-ateway -n your-gateway-namespace -o jsonpath='{.status.addresses[0].value}')
$ dig $fqdn +short
Alternatively, use:
$ nslookup $fqdn | grep Address | tail -n 1 | awk '{print $2}'
Accessing Microservices via Domain Names
Once DNS resolution is configured, you can access microservices using their domain names:
$ curl http://raincity-gateway.nsalexamy.com/actuator/health | jq
Example Response
# output
{
"status": "UP",
"groups": [
"liveness",
"readiness"
]
}
With Kubernetes Gateway and HttpRoute, microservices are efficiently load-balanced, ensuring scalability, high availability, and seamless traffic routing
OAuth 2.0 Authentication and Authorization
Authentication and authorization in Service Foundry for Backend are managed by a centralized authentication and authorization server, raincity-auth-server. This server is responsible for issuing OAuth 2.0 security tokens to authenticate and authorize requests from both microservices and clients.
How it Works
-
To access a microservice, clients must first obtain an access token from the raincity-auth-server.
-
The access token is then included in the HTTP request headers to authenticate and authorize the request.
-
If a client attempts to access a protected microservice (e.g., raincity-resource-server-example) without a valid token, they are automatically redirected to the authentication server to log in.
-
Once authenticated, an access token is issued, and the client can use it to access microservices securely.
Example Access Flow
Test URL(Accessing a Protected Resource)
http://raincity-gateway.nsalexamy.com/resource-server/hello
Redirected Login Page
http://raincity-auth-server.nsalexamy.com/login

Test Credentials
Use the following credentials to authenticate and obtain an access token:
-
Username: raincityadmin
-
Password: password

Backend For Frontend (BFF) Pattern
The Backend For Frontend (BFF) pattern is used in the microservices architecture to improve security and streamline authentication.
-
Unlike traditional approaches, the JWT token is not visible in browser developer tools (e.g., Chrome DevTools).
-
Instead, the token is securely stored in the session store of the raincity-gateway microservice, ensuring better security and session management.
By leveraging OAuth 2.0 with the BFF pattern, the Service Foundry for Backend ensures secure, scalable, and seamless authentication across microservices
Distributed Tracing with Jaeger
All microservices in Service Foundry for Backend are instrumented with Jaeger for distributed tracing. Jaeger, an open-source tracing system, helps monitor, troubleshoot, and analyze the performance of microservices-based applications.
Since we have already invoked the microservices in the previous section, their traces can be viewed in the Jaeger UI.
Analyzing Traces in Jaeger
-
Use raincity-gateway as the service name to search for traces.
-
View detailed information, including spans, logs, and tags, to analyze request flows and identify bottlenecks.
Example: Searching for Traces

Example: Viewing Request Flows
Clicking on a trace reveals in-depth details about the request lifecycle, including spans, logs, and execution timelines.

Centralized Logging with OpenSearch
For centralized log management, all microservices are integrated with OpenSearch, an open-source search and analytics engine designed for collecting, storing, and analyzing logs at scale.
Viewing Logs in OpenSearch
To inspect logs for the raincity-gateway microservice, enter the following query in the DQL search bar within the OpenSearch Dashboard:
serviceName:raincity-gateway

With Jaeger for tracing and OpenSearch for centralized logging, the Service Foundry for Backend provides deep observability, enabling efficient monitoring, troubleshooting, and performance optimization for cloud-native applications.
Dynamic Configuration with Spring Config Watcher
Spring Config Watcher enables dynamic configuration updates for microservices without requiring a restart. It continuously monitors changes in Kubernetes ConfigMaps and Secrets and automatically reloads updated configurations in the microservices.
For detailed information, see:
Configuration Structure
Each microservice has its own ConfigMap and Secret, in addition to shared configurations:
Shared Across All Microservices
-
ConfigMap: raincity-configmap
-
Secret: raincity-secret
Specific to Each Microservice (Example: raincity-gateway)
-
ConfigMap: raincity-gateway
-
Secret: raincity-gateway
Mounted Configuration Directories
Configuration settings are mounted as files in microservices under the following directories:
-
/etc/configs/common/ - common ConfigMap
-
/etc/secrets/common/ - common Secret
-
/etc/configs/app/ - microservice-specific ConfigMap
-
/etc/secrets/app/ - microservice-specific Secret

Each microservice loads configuration settings from ConfigMaps and Secrets via bootstrap.yaml:
# omitted for brevity
---
spring.config.activate.on-profile: kubernetes
spring:
config:
import:
- configtree:/etc/configs/app/
- configtree:/etc/configs/common/
- configtree:/etc/secrets/app/
- configtree:/etc/secrets/common/
spring.cloud.kubernetes:
reload:
enabled: true
monitoring-config-maps: true
monitoring-secrets: true
mode: event
config:
enabled: true
namespace: raincity
sources:
- name: raincity-configmap
- name: raincity-gateway
secrets:
enabled: true
namespace: raincity
sources:
- name: raincity-secret
- name: raincity-gateway
This configuration enables automatic reload of ConfigMap and Secret changes in the raincity namespace.
Testing Dynamic Configuration Updates
ConfigWatcherController
A REST controller (ConfigWatcherController) is provided to test dynamic configuration reloading.
@RefreshScope // Enables dynamic configuration reload
@RestController
@RequestMapping("/config-watcher")
@Slf4j
public class ConfigWatcherController {
@Value("${COMMON_PROPERTY:unknown}")
private String commonProperty;
@Value("${APP_PROPERTY:unknown}")
private String appProperty;
private final Environment env;
public ConfigWatcherController(Environment env) {
this.env = env;
}
@GetMapping("/")
public Map<String, String> getConfig() {
var config = Map.of("commonProperty", commonProperty,
"appProperty", appProperty
);
log.info("config: {}", config);
return config;
}
@GetMapping("/{name}")
public String getProperty(@PathVariable String name) {
var value = env.getProperty(name, "unknown");
log.info("property - name: {}, value: {}", name, value);
return value;
}
}
The @RefreshScope annotation ensures that the microservice automatically reloads configurations when they change.
Test the Dynamic Configuration Reload
In the raincity-configmap ConfigMap, there is a property named 'COMMON_PROPERTY' with the value 'raincity'. And each microservice’s ConfigMap, there is a property named 'APP_PROPERTY' with the value 'raincity-gateway'.
I used a web browser to access the ConfigWatcherController endpoint, because it is easy to handle JWT tokens in the browser.
Test URL:
http://raincity-gateway.nsalexamy.com/config-watcher/COMMON_PROPERTY
Before updating, fetch the COMMON_PROPERTY value from raincity-configmap:
$ kubectl -n raincity get configmap raincity-configmap -o yaml | yq .data.COMMON_PROPERTY
raincity
If calling the ConfigWatcherController endpoint, the response will be 'raincity'.

I updated the COMMON_PROPERTY value in the raincity-configmap to 'raincity-updated'.
$ kubectl -n raincity get configmap raincity-configmap -o yaml | yq .data.COMMON_PROPERTY
raincity-updated
If calling the ConfigWatcherController endpoint again, now the response will be 'raincity-updated'.

Consolidated API Documentation with Swagger
Spring Gateway provides centralized API documentation using Swagger, an open-source tool for generating interactive documentation for RESTful APIs. By aggregating API specifications from multiple microservices, the Gateway allows developers to explore and test endpoints from a single interface.
springdoc:
swagger-ui:
# omitted for brevity
enabled: true
path: /swagger-ui.html
config-url: /v3/api-docs/swagger-config
urls:
- name: gateway-service
url: /v3/api-docs
- name: resource-server
url: /resource-server/v3/api-docs
Key Configuration Points:
-
enabled: true → Activates Swagger UI
-
path: /swagger-ui.html → Defines the Swagger UI endpoint
-
urls → Lists API documentation for multiple microservices
-
/v3/api-docs → Gateway API documentation
-
/resource-server/v3/api-docs → Resource Server API documentation
-
With this setup, each microservice’s API documentation is accessible through the Gateway, making it easier to explore and test APIs in a centralized way.
Why Consolidate API Documentation in the Gateway?
-
Unified Access → Since resource servers are typically not directly accessible, hosting their API documentation in the Gateway provides a single entry point.
-
Improved Security → Ensures API documentation follows the same security policies as API access through the Gateway.
-
Simplified Development & Testing → Developers can explore APIs from multiple microservices in one place.
Swagger UI Examples
Gateway API Documentation

Resource Server API Documentation

This consolidated approach enhances API discoverability, usability, and security, making it an essential feature for microservice-based architectures.
Scalability
Scaling Microservices in Kubernetes
Microservices can be scaled dynamically using Kubernetes’ built-in scaling mechanisms, either through kubectl commands or the Kubernetes Dashboard. This ensures high availability and efficient resource utilization.
Manual Scaling with kubectl
To scale the Resource Server Example to three replicas, run the following command:
$ kubectl -n raincity scale deployment raincity-resource-server-example --replicas=3
Verifying the Number of Replicas
To confirm that the deployment has been scaled, use:
kubectl -n raincity get pods -l app.kubernetes.io/name=raincity-resource-server-example
NAME READY STATUS RESTARTS AGE
raincity-resource-server-example-75596f4d6b-jv6qr 1/1 Running 0 1m
raincity-resource-server-example-75596f4d6b-sxv9p 1/1 Running 0 15h
raincity-resource-server-example-75596f4d6b-z6m6x 1/1 Running 0 1m
Auto-Scaling with Kubernetes Horizontal Pod Autoscaler (HPA)
For automated scaling, Kubernetes provides the Horizontal Pod Autoscaler (HPA), which dynamically adjusts the number of replicas based on CPU utilization. HPA helps optimize resource usage and ensures microservices scale automatically under varying workloads.
We will cover HPA in detail in a separate article.
Service Discovery with Kubernetes Service
In Service Foundry for Backend, Kubernetes Services enable service discovery, providing stable network endpoints for microservices to communicate seamlessly. Instead of relying on dynamic pod IPs, microservices can interact using host-based service names, ensuring reliable connectivity regardless of scaling.
Within the Kubernetes cluster, microservices communicate using their service names. For example, the raincity-gateway microservice can interact with raincity-resource-server-example simply by referencing its service name, raincity-resource-server-example, irrespective of the number of running replicas.
Metrics Collection with Prometheus
Prometheus is an open-source monitoring and alerting toolkit designed to collect, store, and query metrics from microservices. It offers a powerful query language that allows you to analyze and visualize these metrics effectively.
For example, to retrieve the recent CPU utilization ratio of the raincity-resource-server-example microservice, you can use the following query:
jvm_cpu_recent_utilization_ratio{job='raincity-resource-server-example'}
You can execute this query within the Prometheus UI to visualize and analyze the collected data.

Metrics Collection with Grafana
Grafana is an open-source platform for analytics and monitoring, designed to visualize and analyze metrics from microservices. It offers a wide range of visualization options for creating dashboards and setting up alerts.
Similar to Prometheus, Grafana allows us to collect and display metrics. You can create custom dashboards to visualize key metrics and set up alerts to notify you of any issues or anomalies.

Helm Charts for Microservices
Helm charts are used to package, version, and deploy microservices on Kubernetes. Helm, a package manager for Kubernetes, streamlines the management of applications running within a Kubernetes cluster. All microservices created with ‘Service Foundry for Backend’ are packaged as Helm charts, enabling smooth and efficient deployment.
To list the Helm charts installed in the ‘raincity’ namespace, use the following command:
$ helm -n raincity list --short
raincity-auth-server
raincity-gateway
raincity-resource-server-example
Each Helm chart contains all the necessary Kubernetes resources for deploying the microservices. The charts manage the entire deployment lifecycle, simplifying the process of getting microservices up and running on Kubernetes.
Here’s an example of the Helm chart structure for the ‘raincity-gateway’ microservice:
$ tree raincity-gateway/src/main/k8s
raincity-gateway/src/main/k8s
├── Dockerfile
└── helm-chart
└── raincity-gateway
├── Chart.yaml
├── templates
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── config-watcher-configmap-kubernetes.yaml
│ ├── config-watcher-configmap.yaml
│ ├── config-watcher-secret-kubernetes.yaml
│ ├── config-watcher-secret.yaml
│ ├── deployment.yaml
│ ├── hpa.yaml
│ ├── httproute.yaml
│ ├── ingress.yaml
│ ├── role.yaml
│ ├── rolebinding.yaml
│ ├── service.yaml
│ ├── serviceaccount.yaml
│ ├── servicemonitor.yaml
│ └── tests
│ └── test-connection.yaml
└── values.yaml
This structure defines the various resources for deploying and managing the raincity-gateway service in a Kubernetes environment.
Clean up Kubernetes Resources
To remove all deployed microservices and associated resources from the Kubernetes cluster, execute the following script:
$ ./undeploy-backend-foundry.sh
This script uninstalls all Helm releases and deletes ConfigMaps, Secrets, and other related resources:
configmap "raincity-configmap" deleted configmap "raincity-configmap-kubernetes" deleted secret "raincity-secret" deleted secret "raincity-secret-kubernetes" deleted configmap "raincity-observability-configmap" deleted Uninstalling Spring K8s Config Watcher service "spring-cloud-kubernetes-configuration-watcher" deleted serviceaccount "spring-cloud-kubernetes-configuration-watcher" deleted rolebinding.rbac.authorization.k8s.io "spring-cloud-kubernetes-configuration-watcher:view" deleted role.rbac.authorization.k8s.io "namespace-reader" deleted deployment.apps "spring-cloud-kubernetes-configuration-watcher-deployment" deleted Uninstalling previous auth-server release "raincity-auth-server" uninstalled Uninstalling previous gateway release "raincity-gateway" uninstalled Uninstalling previous raincity-resource-server-example release "raincity-resource-server-example" uninstalled
The script removes all microservices and their dependencies; however, it does not delete Persistent Volume Claims (PVCs) and Persistent Volumes (PVs) used by PostgreSQL. To remove PostgreSQL resources, run:
$ uninstall-postgresql.sh
Additionally, the raincity namespace must be deleted manually. Before proceeding, ensure that you have reviewed and backed up any necessary data. To delete the namespace, use the following command:
$ kubectl delete namespace raincity
Conclusion
In conclusion, Service Foundry for Backend is a comprehensive, cloud-native solution designed to streamline the development, deployment, and management of microservices. By leveraging Kubernetes and a set of powerful tools, Service Foundry enables organizations to build scalable, resilient, and highly observable applications. Through integrations with essential technologies such as OpenTelemetry, Jaeger, Prometheus, Grafana, and Spring Config Watcher, Service Foundry offers a robust infrastructure for real-time monitoring, centralized logging, and dynamic configuration management.
With the flexibility of Helm charts and Kubernetes’ native scaling features, developers can ensure the seamless operation of microservices in production environments, while the centralized OAuth 2.0 authentication and API Gateway provide enhanced security and streamlined API management. By adopting Service Foundry for Backend, organizations can accelerate development cycles, improve operational efficiency, and provide a consistent and reliable experience for users.
In an ever-evolving technological landscape, Service Foundry for Backend represents a solid foundation for teams looking to implement cloud-native applications that are scalable, secure, and efficient.
All my LinkedIn articles are available at My LinkedIn Article Library.
Internal links: docs/service-foundry/03.backend-foundry/index.adoc