Deploy Spring Cloud Microservices to Production on Kubernetes – Revised Edition
This article walks through migrating a Spring Cloud microservice suite from local Docker Compose to a production‑grade Kubernetes deployment, covering namespace setup, ConfigMaps, Secrets, service deployments, auto‑scaling, rolling updates, self‑healing, load balancing, Docker image builds, deployment scripts, common operational commands, and validation steps.
1. Goal of This Episode
The previous episode used Docker Compose for one‑click local deployment; production requires stronger capabilities: automatic scaling, rolling updates, self‑healing, and load balancing.
2. Project Structure
# spring-cloud-teaching-ep11/
├── k8s/
│ ├── namespace.yaml # Namespace definition
│ ├── configmap.yaml # ConfigMap definition
│ ├── secrets.yaml # Secrets definition
│ ├── nacos/
│ │ ├── deployment.yaml
│ │ └── service.yaml
│ ├── order-service/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── hpa.yaml
│ ├── stock-service/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── hpa.yaml
│ ├── point-service/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ └── hpa.yaml
│ ├── ingress.yaml
│ └── kustomization.yaml
├── scripts/
│ ├── deploy.sh # Deployment script
│ ├── undeploy.sh # Uninstall script
│ └── status.sh # Status check script
├── docker/
│ ├── Dockerfile
│ └── push.sh
└── README.md3. Detailed K8s Configuration Files
3.1 Namespace
apiVersion: v1
kind: Namespace
metadata:
name: teaching-cloud3.2 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: teaching-config
namespace: teaching-cloud
data:
NACOS_HOST: "nacos.teaching-cloud.svc.cluster.local"
DB_HOST: "mysql.teaching-cloud.svc.cluster.local"
SEATA_HOST: "seata-server.teaching-cloud.svc.cluster.local"
application.yml: |
spring:
cloud:
nacos:
discovery:
server-addr: nacos.teaching-cloud.svc.cluster.local:8848
datasource:
url: jdbc:mysql://mysql.teaching-cloud.svc.cluster.local:3306/order_db
username: root
password: ${DB_PASSWORD}3.3 Secrets
apiVersion: v1
kind: Secret
metadata:
name: teaching-secrets
namespace: teaching-cloud
type: Opaque
stringData:
DB_PASSWORD: "root123"
MYSQL_ROOT_PASSWORD: "root123"3.4 Nacos Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nacos
namespace: teaching-cloud
spec:
replicas: 1
selector:
matchLabels:
app: nacos
template:
metadata:
labels:
app: nacos
spec:
containers:
- name: nacos
image: nacos/nacos-server:v2.3.2
ports:
- containerPort: 8848
name: http
- containerPort: 9848
name: grpc
env:
- name: MODE
value: "standalone"
resources:
requests:
memory: "512Mi"
cpu: "250m"
limits:
memory: "1Gi"
cpu: "500m"
livenessProbe:
httpGet:
path: /nacos/actuator/health
port: 8848
initialDelaySeconds: 60
periodSeconds: 10
readinessProbe:
httpGet:
path: /nacos/actuator/health
port: 8848
initialDelaySeconds: 30
periodSeconds: 53.5 Nacos Service
apiVersion: v1
kind: Service
metadata:
name: nacos
namespace: teaching-cloud
spec:
selector:
app: nacos
ports:
- name: http
port: 8848
targetPort: 8848
- name: grpc
port: 9848
targetPort: 9848
type: ClusterIP3.6 Order‑Service Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: teaching-cloud
spec:
replicas: 2
selector:
matchLabels:
app: order-service
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-service
image: teaching/order-service:latest
imagePullPolicy: Always
ports:
- containerPort: 8081
name: http
env:
- name: SPRING_PROFILES_ACTIVE
value: "k8s"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: teaching-secrets
key: DB_PASSWORD
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8081
initialDelaySeconds: 90
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8081
initialDelaySeconds: 60
periodSeconds: 53.7 Order‑Service Service
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: teaching-cloud
spec:
selector:
app: order-service
ports:
- port: 8081
targetPort: 8081
name: http
type: ClusterIP3.8 Order‑Service HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
namespace: teaching-cloud
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 803.9 Stock‑Service Deployment (similar structure to Order‑Service)
# (omitted for brevity – same pattern with image teaching/stock-service:latest and port 8082)3.10 Stock‑Service HPA
# (omitted for brevity – same metrics as order‑service)3.11 Point‑Service Deployment (similar structure, port 8083)
# (omitted for brevity – same pattern with image teaching/point-service:latest)3.12 Point‑Service HPA
# (omitted for brevity – same metrics as order‑service)3.13 Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: teaching-ingress
namespace: teaching-cloud
annotations:
nginx.ingress.kubernetes.io/rewrite-target: "/"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: api.teaching.com
http:
paths:
- path: /api/order
pathType: Prefix
backend:
service:
name: order-service
port:
number: 8081
- path: /api/stock
pathType: Prefix
backend:
service:
name: stock-service
port:
number: 8082
- path: /api/point
pathType: Prefix
backend:
service:
name: point-service
port:
number: 80833.14 Kustomize Configuration
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: teaching-cloud
resources:
- namespace.yaml
- configmap.yaml
- secrets.yaml
- nacos/deployment.yaml
- nacos/service.yaml
- order-service/deployment.yaml
- order-service/service.yaml
- order-service/hpa.yaml
- stock-service/deployment.yaml
- stock-service/service.yaml
- stock-service/hpa.yaml
- point-service/deployment.yaml
- point-service/service.yaml
- point-service/hpa.yaml
- ingress.yaml
images:
- name: teaching/order-service
newTag: latest
- name: teaching/stock-service
newTag: latest
- name: teaching/point-service
newTag: latest4. Docker Image Build
# Dockerfile
FROM openjdk:17-jdk-slim
WORKDIR /app
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
RUN groupadd -r teaching && useradd -r -g teaching teaching
COPY target/*.jar app.jar
USER teaching
EXPOSE 8081
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseG1GC"
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"] # push.sh (build and push images)
#!/bin/bash
REGISTRY=${REGISTRY:-docker.io/teaching}
TAG=${TAG:-latest}
services=("order-service" "stock-service" "point-service")
for service in "${services[@]}"; do
echo "Building $service..."
cd ../services/$service
mvn clean package -DskipTests
docker build -t ${REGISTRY}/${service}:${TAG} -f ../../docker/Dockerfile .
docker push ${REGISTRY}/${service}:${TAG}
cd -
done
echo "✅ All images built and pushed"5. Deployment Scripts
# deploy.sh (deployment script)
#!/bin/bash
set -e
echo "🚀 Deploying to Kubernetes..."
# Ensure namespace exists
if ! kubectl get namespace teaching-cloud >/dev/null 2>&1; then
echo "Creating namespace..."
kubectl create namespace teaching-cloud
fi
# Deploy ConfigMap and Secrets
echo "Deploying ConfigMap and Secrets..."
kubectl apply -f ../k8s/configmap.yaml
kubectl apply -f ../k8s/secrets.yaml
# Deploy Nacos
echo "Deploying Nacos..."
kubectl apply -f ../k8s/nacos/deployment.yaml
kubectl apply -f ../k8s/nacos/service.yaml
# Wait for Nacos to become ready
echo "Waiting for Nacos to become ready..."
kubectl wait --for=condition=available --timeout=300s deployment/nacos -n teaching-cloud
# Deploy business services
echo "Deploying business services..."
kubectl apply -f ../k8s/order-service/deployment.yaml
kubectl apply -f ../k8s/order-service/service.yaml
kubectl apply -f ../k8s/order-service/hpa.yaml
kubectl apply -f ../k8s/stock-service/deployment.yaml
kubectl apply -f ../k8s/stock-service/service.yaml
kubectl apply -f ../k8s/stock-service/hpa.yaml
kubectl apply -f ../k8s/point-service/deployment.yaml
kubectl apply -f ../k8s/point-service/service.yaml
kubectl apply -f ../k8s/point-service/hpa.yaml
# Deploy Ingress
echo "Deploying Ingress..."
kubectl apply -f ../k8s/ingress.yaml
echo "✅ Deployment completed!"
echo "Check status:"
echo " kubectl get pods -n teaching-cloud"
echo " kubectl get svc -n teaching-cloud"
echo " kubectl get ingress -n teaching-cloud" # undeploy.sh (uninstall script)
#!/bin/bash
echo "🗑️ Uninstalling all resources..."
kubectl delete -f ../k8s/ingress.yaml --ignore-not-found
kubectl delete -f ../k8s/order-service/ --ignore-not-found
kubectl delete -f ../k8s/stock-service/ --ignore-not-found
kubectl delete -f ../k8s/point-service/ --ignore-not-found
kubectl delete -f ../k8s/nacos/ --ignore-not-found
kubectl delete -f ../k8s/configmap.yaml --ignore-not-found
kubectl delete -f ../k8s/secrets.yaml --ignore-not-found
echo "✅ Uninstall completed" # status.sh (status check script)
#!/bin/bash
echo "📊 Kubernetes cluster status"
echo "========================"
echo "Pods:"
kubectl get pods -n teaching-cloud
echo ""
echo "Services:"
kubectl get svc -n teaching-cloud
echo ""
echo "Deployments:"
kubectl get deployments -n teaching-cloud
echo ""
echo "HorizontalPodAutoscalers:"
kubectl get hpa -n teaching-cloud
echo ""
echo "Ingress:"
kubectl get ingress -n teaching-cloud6. Common Operational Commands
# View Pod logs
kubectl logs -f deployment/order-service -n teaching-cloud
# Enter container for debugging
kubectl exec -it deployment/order-service -n teaching-cloud -- /bin/sh
# Manually scale
kubectl scale deployment order-service -n teaching-cloud --replicas=5
# Rolling restart
kubectl rollout restart deployment/order-service -n teaching-cloud
# Check rolling update status
kubectl rollout status deployment/order-service -n teaching-cloud
# Roll back to previous version
kubectl rollout undo deployment/order-service -n teaching-cloud
# Port forwarding (local debugging)
kubectl port-forward service/order-service 8081:8081 -n teaching-cloud7. Validation Steps
# 1. Check Pod status
kubectl get pods -n teaching-cloud
# 2. Check services
kubectl get svc -n teaching-cloud
# 3. Port forwarding test
kubectl port-forward service/order-service 8081:8081 -n teaching-cloud &
# 4. Test API
curl -X POST http://localhost:8081/api/order/create \
-H "Content-Type: application/json" \
-d '{"userId":1,"productId":100,"quantity":2,"amount":198}'8. Next Episode Preview
Spring Cloud Microservices – Revised Edition (12): Load testing, performance bottleneck analysis, parameter tuning, and full‑series pitfall recap.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Coder Trainee
Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
