Cloud Native 16 min read

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.

Coder Trainee
Coder Trainee
Coder Trainee
Deploy Spring Cloud Microservices to Production on Kubernetes – Revised Edition

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.md

3. Detailed K8s Configuration Files

3.1 Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: teaching-cloud

3.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: 5

3.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: ClusterIP

3.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: 5

3.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: ClusterIP

3.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: 80

3.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: 8083

3.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: latest

4. 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-cloud

6. 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-cloud

7. 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

dockermicroserviceskubernetesspring-cloudingresshparolling-updatedeployment-scripts
Coder Trainee
Written by

Coder Trainee

Experienced in Java and Python, we share and learn together. For submissions or collaborations, DM us.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.