Skip to content
清晨的一缕阳光
返回

Spring Boot Kubernetes 部署实战

前言

Kubernetes 是容器编排的事实标准。Spring Boot 应用可以方便地部署到 K8s 集群。本文将介绍 Spring Boot Kubernetes 部署的完整方案。

基础概念

1. K8s 架构

┌─────────────────────────────────────────┐
│           Control Plane                 │
│  ┌─────────┬─────────┬─────────────┐   │
│  │ API     │ Scheduler│ Controller  │   │
│  │ Server  │         │ Manager     │   │
│  └─────────┴─────────┴─────────────┘   │
│              │ etcd                     │
└──────────────┼──────────────────────────┘

    ┌──────────┼──────────┐
    │          │          │
┌───▼────┐ ┌───▼────┐ ┌───▼────┐
│ Node 1 │ │ Node 2 │ │ Node 3 │
│ ┌────┐ │ │ ┌────┐ │ │ ┌────┐ │
│ │Pod │ │ │ │Pod │ │ │ │Pod │ │
│ └────┘ │ │ └────┘ │ │ └────┘ │
└────────┘ └────────┘ └────────┘

2. 核心资源

资源说明用途
Pod最小调度单元运行容器
Deployment无状态应用管理 Pod
Service服务发现负载均衡
ConfigMap配置管理外部化配置
Secret敏感信息密码、证书
Ingress入口规则HTTP 路由

Deployment

1. 基础配置

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
  labels:
    app: demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
        - name: demo
          image: demo:1.0.0
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 8080
              protocol: TCP
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "prod"
            - name: JAVA_OPTS
              value: "-Xms512m -Xmx512m"
          resources:
            requests:
              memory: "512Mi"
              cpu: "250m"
            limits:
              memory: "1Gi"
              cpu: "500m"
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 3
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 3

2. 部署命令

# 创建 Deployment
kubectl apply -f deployment.yaml

# 查看状态
kubectl get deployments
kubectl get pods
kubectl get pods -l app=demo

# 查看日志
kubectl logs -f deployment/demo-app
kubectl logs -f deployment/demo-app -c demo

# 扩缩容
kubectl scale deployment demo-app --replicas=5

# 滚动更新
kubectl set image deployment/demo-app demo=demo:1.1.0

# 回滚
kubectl rollout undo deployment/demo-app

# 查看历史
kubectl rollout history deployment/demo-app

Service

1. ClusterIP(内部访问)

# service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo-service
spec:
  selector:
    app: demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

2. NodePort(外部访问)

# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo-service
spec:
  selector:
    app: demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
      nodePort: 30080
  type: NodePort

3. LoadBalancer(云厂商)

# service-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo-service
spec:
  selector:
    app: demo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer

ConfigMap 和 Secret

1. ConfigMap

# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo-config
data:
  application.yml: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://mysql:3306/demo
        username: root
      redis:
        host: redis
        port: 6379
    logging:
      level:
        com.example.demo: INFO
# 使用 ConfigMap
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
spec:
  template:
    spec:
      containers:
        - name: demo
          image: demo:1.0.0
          envFrom:
            - configMapRef:
                name: demo-config
          volumeMounts:
            - name: config
              mountPath: /app/config
      volumes:
        - name: config
          configMap:
            name: demo-config

2. Secret

# secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: demo-secret
type: Opaque
stringData:
  DB_PASSWORD: "complex-password"
  JWT_SECRET: "jwt-secret-key"
  API_KEY: "api-key-value"
# 创建 Secret
kubectl create secret generic demo-secret \
  --from-literal=DB_PASSWORD=complex-password \
  --from-literal=JWT_SECRET=jwt-secret-key
# 使用 Secret
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
spec:
  template:
    spec:
      containers:
        - name: demo
          image: demo:1.0.0
          env:
            - name: DB_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: demo-secret
                  key: DB_PASSWORD

Ingress

1. 基础 Ingress

# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
    - host: demo.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: demo-service
                port:
                  number: 80

2. TLS 配置

# ingress-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-ingress
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - demo.example.com
      secretName: demo-tls
  rules:
    - host: demo.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: demo-service
                port:
                  number: 80

自动扩缩容

1. HPA(水平扩缩容)

# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: demo-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: demo-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
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
        - type: Percent
          value: 10
          periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
        - type: Percent
          value: 100
          periodSeconds: 15
        - type: Pods
          value: 4
          periodSeconds: 15
      selectPolicy: Max

2. VPA(垂直扩缩容)

# vpa.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
  name: demo-vpa
spec:
  targetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: demo-app
  updatePolicy:
    updateMode: Auto
  resourcePolicy:
    containerPolicies:
      - containerName: demo
        minAllowed:
          cpu: 100m
          memory: 256Mi
        maxAllowed:
          cpu: 1
          memory: 2Gi

存储管理

1. PersistentVolume

# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: demo-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: standard
  hostPath:
    path: /mnt/data/demo

2. PersistentVolumeClaim

# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  storageClassName: standard
# 使用 PVC
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-app
spec:
  template:
    spec:
      containers:
        - name: demo
          image: demo:1.0.0
          volumeMounts:
            - name: data
              mountPath: /app/data
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: demo-pvc

监控和日志

1. Prometheus 监控

# service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: demo-monitor
  labels:
    release: prometheus
spec:
  selector:
    matchLabels:
      app: demo
  endpoints:
    - port: http
      path: /actuator/prometheus
      interval: 30s
  namespaceSelector:
    matchNames:
      - default

2. 日志收集

# 使用 Fluentd 收集日志
apiVersion: v1
kind: ConfigMap
metadata:
  name: fluentd-config
data:
  fluent.conf: |
    <source>
      @type tail
      path /var/log/containers/*.log
      pos_file /var/log/fluentd-containers.log.pos
      tag kubernetes.*
      <parse>
        @type json
      </parse>
    </source>
    
    <match kubernetes.**>
      @type elasticsearch
      host elasticsearch
      port 9200
      logstash_format true
      logstash_prefix kubernetes
    </match>

最佳实践

1. 资源限制

# ✅ 推荐
resources:
  requests:
    memory: "512Mi"
    cpu: "250m"
  limits:
    memory: "1Gi"
    cpu: "500m"

# ❌ 不推荐
# 不设置资源限制

2. 健康检查

# ✅ 推荐
livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

# ❌ 不推荐
# 不设置健康检查

3. 优雅关闭

# application.yml
server:
  shutdown: graceful

spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s
# Deployment 配置
spec:
  template:
    spec:
      terminationGracePeriodSeconds: 30

4. 多环境部署

# 命名空间隔离
kubectl create namespace dev
kubectl create namespace test
kubectl create namespace prod

# 不同环境使用不同配置
kubectl apply -f deployment.yaml -n dev
kubectl apply -f deployment.yaml -n prod

5. Helm Chart

# Chart.yaml
apiVersion: v2
name: demo
description: Demo Application
type: application
version: 1.0.0
appVersion: "1.0.0"
# values.yaml
replicaCount: 3
image:
  repository: demo
  tag: "1.0.0"
  pullPolicy: IfNotPresent
resources:
  requests:
    memory: "512Mi"
    cpu: "250m"
  limits:
    memory: "1Gi"
    cpu: "500m"

总结

Kubernetes 部署要点:

Kubernetes 是云原生部署的标准平台。


分享这篇文章到:

上一篇文章
Spring Boot 结构化日志与 ELK
下一篇文章
微服务监控体系