Kubernetes 部署 Spring Boot 全指南
引言
隨著容器化技術(shù)和云原生架構(gòu)的普及,將Spring Boot應(yīng)用部署到K8s已成為企業(yè)級(jí)應(yīng)用的標(biāo)準(zhǔn)實(shí)踐。這種部署方式不僅能實(shí)現(xiàn)應(yīng)用的快速擴(kuò)展和高可用,還能簡(jiǎn)化配置管理和版本迭代流程。
本文將詳細(xì)介紹如何在K8s環(huán)境中完整部署一個(gè)Spring Boot應(yīng)用,涵蓋從項(xiàng)目準(zhǔn)備、鏡像構(gòu)建到K8s資源配置、部署驗(yàn)證及日常運(yùn)維的全流程。
前置條件
開(kāi)發(fā)環(huán)境:
- JDK 11+(與Spring Boot版本匹配)
 - Maven 3.6+或Gradle 7.0+
 - Docker 20.10+
 - Kubernetes集群(1.27+,可使用Minikube、Kind或生產(chǎn)級(jí)集群)
 - kubectl命令行工具(與集群版本兼容)
 
基礎(chǔ)知識(shí):
- 了解Spring Boot應(yīng)用的打包和運(yùn)行機(jī)制
 - 熟悉Docker基本命令和鏡像構(gòu)建
 - 了解Kubernetes核心概念(Pod、Deployment、Service、ConfigMap等)
 
項(xiàng)目準(zhǔn)備與容器化
首先確保Spring Boot項(xiàng)目能正常構(gòu)建為可執(zhí)行JAR包。在項(xiàng)目根目錄執(zhí)行打包命令:
# Maven項(xiàng)目
mvn clean package -DskipTests
# Gradle項(xiàng)目
gradle clean build -x test編寫(xiě) Dockerfile
在項(xiàng)目根目錄創(chuàng)建Dockerfile,用于將Spring Boot應(yīng)用容器化:
# 基礎(chǔ)鏡像選擇(推薦使用官方精簡(jiǎn)版JDK)
FROM openjdk:11-jdk-slim
# 維護(hù)者信息
LABEL maintainer="yian@example.com"
# 設(shè)置工作目錄
WORKDIR /app
# 復(fù)制JAR包到容器(注意替換實(shí)際JAR文件名)
COPY target/vpdnapi-0.0.1-SNAPSHOT.jar app.jar
# 暴露應(yīng)用端口(與Spring Boot配置的server.port一致)
EXPOSE 8080
# 啟動(dòng)命令(使用exec格式確保容器能正確接收信號(hào))
ENTRYPOINT ["java", "-jar", "app.jar"]
# 可選:添加JVM參數(shù)優(yōu)化
# ENTRYPOINT ["java", "-Xms512m", "-Xmx1g", "-jar", "app.jar"]最佳實(shí)踐:
- 選擇合適的JDK版本,與項(xiàng)目編譯版本一致
 - 使用精簡(jiǎn)基礎(chǔ)鏡像(如slim或alpine版本)減小鏡像體積
 - 固定鏡像標(biāo)簽,避免使用latest
 - 合理配置JVM參數(shù),避免資源浪費(fèi)
 
構(gòu)建 Docker 鏡像
# 格式:docker build -t [鏡像倉(cāng)庫(kù)地址]/[鏡像名]:[版本] .
docker build -t your-registry.example.com/vpdnapi:v1.0.0 .推送鏡像到倉(cāng)庫(kù):
# 登錄鏡像倉(cāng)庫(kù)(如需)
docker login your-registry.example.com
# 推送鏡像
docker push your-registry.example.com/vpdnapi:v1.0.0資源配置
配置管理:ConfigMap 與 Secret
Spring Boot應(yīng)用通常需要外部配置文件(如application.yml)和敏感信息(如數(shù)據(jù)庫(kù)密碼)。在K8s中,推薦使用ConfigMap存儲(chǔ)普通配置,使用Secret存儲(chǔ)敏感信息。
apiVersion: v1
kind: ConfigMap
metadata:
  name: vpdnapi-config
  namespace: vpdn-system
  labels:
    app: vpdnapi
data:
  application.yml: |
    spring:
      profiles:
        active: prod
      application:
        name: vpdnapi
    server:
      port: 8080
    management:
      endpoints:
        web:
          exposure:
            include: health,info,metrics,prometheus
      endpoint:
        health:
          probes:
            enabled: true# 啟用Spring Boot的探針支持
  application-prod.yml: |
    spring:
      datasource:
        url: jdbc:mysql://mysql-service:3306/vpdn_db
        username: ${DB_USERNAME}
        password: ${DB_PASSWORD}
---
# conf目錄資源文件
apiVersion: v1
kind: ConfigMap
metadata:
  name: vpdnapi-conf-files
  namespace: vpdn-system
  labels:
    app: vpdnapi
data:
  clients.xml: |
    <?xml version="1.0" encoding="UTF-8"?>
    <clients>
      <client id="web" name="Web Application"/>
    </clients>
  permissions.properties: |
    admin=*
    operator=read,write
    viewer=readapiVersion: v1
kind: Secret
metadata:
  name: vpdnapi-secret
  namespace: your-namespace
type: Opaque
data:
  # 注意:值必須使用Base64編碼(echo -n "實(shí)際值" | base64)
  db-username: YWRtaW4=  # 編碼前:admin
  db-password: cGFzc3dvcmQxMjM=  # 編碼前:password123
  api-key: SldJVFNlY3JldEtleQ==  # 編碼前:JWTSecretKey部署應(yīng)用:Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vpdnapi-deployment
  namespace: vpdn-system
  labels:
    app: vpdnapi
spec:
  replicas: 3
  selector:
    matchLabels:
      app: vpdnapi
# 滾動(dòng)更新策略優(yōu)化
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
    type: RollingUpdate
# 最小就緒時(shí)間(K8s 1.27+推薦設(shè)置)
  minReadySeconds: 10
  template:
    metadata:
      labels:
        app: vpdnapi
    spec:
      containers:
      - name: vpdnapi
        image: your-registry.example.com/vpdnapi:1.0.0
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        # 資源管理
        resources:
          requests:
            memory: "512Mi"
            cpu: "500m"
          limits:
            memory: "1Gi"
            cpu: "1000m"
        # 環(huán)境變量
        env:
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: vpdnapi-secret
              key: db-username
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: vpdnapi-secret
              key: db-password
        # 配置文件掛載
        volumeMounts:
        - name: main-config
          mountPath: /app/application.yml
          subPath: application.yml
        - name: main-config
          mountPath: /app/application-prod.yml
          subPath: application-prod.yml
        - name: conf-files
          mountPath: /app/conf
        # 健康探針(K8s 1.27推薦配置)
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: http
          initialDelaySeconds: 60
          periodSeconds: 10
          timeoutSeconds: 3
          failureThreshold: 3
          successThreshold: 1
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: http
          initialDelaySeconds: 30
          periodSeconds: 5
          timeoutSeconds: 3
        # 啟動(dòng)探針(處理慢啟動(dòng)場(chǎng)景)
        startupProbe:
          httpGet:
            path: /actuator/health
            port: http
          failureThreshold: 30
          periodSeconds: 10
      volumes:
      - name: main-config
        configMap:
          name: vpdnapi-config
          defaultMode: 0644
      - name: conf-files
        configMap:
          name: vpdnapi-conf-files
          defaultMode: 0644關(guān)鍵配置說(shuō)明:
- replicas: 設(shè)置多個(gè)副本實(shí)現(xiàn)高可用
 - resources: 配置資源請(qǐng)求和限制,避免資源競(jìng)爭(zhēng)
 - livenessProbe/readinessProbe: 健康檢查確保K8s能正確識(shí)別應(yīng)用狀態(tài)
 - volumeMounts: 將ConfigMap掛載到容器內(nèi),實(shí)現(xiàn)配置外部化
 - imagePullPolicy: 建議設(shè)置為IfNotPresent或Always(生產(chǎn)環(huán)境)
 
暴露服務(wù):Service
apiVersion: v1
kind: Service
metadata:
  name: vpdnapi-service
  namespace: vpdn-system
  labels:
    app: vpdnapi
spec:
  selector:
    app: vpdnapi
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
    name: http
type: ClusterIPService類(lèi)型說(shuō)明:
- ClusterIP: 僅集群內(nèi)部可訪問(wèn)(默認(rèn))
 - NodePort: 通過(guò)節(jié)點(diǎn)端口暴露服務(wù)(適合測(cè)試環(huán)境)
 - LoadBalancer: 結(jié)合云廠商負(fù)載均衡器使用(適合生產(chǎn)環(huán)境)
 
外部訪問(wèn):Ingress(可選)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: vpdnapi-ingress
  namespace: vpdn-system
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    # 啟用會(huì)話保持(如需)
    nginx.ingress.kubernetes.io/affinity: "cookie"
    nginx.ingress.kubernetes.io/session-cookie-name: "VPdnApiSession"
    nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
    nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
spec:
  ingressClassName: nginx
  rules:
  - host: vpdnapi.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: vpdnapi-service
            port:
              name: http
  tls:
  - hosts:
    - vpdnapi.example.com
    secretName: vpdnapi-tls-cert部署與驗(yàn)證
# 創(chuàng)建命名空間(如不存在)
kubectl create namespace your-namespace
# 部署配置資源
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
# 部署應(yīng)用
kubectl apply -f deployment.yaml
# 部署服務(wù)
kubectl apply -f service.yaml
# 部署Ingress(如需要)
kubectl apply -f ingress.yaml驗(yàn)證部署狀態(tài)
#查看 Pod 狀態(tài)
kubectl get pods -n your-namespace -l app=vpdnapi
NAME                                    READY   STATUS    RESTARTS   AGE
vpdnapi-deployment-7f9d658b45-2xq8k     1/1     Running   0          5m
vpdnapi-deployment-7f9d658b45-zm7p3     1/1     Running   0          5m
#查看 Deployment 狀態(tài)
kubectl get deployment vpdnapi-deployment -n your-namespace
#查看 Service 狀態(tài)
kubectl get service vpdnapi-service -n your-namespace
#查看應(yīng)用日志
# 查看指定Pod日志
kubectl logs -f <pod-name> -n your-namespace
# 查看最近100行日志
kubectl logs --tail=100 <pod-name> -n your-namespace測(cè)試訪問(wèn):
# 通過(guò)Service ClusterIP訪問(wèn)
curl http://<service-ip>:80/actuator/health
# 通過(guò)Ingress訪問(wèn)
curl https://vpdnapi.example.com/actuator/health














 
 
 

















 
 
 
 