Kubernetes Deployment YAML for Java Applications

This comprehensive guide covers Kubernetes deployment configurations specifically optimized for Java applications, including best practices, resource management, and production-ready configurations.

Basic Java Application Deployment

1. Simple Spring Boot Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
name: spring-boot-app
namespace: java-apps
labels:
app: spring-boot-app
version: v1
component: backend
spec:
replicas: 3
selector:
matchLabels:
app: spring-boot-app
template:
metadata:
labels:
app: spring-boot-app
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
spec:
containers:
- name: spring-boot-app
image: my-registry/java-app:1.0.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: JAVA_OPTS
value: "-Xmx512m -Xms256m -XX:+UseG1GC"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 90
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 3
startupProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 30
volumeMounts:
- name: tmp-volume
mountPath: /tmp
volumes:
- name: tmp-volume
emptyDir: {}
terminationGracePeriodSeconds: 60
---
apiVersion: v1
kind: Service
metadata:
name: spring-boot-service
namespace: java-apps
labels:
app: spring-boot-app
spec:
selector:
app: spring-boot-app
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
type: ClusterIP

Advanced Java-Specific Configurations

2. Microservices Deployment with Multiple JVM Options

apiVersion: apps/v1
kind: Deployment
metadata:
name: user-service
namespace: microservices
spec:
replicas: 2
selector:
matchLabels:
app: user-service
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: user-service
tier: backend
annotations:
sidecar.istio.io/inject: "true"
spec:
containers:
- name: user-service
image: my-registry/user-service:2.1.0
ports:
- containerPort: 8080
env:
- name: JAVA_TOOL_OPTIONS
value: >-
-Xmx1024m
-Xms512m
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:+UnlockExperimentalVMOptions
-XX:+UseContainerSupport
-Djava.security.egd=file:/dev/./urandom
-Dspring.profiles.active=kubernetes
- name: SPRING_APPLICATION_NAME
value: "user-service"
- name: MANAGEMENT_ENDPOINTS_WEB_EXPOSURE_INCLUDE
value: "health,info,metrics,prometheus"
- name: LOGGING_LEVEL_COM_EXAMPLE
value: "INFO"
resources:
requests:
memory: "768Mi"
cpu: "300m"
ephemeral-storage: "1Gi"
limits:
memory: "1536Mi"
cpu: "800m"
ephemeral-storage: "2Gi"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
httpHeaders:
- name: Custom-Header
value: "Liveness-Check"
initialDelaySeconds: 120
periodSeconds: 30
timeoutSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 45
periodSeconds: 20
timeoutSeconds: 5
startupProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 15
periodSeconds: 10
failureThreshold: 30
lifecycle:
preStop:
exec:
command: 
- /bin/sh
- -c
- |
curl -X POST http://localhost:8080/actuator/shutdown || true
sleep 30
volumeMounts:
- name: config-volume
mountPath: /app/config
- name: logs-volume
mountPath: /app/logs
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
volumes:
- name: config-volume
configMap:
name: user-service-config
- name: logs-volume
emptyDir: {}
imagePullSecrets:
- name: registry-credentials
nodeSelector:
node-type: application
tolerations:
- key: "app"
operator: "Equal"
value: "java"
effect: "NoSchedule"

3. Stateful Java Application (e.g., with Database)

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: order-processing-service
namespace: java-apps
spec:
serviceName: "order-service"
replicas: 2
selector:
matchLabels:
app: order-processing-service
template:
metadata:
labels:
app: order-processing-service
version: v2
spec:
containers:
- name: order-service
image: my-registry/order-service:3.0.0
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxRAMPercentage=75.0"
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "3Gi"
cpu: "1000m"
volumeMounts:
- name: data-volume
mountPath: /app/data
- name: temp-volume
mountPath: /tmp
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: order-data-pvc
- name: temp-volume
emptyDir: {}
volumeClaimTemplates:
- metadata:
name: order-data-pvc
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "fast-ssd"
resources:
requests:
storage: 10Gi

Complete Microservices Stack

4. Multi-Service Deployment with ConfigMaps and Secrets

---
# ConfigMap for application configuration
apiVersion: v1
kind: ConfigMap
metadata:
name: java-app-config
namespace: java-apps
data:
application.yml: |
server:
port: 8080
shutdown: graceful
spring:
datasource:
url: jdbc:postgresql://postgres-service:5432/mydb
jpa:
hibernate:
ddl-auto: validate
show-sql: false
redis:
host: redis-service
port: 6379
logging:
level:
com.example: INFO
org.hibernate.SQL: WARN
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
show-details: always
probes:
enabled: true
---
# Secret for sensitive data
apiVersion: v1
kind: Secret
metadata:
name: app-secrets
namespace: java-apps
type: Opaque
data:
database-password: cG9zdGdyZXNfcGFzc3dvcmQ=  # base64 encoded
api-key: eW91cl9hcGlfa2V5  # base64 encoded
---
# Deployment using ConfigMap and Secret
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
namespace: java-apps
spec:
replicas: 2
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
version: v1.2.0
spec:
containers:
- name: api-gateway
image: my-registry/api-gateway:1.2.0
ports:
- containerPort: 8080
env:
- name: JAVA_OPTS
value: "-Xmx1g -Xms512m -XX:+UseG1GC -Dspring.config.location=file:/app/config/application.yml"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: app-secrets
key: database-password
- name: API_KEY
valueFrom:
secretKeyRef:
name: app-secrets
key: api-key
volumeMounts:
- name: config-volume
mountPath: /app/config
readOnly: true
resources:
requests:
memory: "768Mi"
cpu: "300m"
limits:
memory: "1536Mi"
cpu: "800m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 15
volumes:
- name: config-volume
configMap:
name: java-app-config
items:
- key: application.yml
path: application.yml
---
# Service for API Gateway
apiVersion: v1
kind: Service
metadata:
name: api-gateway-service
namespace: java-apps
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
selector:
app: api-gateway
ports:
- name: http
port: 80
targetPort: 8080
protocol: TCP
type: LoadBalancer
externalTrafficPolicy: Local

Horizontal Pod Autoscaling

5. Auto-scaling Configuration for Java Apps

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: java-app-hpa
namespace: java-apps
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: spring-boot-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "500"
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 60
- type: Pods
value: 2
periodSeconds: 60
selectPolicy: Min
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 30
- type: Pods
value: 4
periodSeconds: 30
selectPolicy: Max

Job and CronJob for Batch Processing

6. Spring Batch Job Deployment

---
# CronJob for scheduled batch processing
apiVersion: batch/v1
kind: CronJob
metadata:
name: data-processor-job
namespace: java-apps
spec:
schedule: "0 2 * * *"  # Run daily at 2 AM
concurrencyPolicy: Forbid
startingDeadlineSeconds: 600
jobTemplate:
spec:
template:
spec:
containers:
- name: batch-processor
image: my-registry/batch-processor:1.0.0
env:
- name: JAVA_OPTS
value: "-Xmx2g -Xms1g -XX:+UseG1GC -Dspring.batch.job.names=dataMigrationJob"
- name: SPRING_PROFILES_ACTIVE
value: "batch,production"
resources:
requests:
memory: "2Gi"
cpu: "500m"
limits:
memory: "3Gi"
cpu: "1000m"
volumeMounts:
- name: input-data
mountPath: /app/input
- name: output-data
mountPath: /app/output
volumes:
- name: input-data
persistentVolumeClaim:
claimName: input-data-pvc
- name: output-data
persistentVolumeClaim:
claimName: output-data-pvc
restartPolicy: OnFailure
activeDeadlineSeconds: 3600  # 1 hour timeout
---
# One-time Job
apiVersion: batch/v1
kind: Job
metadata:
name: database-migration-job
namespace: java-apps
spec:
backoffLimit: 3
activeDeadlineSeconds: 1800
template:
spec:
containers:
- name: migration-job
image: my-registry/migration-service:2.1.0
env:
- name: JAVA_OPTS
value: "-Xmx1g -Xms512m -Dspring.datasource.url=jdbc:postgresql://db-host:5432/mydb"
command: ["java"]
args: 
- "-jar"
- "/app/app.jar"
- "--spring.batch.job.name=dataMigrationJob"
resources:
requests:
memory: "1Gi"
cpu: "500m"
limits:
memory: "2Gi"
cpu: "1000m"
restartPolicy: Never

Advanced Features and Best Practices

7. Pod Disruption Budget

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: java-app-pdb
namespace: java-apps
spec:
minAvailable: 2
selector:
matchLabels:
app: spring-boot-app

8. Network Policies

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: java-app-network-policy
namespace: java-apps
spec:
podSelector:
matchLabels:
app: spring-boot-app
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: frontend-namespace
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
name: database-namespace
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector:
matchLabels:
name: redis-namespace
ports:
- protocol: TCP
port: 6379

Monitoring and Observability

9. ServiceMonitor for Prometheus

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: spring-boot-monitor
namespace: java-apps
labels:
app: spring-boot-app
release: prometheus
spec:
selector:
matchLabels:
app: spring-boot-app
endpoints:
- port: http
path: /actuator/prometheus
interval: 30s
scrapeTimeout: 10s
relabelings:
- sourceLabels: [__meta_kubernetes_pod_name]
targetLabel: pod_name

Best Practices Summary

Resource Management

# Good practices for Java apps
resources:
requests:
memory: "512Mi"    # Start with reasonable requests
cpu: "250m"
limits:
memory: "1Gi"      # Set limits to prevent runaway processes
cpu: "500m"

JVM Optimization

env:
- name: JAVA_OPTS
value: >-
-Xmx512m
-Xms256m
-XX:+UseG1GC
-XX:MaxRAMPercentage=75.0
-XX:+UnlockExperimentalVMOptions
-XX:+UseContainerSupport
-Djava.security.egd=file:/dev/./urandom

Health Checks

livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 90  # Give JVM time to start
periodSeconds: 30
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 15
startupProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 30    # Allow up to 5 minutes for startup

Graceful Shutdown

terminationGracePeriodSeconds: 60
lifecycle:
preStop:
exec:
command: 
- /bin/sh
- -c
- |
# Send graceful shutdown signal to Spring Boot
curl -X POST http://localhost:8080/actuator/shutdown || true
sleep 30

These Kubernetes deployment configurations provide a solid foundation for running Java applications in production environments, with proper resource management, health monitoring, and scalability considerations specific to JVM-based applications.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper