Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions API-Gateway/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
Expand Down
6 changes: 6 additions & 0 deletions API-Gateway/src/main/resources/bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
spring:
application:
name: api-gateway
cloud:
config:
uri: http://localhost:8888
4 changes: 4 additions & 0 deletions Account-Service/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
Expand Down
6 changes: 6 additions & 0 deletions Account-Service/src/main/resources/bootstrap.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
spring:
application:
name: account-service
cloud:
config:
uri: http://localhost:8888
7 changes: 7 additions & 0 deletions Config-Server/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM openjdk:17-jdk

COPY target/configserver-0.0.1-SNAPSHOT.jar .

EXPOSE 8888

ENTRYPOINT ["java", "-jar", "configserver-0.0.1-SNAPSHOT.jar"]
148 changes: 148 additions & 0 deletions Config-Server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Config Server

## 🚀 Introduction
The Config Server is a critical component in a microservices architecture, responsible for centralized configuration management. It allows microservices to externalize their configuration and retrieve it from a central location at runtime.

## 📚 Table of Contents
- [📂 Project Structure](#-project-structure)
- [🛠️ Technologies Used](#-technologies-used)
- [🌱 Spring Boot](#spring-boot)
- [☁️ Spring Cloud Config](#spring-cloud-config)
- [🔗 API Endpoints](#api-endpoints)
- [⚠️ Error Handling](#error-handling)
- [🔒 Security](#security)
- [⚙️ Configuration](#configuration)
- [📈 Monitoring](#monitoring)
- [📝 Logging](#logging)
- [🧪 Testing](#testing)
- [🚀 Build and Deployment](#build-and-deployment)

## 📂 Project Structure
The project structure of the Config Server is as follows:
```
Config-Server
├── src
│ ├── main
│ │ ├── java
│ │ │ └── org
│ │ │ └── training
│ │ │ └── config
│ │ │ └── server
│ │ │ └── ConfigServerApplication.java
│ │ └── resources
│ │ ├── application.yml
│ │ └── config
│ │ ├── service-registry.yml
│ │ ├── api-gateway.yml
│ │ ├── user-service.yml
│ │ ├── account-service.yml
│ │ ├── fund-transfer-service.yml
│ │ ├── transaction-service.yml
│ │ └── sequence-generator.yml
├── .gitignore
├── Dockerfile
├── pom.xml
└── README.md
```

## 🛠️ Technologies Used

### 🌱 Spring Boot
Spring Boot is used to create stand-alone, production-grade Spring-based applications. It simplifies the configuration and deployment process by providing a set of default configurations and a wide range of features such as embedded servers, security, and monitoring.

### ☁️ Spring Cloud Config
Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server, you have a central place to manage external properties for applications across all environments.

## 🔗 API Endpoints
The Config Server exposes the following endpoints:

- `GET /{application}/{profile}[/{label}]` - Retrieve configuration for a specific application and profile
- `GET /{application}-{profile}.yml` - Retrieve configuration as YAML
- `GET /{application}-{profile}.properties` - Retrieve configuration as properties
- `GET /{label}/{application}-{profile}.yml` - Retrieve configuration from a specific label (branch/tag)

Example: `GET http://localhost:8888/user-service/default` retrieves the configuration for user-service.

## ⚠️ Error Handling
The Config Server uses standard HTTP status codes to indicate the success or failure of requests. Common status codes include:
- `200 OK` - The request was successful.
- `400 Bad Request` - The request was invalid or cannot be served.
- `404 Not Found` - The requested configuration was not found.
- `500 Internal Server Error` - An error occurred on the server.

## 🔒 Security
The Config Server can be secured using Spring Security. Authentication and authorization can be configured to protect the configuration endpoints and ensure only authorized services can access configurations.

## ⚙️ Configuration
The Config Server is configured to use the native profile, which stores configuration files in the classpath under `/config` directory. Each microservice has its own configuration file named `{service-name}.yml`.

### Centralized Configurations
The Config Server manages configurations for the following services:
- **Service Registry** (service-registry.yml) - Port 8761
- **API Gateway** (api-gateway.yml) - Port 8080
- **User Service** (user-service.yml) - Port 8082
- **Account Service** (account-service.yml) - Port 8081
- **Fund Transfer Service** (fund-transfer-service.yml) - Port 8085
- **Transaction Service** (transaction-service.yml) - Port 8084
- **Sequence Generator** (sequence-generator.yml) - Port 8083

### Environment Variable Support
All database configurations support environment variable substitution:
- `MYSQL_HOST` (default: localhost)
- `MYSQL_PORT` (default: 3306)
- `MYSQL_DB_NAME` (default: service-specific database name)
- `MYSQL_USER` (default: root)
- `MYSQL_PASSWORD` (default: root)

## 📈 Monitoring
Spring Boot Actuator is used for monitoring and managing the application. It provides various endpoints to check the health, metrics, and other operational information of the service.

## 📝 Logging
Logging is configured using Logback, which is the default logging framework in Spring Boot. It provides powerful and flexible logging capabilities.

## 🧪 Testing
JUnit and Mockito are used for unit and integration testing. These frameworks provide a comprehensive set of tools for writing and running tests.

## 🚀 Build and Deployment

### Building the Project
```bash
cd Config-Server
mvn clean install
```

### Running Locally
```bash
mvn spring-boot:run
```

The Config Server will start on port 8888.

### Startup Sequence
The recommended startup sequence for the microservices architecture is:
1. **Service Registry** (port 8761) - Must start first for service discovery
2. **Config Server** (port 8888) - Starts second to provide centralized configuration
3. **Other services** - Can start in any order, they will connect to Config Server via bootstrap.yml

### Docker Deployment
The service can be packaged as a Docker container for deployment in a containerized environment.

```bash
mvn clean package -DskipTests
docker build -t config-server .
docker run -p 8888:8888 config-server
```

## 📖 Usage by Client Services
Client services connect to the Config Server by adding the `spring-cloud-starter-config` dependency and creating a `bootstrap.yml` file with the Config Server URL:

```yaml
spring:
application:
name: {service-name}
cloud:
config:
uri: http://localhost:8888
```

Client services will automatically fetch their configuration from the Config Server on startup based on their application name.
60 changes: 60 additions & 0 deletions Config-Server/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/>
</parent>
<groupId>org.training</groupId>
<artifactId>configserver</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Config Server</name>
<description>Config Server</description>
<properties>
<java.version>17</java.version>
<spring-cloud.version>2021.0.8</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<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>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.training.config.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}

}
13 changes: 13 additions & 0 deletions Config-Server/src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
server:
port: 8888

spring:
application:
name: config-server
profiles:
active: native
cloud:
config:
server:
native:
search-locations: classpath:/config
23 changes: 23 additions & 0 deletions Config-Server/src/main/resources/config/account-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
server:
port: 8081

spring:
application:
name: account-service
bad_request: 400
conflict: 409
ok: 200
not_found: 404

datasource:
url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${MYSQL_DB_NAME:account_service}
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:root}

jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
68 changes: 68 additions & 0 deletions Config-Server/src/main/resources/config/api-gateway.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
server:
port: 8080

app:
config:
keycloak:
url: http://localhost:8571/
realm: banking-service

eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka

spring:
application:
name: api-gateway

cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
- id: fund-transfer-service
uri: lb://fund-transfer-service
predicates:
- Path=/api/fund-transfers/**
- id: account-service
uri: lb://account-service
predicates:
- Path=/accounts/**
- id: sequence-generator
uri: lb://sequence-generator
predicates:
- Path=/sequence/**
- id: transaction-service
uri: lb://transaction-service
predicates:
- Path=/transactions/**
- id: fund-transfer-service-direct
uri: lb://fund-transfer-service
predicates:
- Path=/fund-transfers/**

security:
oauth2:
client:
provider:
keycloak:
token-uri: ${app.config.keycloak.url}/realms/${app.config.keycloak.realm}/protocol/openid-connect/token
authorization-uri: ${app.config.keycloak.url}/realms/${app.config.keycloak.realm}/protocol/openid-connect/auth
user-name-attribute: preferred_username
user-info-uri: ${app.config.keycloak.url}/realms/${app.config.keycloak.realm}/protocol/openid-connect/userinfo
jwk-set-uri: ${app.config.keycloak.url}/realms/${app.config.keycloak.realm}/protocol/openid-connect/certs
user-info-authentication-method: header
registration:
banking-service-client:
provider: keycloak
client-id: banking-service-client
client-secret: ${KEYCLOAK_CLIENT_SECRET}
authorization-grant-type: authorization_code
redirect-uri: http://localhost:8571/login/oauth2/code/keycloak
scope: openid
resourceserver:
jwt:
jwk-set-uri: ${app.config.keycloak.url}/realms/${app.config.keycloak.realm}/protocol/openid-connect/certs
21 changes: 21 additions & 0 deletions Config-Server/src/main/resources/config/fund-transfer-service.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
server:
port: 8085

spring:
application:
name: fund-transfer-service
bad_request: 400
ok: 200

datasource:
url: jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/${MYSQL_DB_NAME:fund_transfer_service}
username: ${MYSQL_USER:root}
password: ${MYSQL_PASSWORD:root}

jpa:
hibernate:
ddl-auto: update
show-sql: true
properties:
hibernate:
format_sql: true
Loading