Skip to content
Merged
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,33 @@ src/
└── java/ # Test classes
```

## Docker Support

## Kubernetes/Minikube Deployment

### Prerequisites
- Minikube
- kubectl
- Docker

### Deploy to Minikube
```bash
# Create k8s directory and copy configuration files
mkdir k8s
chmod +x k8s/deploy.sh

# Deploy to Minikube
./k8s/deploy.sh

# Get application URL
minikube service spring-app --url
```

### Cleanup
```bash
kubectl delete -f k8s/
```

## Contributing

1. Fork the repository
Expand Down
26 changes: 21 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ plugins {
id 'org.springframework.boot' version '3.1.4'
id 'io.spring.dependency-management' version '1.1.3'
id 'java'
id 'org.flywaydb.flyway' version '9.22.3'
}

group = 'com.boilerplate'
Expand Down Expand Up @@ -38,15 +39,30 @@ dependencies {
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'
implementation 'org.springframework.boot:spring-boot-starter-aop'
implementation 'jakarta.validation:jakarta.validation-api:3.0.0'
implementation 'org.hibernate.validator:hibernate-validator:6.2.0.Final'
implementation 'org.glassfish:javax.el:3.0.0'
implementation 'org.springdoc:springdoc-openapi-ui:1.6.14'
implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final'
implementation 'org.glassfish:jakarta.el:4.0.2'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'
implementation 'io.swagger.core.v3:swagger-annotations:2.1.2'
implementation 'org.flywaydb:flyway-core:9.16.0'
implementation 'org.flywaydb:flyway-database-postgresql'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
}

flyway {
url = 'jdbc:postgresql://localhost:5432/boilerplate'
user = 'postgres'
password = 'postgres'
}

task createMigration {
doLast {
def migrationName = project.hasProperty('migrationName') ? project.getProperty('migrationName') : 'migration'
def timestamp = new Date().format('yyyyMMddHHmmss')
def fileName = "V${timestamp}__${migrationName}.sql"
def migrationDir = new File("${projectDir}/src/main/resources/db/migration")
migrationDir.mkdirs()
new File(migrationDir, fileName).createNewFile()
}
}
16 changes: 14 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ version: '3.8'

services:
app:
container_name: spring-boilerplate
platform: linux/arm64
build:
context: .
Expand All @@ -21,6 +22,7 @@ services:
SPRING_KAFKA_BOOTSTRAP_SERVERS: kafka:9092

postgres:
container_name: pg_master
image: postgres:16.2
ports:
- "5432:5432"
Expand All @@ -32,25 +34,35 @@ services:
- postgres_data:/var/lib/postgresql/data

redis:
container_name: redis_master
image: redis:7.0.11
command: redis-server --requirepass redis123
ports:
- "6379:6379"

zookeeper:
image: bitnami/zookeeper:3.8.0
container_name: zookeeper_master
image: bitnami/zookeeper:3.8.1
platform: linux/arm64
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
ALLOW_ANONYMOUS_LOGIN: "yes"
ports:
- "22181:2181"
healthcheck:
test: ["CMD", "nc", "-z", "localhost", "2181"]
interval: 10s
timeout: 5s
retries: 5

kafka:
container_name: kafka_master
image: bitnami/kafka:latest
platform: linux/arm64
depends_on:
- zookeeper
zookeeper:
condition: service_healthy
ports:
- "29092:29092"
environment:
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
45 changes: 45 additions & 0 deletions k8s/app-deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-app
spec:
replicas: 1
selector:
matchLabels:
app: spring-app
template:
metadata:
labels:
app: spring-app
spec:
containers:
- name: spring-app
image: spring-boot-boilerplate:latest
ports:
- containerPort: 8080
env:
- name: SPRING_DATASOURCE_URL
value: jdbc:postgresql://postgres:5432/boilerplate
- name: SPRING_REDIS_HOST
value: redis
- name: SPRING_KAFKA_BOOTSTRAP_SERVERS
value: kafka:9092
imagePullPolicy: Never
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: spring-app
spec:
selector:
app: spring-app
ports:
- port: 8080
type: LoadBalancer
27 changes: 27 additions & 0 deletions k8s/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/bin/bash

# Start Minikube if not running
minikube status || minikube start

# Build the application Docker image
eval $(minikube docker-env)
docker build -t spring-boot-boilerplate:latest .

# Create k8s resources
kubectl apply -f k8s/storage.yml
kubectl apply -f k8s/postgres-deployment.yml
kubectl apply -f k8s/redis-deployment.yml
kubectl apply -f k8s/kafka-deployment.yml
kubectl apply -f k8s/app-deployment.yml

# Wait for deployments
echo "Waiting for deployments to be ready..."
kubectl wait --for=condition=available --timeout=300s deployment/postgres
kubectl wait --for=condition=available --timeout=300s deployment/redis
kubectl wait --for=condition=available --timeout=300s deployment/zookeeper
kubectl wait --for=condition=available --timeout=300s deployment/kafka
kubectl wait --for=condition=available --timeout=300s deployment/spring-app

# Get the application URL
echo "Application URL:"
minikube service spring-app --url
75 changes: 75 additions & 0 deletions k8s/kafka-deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: zookeeper
spec:
replicas: 1
selector:
matchLabels:
app: zookeeper
template:
metadata:
labels:
app: zookeeper
spec:
containers:
- name: zookeeper
image: bitnami/zookeeper:3.8.0
ports:
- containerPort: 2181
env:
- name: ALLOW_ANONYMOUS_LOGIN
value: "yes"
---
apiVersion: v1
kind: Service
metadata:
name: zookeeper
spec:
selector:
app: zookeeper
ports:
- port: 2181
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: kafka
spec:
replicas: 1
selector:
matchLabels:
app: kafka
template:
metadata:
labels:
app: kafka
spec:
containers:
- name: kafka
image: bitnami/kafka:latest
ports:
- containerPort: 9092
env:
- name: KAFKA_BROKER_ID
value: "1"
- name: KAFKA_ZOOKEEPER_CONNECT
value: "zookeeper:2181"
- name: KAFKA_LISTENERS
value: "PLAINTEXT://:9092"
- name: KAFKA_ADVERTISED_LISTENERS
value: "PLAINTEXT://kafka:9092"
- name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
value: "1"
---
apiVersion: v1
kind: Service
metadata:
name: kafka
spec:
selector:
app: kafka
ports:
- port: 9092
type: ClusterIP
44 changes: 44 additions & 0 deletions k8s/postgres-deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16.2
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: boilerplate
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: postgres
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: postgres-pvc
---
apiVersion: v1
kind: Service
metadata:
name: postgres
spec:
selector:
app: postgres
ports:
- port: 5432
type: ClusterIP
31 changes: 31 additions & 0 deletions k8s/redis-deployment.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7.0.11
ports:
- containerPort: 6379
args: ["--requirepass", "redis123"]
---
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
selector:
app: redis
ports:
- port: 6379
type: ClusterIP
10 changes: 10 additions & 0 deletions k8s/storage.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.1.0</version>
</dependency>
Loading
Loading