欢迎光临
我们一直在努力

Java 程序员第 42 阶段19:文档智能解析审核大模型实现合同摘要与合规校验,容器化部署与Kubernetes编排

──────────────────────────────────────────────────

目录

  • [章节概述](#章节概述)
  • 2. [Docker多阶段构建详解](#docker多阶段构建详解)

    3. [Docker Compose本地开发环境](#docker-compose本地开发环境)

    4. [Kubernetes集群部署架构](#kubernetes集群部署架构)

    5. [HPA弹性伸缩配置](#hpa弹性伸缩配置)

    6. [实际代码示例](#实际代码示例)

    7. [章节总结](#章节总结)

    ──────────────────────────────────────────────────

    章节概述

    19.1 学习目标

    本章节将深入讲解合同审核系统的容器化部署与Kubernetes编排技术栈,包括:

    • 掌握Docker多阶段构建技术,减小镜像体积
    • 熟练使用Docker Compose搭建本地开发环境
    • 理解Kubernetes核心资源对象及部署策略
    • 掌握HPA弹性伸缩配置,实现自动扩缩容

    19.2 章节背景

    合同智能审核系统涉及大模型推理,需要稳定的容器化部署环境支持。通过Docker和Kubernetes的组合,我们可以实现:

    • 环境一致性:开发、测试、生产环境统一
    • 弹性伸缩:根据负载自动调整实例数量
    • 高可用:多副本部署,自动故障恢复
    • 资源隔离:不同服务独立运行,互不影响

    ──────────────────────────────────────────────────

    Docker多阶段构建详解

    19.2.1 传统构建的问题

    传统的Dockerfile通常存在以下问题:

    # 传统方式 – 问题多
    FROM ubuntu:20.04
    RUN apt-get update && apt-get install -y \\
        openjdk-11-jdk \\
        maven \\
        git \\
        && rm -rf /var/lib/apt/lists/*
    COPY . /app
    WORKDIR /app
    RUN mvn package
    CMD ["java", "-jar", "/app/target/contract-api.jar"]

    **问题分析:**

    • 镜像体积过大(可能超过2GB)
    • 包含构建工具,安全性降低
    • 层次结构不清晰,缓存利用率低

    19.2.2 多阶段构建解决方案

    # contract-api/Dockerfile
    # ===================================================================
    # 第一阶段:构建阶段
    # ===================================================================
    FROM maven:3.8.6-openjdk-11 AS builder

    # 设置工作目录
    WORKDIR /build

    # 复制pom.xml以利用Docker缓存
    COPY pom.xml .

    # 下载依赖(单独层,便于缓存)
    RUN mvn dependency:go-offline -B

    # 复制源代码
    COPY src ./src

    # 构建应用(跳过测试)
    RUN mvn package -DskipTests

    # ===================================================================
    # 第二阶段:运行时阶段
    # ===================================================================
    FROM openjdk:11-jre-slim

    # 创建非root用户
    RUN groupadd -r appgroup && useradd -r -g appgroup appuser

    # 设置工作目录
    WORKDIR /app

    # 从构建阶段复制产物
    COPY –from=builder /build/target/*.jar app.jar
    COPY –from=builder /build/src/main/resources/config ./config

    # 修改文件所有者
    RUN chown -R appuser:appgroup /app

    # 切换到非root用户
    USER appuser

    # 暴露端口
    EXPOSE 8080

    # 健康检查
    HEALTHCHECK –interval=30s –timeout=10s –start-period=60s –retries=3 \\
        CMD "curl -f http://localhost:8080/actuator/health || exit 1"

    # JVM参数优化
    ENV JAVA_OPTS="-Xms512m -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

    # 启动命令
    ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

    19.2.3 构建实战

    # 构建镜像
    docker build -t contract-api:1.0.0 .

    # 查看镜像大小对比
    docker images | grep contract-api

    # 多阶段构建日志示例
    Step 1/15 : FROM maven:3.8.6-openjdk-11 AS builder
     —> a1b2c3d4e5f6
    Step 2/15 : WORKDIR /build
     —> Using cache
    Step 3/15 : COPY pom.xml .
     —> Using cache
    Step 4/15 : RUN mvn dependency:go-offline -B
     —> Running in abc123…
    Downloading dependencies…
    Completed dependency resolution
     —> def456…

    Successfully built abc789
    Successfully tagged contract-api:1.0.0

    # 运行容器测试
    docker run -d -p 8080:8080 –name contract-api contract-api:1.0.0

    # 查看容器日志
    docker logs -f contract-api

    # 查看容器状态
    docker inspect contract-api | grep -A 10 "Status"

    19.2.4 镜像优化技巧

    | 优化项 | 优化前 | 优化后 | 节省 |

    |——–|——–|——–|——|

    | 基础镜像 | ubuntu:20.04 (800MB) | openjdk:11-jre-slim (200MB) | 75% |

    | 包含工具 | Maven、JDK完整版 | 仅JRE运行时 | 60% |

    | 最终大小 | ~2.5GB | ~400MB | 84% |

    ──────────────────────────────────────────────────

    Docker Compose本地开发环境

    19.3.1 docker-compose.yml配置

    # docker-compose.yml
    version: '3.8'

    services:
      # ===================================================================
      # 合同审核API服务
      # ===================================================================
      contract-api:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: contract-api
        ports:
          – "8080:8080"
          – "5005:5005"  # 远程调试端口
        environment:
          – SPRING_PROFILES_ACTIVE=dev
          – JAVA_OPTS=-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=5005,suspend=n
          – DB_HOST=mysql
          – DB_PORT=3306
          – REDIS_HOST=redis
          – REDIS_PORT=6379
        volumes:
          – ./logs:/app/logs
          – ./config/dev:/app/config:ro
        depends_on:
          mysql:
            condition: service_healthy
          redis:
            condition: service_started
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # MySQL数据库服务
      # ===================================================================
      mysql:
        image: mysql:8.0
        container_name: contract-mysql
        ports:
          – "3306:3306"
        environment:
          – MYSQL_ROOT_PASSWORD=root_secret
          – MYSQL_DATABASE=contract_db
          – MYSQL_USER=contract_user
          – MYSQL_PASSWORD=contract_pass
        volumes:
          – mysql-data:/var/lib/mysql
          – ./init-scripts:/docker-entrypoint-initdb.d:ro
        command:
          – –character-set-server=utf8mb4
          – –collation-server=utf8mb4_unicode_ci
          – –default-authentication-plugin=mysql_native_password
        healthcheck:
          test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot_secret"]
          interval: 10s
          timeout: 5s
          retries: 5
          start_period: 30s
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # Redis缓存服务
      # ===================================================================
      redis:
        image: redis:7-alpine
        container_name: contract-redis
        ports:
          – "6379:6379"
        command: redis-server –appendonly yes –maxmemory 512mb –maxmemory-policy allkeys-lru
        volumes:
          – redis-data:/data
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # Elasticsearch日志存储
      # ===================================================================
      elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0
        container_name: contract-elasticsearch
        ports:
          – "9200:9200"
          – "9300:9300"
        environment:
          – discovery.type=single-node
          – xpack.security.enabled=false
          – ES_JAVA_OPTS=-Xms1g -Xmx1g
        volumes:
          – es-data:/usr/share/elasticsearch/data
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # Logstash日志处理
      # ===================================================================
      logstash:
        image: docker.elastic.co/logstash/logstash:8.11.0
        container_name: contract-logstash
        ports:
          – "5044:5044"
        volumes:
          – ./logstash/pipeline:/usr/share/logstash/pipeline:ro
          – ./logstash/config/logstash.yml:/usr/share/logstash/config/logstash.yml:ro
        depends_on:
          – elasticsearch
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # Kibana可视化
      # ===================================================================
      kibana:
        image: docker.elastic.co/kibana/kibana:8.11.0
        container_name: contract-kibana
        ports:
          – "5601:5601"
        environment:
          – ELASTICSEARCH_HOSTS=http://elasticsearch:9200
        depends_on:
          – elasticsearch
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # Prometheus监控
      # ===================================================================
      prometheus:
        image: prom/prometheus:v2.47.0
        container_name: contract-prometheus
        ports:
          – "9090:9090"
        volumes:
          – ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
          – prometheus-data:/prometheus
        command:
          – '–config.file=/etc/prometheus/prometheus.yml'
          – '–storage.tsdb.path=/prometheus'
          – '–web.console.libraries=/etc/prometheus/console_libraries'
          – '–web.console.templates=/etc/prometheus/consoles'
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # Grafana可视化监控
      # ===================================================================
      grafana:
        image: grafana/grafana:10.2.0
        container_name: contract-grafana
        ports:
          – "3000:3000"
        environment:
          – GF_SECURITY_ADMIN_USER=admin
          – GF_SECURITY_ADMIN_PASSWORD=admin123
          – GF_USERS_ALLOW_SIGN_UP=false
        volumes:
          – grafana-data:/var/lib/grafana
          – ./grafana/provisioning:/etc/grafana/provisioning:ro
        depends_on:
          – prometheus
        networks:
          – contract-network
        restart: unless-stopped

      # ===================================================================
      # MinIO对象存储
      # ===================================================================
      minio:
        image: minio/minio:latest
        container_name: contract-minio
        ports:
          – "9000:9000"
          – "9001:9001"
        environment:
          – MINIO_ROOT_USER=minioadmin
          – MINIO_ROOT_PASSWORD=minioadmin123
        volumes:
          – minio-data:/data
        command: server /data –console-address ":9001"
        networks:
          – contract-network
        restart: unless-stopped

    # ===================================================================
    # 网络配置
    # ===================================================================
    networks:
      contract-network:
        driver: bridge
        name: contract_dev_network

    # ===================================================================
    # 卷配置
    # ===================================================================
    volumes:
      mysql-data:
        name: contract_mysql_data
      redis-data:
        name: contract_redis_data
      es-data:
        name: contract_es_data
      prometheus-data:
        name: contract_prometheus_data
      grafana-data:
        name: contract_grafana_data
      minio-data:
        name: contract_minio_data

    19.3.2 环境启动与验证

    # 启动所有服务(后台运行)
    docker-compose up -d

    # 查看服务状态
    docker-compose ps

    # 查看服务日志
    docker-compose logs -f contract-api
    docker-compose logs -f mysql
    docker-compose logs -f redis

    # 等待服务健康检查通过
    docker-compose ps –format "table {{.Name}}\\t{{.Status}}\\t{{.Ports}}"

    # 测试API接口
    curl -s http://localhost:8080/actuator/health | jq .

    # 验证数据库连接
    docker-compose exec mysql mysql -ucontract_user -pcontract_pass -e "SHOW DATABASES;"

    # 验证Redis连接
    docker-compose exec redis redis-cli ping

    # 访问监控界面
    # Prometheus: http://localhost:9090
    # Grafana: http://localhost:3000 (admin/admin123)
    # Kibana: http://localhost:5601
    # MinIO: http://localhost:9001 (minioadmin/minioadmin123)

    # 停止所有服务
    docker-compose down

    # 停止服务并清除数据卷
    docker-compose down -v

    ──────────────────────────────────────────────────

    Kubernetes集群部署架构

    19.4.1 命名空间配置

    # namespace.yaml
    apiVersion: v1
    kind: Namespace
    metadata:
      name: production
      labels:
        name: production
        environment: production
        team: contract-team

    # 创建命名空间
    kubectl apply -f namespace.yaml

    # 查看命名空间
    kubectl get namespaces

    19.4.2 ConfigMap配置

    # configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: contract-api-config
      namespace: production
      labels:
        app: contract-api
        version: v1
    data:
      # 应用配置
      application.yml: |
        spring:
          application:
            name: contract-api
          profiles:
            active: production
          servlet:
            multipart:
              max-file-size: 100MB
              max-request-size: 100MB

        # 数据库配置
        datasource:
          url: jdbc:mysql://mysql.production.svc.cluster.local:3306/contract_db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
          username: contract_user
          driver-class-name: com.mysql.cj.jdbc.Driver
          hikari:
            maximum-pool-size: 20
            minimum-idle: 5
            idle-timeout: 300000
            connection-timeout: 20000

        # Redis配置
        redis:
          host: redis.production.svc.cluster.local
          port: 6379
          timeout: 5000
          lettuce:
            pool:
              max-active: 50
              max-idle: 20
              min-idle: 5

        # 文件存储配置
        minio:
          endpoint: http://minio.production.svc.cluster.local:9000
          access-key: ${MINIO_ACCESS_KEY}
          secret-key: ${MINIO_SECRET_KEY}
          bucket: contracts

        # AI模型配置
        ai:
          model:
            provider: openai
            api-key: ${AI_API_KEY}
            base-url: https://api.openai.com/v1
            completion-model: gpt-4
            embedding-model: text-embedding-ada-002
            max-tokens: 4096
            temperature: 0.7

        # 日志配置
        logging:
          level:
            root: INFO
            com.contract: DEBUG
          pattern:
            console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} – %msg%n"

      # logback配置
      logback-spring.xml: |
        <?xml version="1.0" encoding="UTF-8"?>
        <configuration>
            <include resource="org/springframework/boot/logging/logback/defaults.xml"/>
            <property name="LOG_FILE" value="${LOG_FILE:-${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}/contract-api}"/>
            <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
                <encoder>
                    <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} – %msg%n</pattern>
                </encoder>
            </appender>
            <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender">
                <encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
                    <layout class="ch.qos.logback.contrib.json.classic.JsonLayout">
                        <timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SSSX</timestampFormat>
                        <timestampFormatTimezoneId>Asia/Shanghai</timestampFormatTimezoneId>
                        <appendLineSeparator>true</appendLineSeparator>
                    </layout>
                </encoder>
            </appender>
            <root level="INFO">
                <appender-ref ref="CONSOLE"/>
            </root>
        </configuration>

    # 应用ConfigMap
    kubectl apply -f configmap.yaml

    # 查看ConfigMap
    kubectl get configmap -n production
    kubectl describe configmap contract-api-config -n production

    19.4.3 Secret配置

    # secret.yaml
    apiVersion: v1
    kind: Secret
    metadata:
      name: contract-api-secret
      namespace: production
    type: Opaque
    stringData:
      # 数据库密码
      DB_PASSWORD: contract_db_secret_pass_2024
      # Redis密码(无密码时留空)
      REDIS_PASSWORD: ""
      # AI API密钥
      AI_API_KEY: sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      # MinIO凭证
      MINIO_ACCESS_KEY: minioadmin
      MINIO_SECRET_KEY: minioadmin123
      # JWT密钥
      JWT_SECRET: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
      # 加密密钥
      ENCRYPTION_KEY: 0123456789abcdef0123456789abcdef

    # 创建Secret
    kubectl apply -f secret.yaml

    # 查看Secret(加密显示)
    kubectl get secret contract-api-secret -n production -o yaml

    # 解码特定字段
    kubectl get secret contract-api-secret -n production -o jsonpath="{.data.AI_API_KEY}" | base64 -d

    19.4.4 Deployment配置

    # deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: contract-api
      namespace: production
      labels:
        app: contract-api
        version: v1
        component: backend
    spec:
      # 副本数
      replicas: 3

      # 选择器
      selector:
        matchLabels:
          app: contract-api

      # 滚动更新策略
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0

      # Pod模板
      template:
        metadata:
          labels:
            app: contract-api
            version: v1
            component: backend
          annotations:
            prometheus.io/scrape: "true"
            prometheus.io/port: "8080"
            prometheus.io/path: "/actuator/prometheus"
        spec:
          # 服务账户
          serviceAccountName: contract-api-sa

          # 安全上下文
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
            fsGroup: 1000

          # 初始化容器 – 等待数据库就绪
          initContainers:
            – name: wait-for-mysql
              image: busybox:1.36
              command:
                – sh
                – -c
                – |
                  echo "Waiting for MySQL to be ready…"
                  until nc -z mysql.production.svc.cluster.local 3306; do
                    echo "MySQL is not ready, waiting…"
                    sleep 5
                  done
                  echo "MySQL is ready!"
            – name: wait-for-redis
              image: busybox:1.36
              command:
                – sh
                – -c
                – |
                  echo "Waiting for Redis to be ready…"
                  until nc -z redis.production.svc.cluster.local 6379; do
                    echo "Redis is not ready, waiting…"
                    sleep 3
                  done
                  echo "Redis is ready!"

          # 容器配置
          containers:
            – name: contract-api
              image: contract-api:1.0.0
              imagePullPolicy: Always

              ports:
                – name: http
                  containerPort: 8080
                  protocol: TCP
                – name: ajp
                  containerPort: 8009
                  protocol: TCP

              # 环境变量
              env:
                – name: SPRING_PROFILES_ACTIVE
                  value: "production"
                – name: JAVA_OPTS
                  value: "-Xms1g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof"
                – name: DB_HOST
                  valueFrom:
                    configMapKeyRef:
                      name: contract-api-config
                      key: DB_HOST
                – name: DB_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      name: contract-api-secret
                      key: DB_PASSWORD
                – name: AI_API_KEY
                  valueFrom:
                    secretKeyRef:
                      name: contract-api-secret
                      key: AI_API_KEY

              # 资源配置
              resources:
                requests:
                  cpu: 500m
                  memory: 1Gi
                limits:
                  cpu: 2000m
                  memory: 4Gi

              # 存活探针
              livenessProbe:
                httpGet:
                  path: /actuator/health/liveness
                  port: http
                initialDelaySeconds: 60
                periodSeconds: 10
                timeoutSeconds: 5
                failureThreshold: 3
                successThreshold: 1

              # 就绪探针
              readinessProbe:
                httpGet:
                  path: /actuator/health/readiness
                  port: http
                initialDelaySeconds: 30
                periodSeconds: 5
                timeoutSeconds: 3
                failureThreshold: 3
                successThreshold: 1

              # 启动探针
              startupProbe:
                httpGet:
                  path: /actuator/health
                  port: http
                initialDelaySeconds: 10
                periodSeconds: 5
                timeoutSeconds: 3
                failureThreshold: 30

              # 卷挂载
              volumeMounts:
                – name: app-logs
                  mountPath: /app/logs
                – name: tmp-volume
                  mountPath: /tmp
                – name: heapdump-volume
                  mountPath: /tmp

          # 卷配置
          volumes:
            – name: app-logs
              emptyDir: {}
            – name: tmp-volume
              emptyDir: {}
            – name: heapdump-volume
              emptyDir: {}

          # 亲和性配置
          affinity:
            # Pod反亲和性 – 分散到不同节点
            podAntiAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
                – weight: 100
                  podAffinityTerm:
                    labelSelector:
                      matchLabels:
                        app: contract-api
                    topologyKey: kubernetes.io/hostname
            # 节点亲和性
            nodeAffinity:
              preferredDuringSchedulingIgnoredDuringExecution:
                – weight: 10
                  preference:
                    matchExpressions:
                      – key: node-type
                        operator: In
                        values:
                          – compute-optimized

          # 容忍调度
          tolerations:
            – key: "node-type"
              operator: "Equal"
              value: "compute-optimized"
              effect: "NoSchedule"

    # 部署应用
    kubectl apply -f deployment.yaml

    # 查看部署状态
    kubectl get deployment -n production
    kubectl describe deployment contract-api -n production

    # 查看Pods
    kubectl get pods -n production -l app=contract-api

    # 查看Pod日志
    kubectl logs -f deployment/contract-api -n production

    # 查看资源使用
    kubectl top pods -n production -l app=contract-api

    19.4.5 Service配置

    # service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: contract-api
      namespace: production
      labels:
        app: contract-api
    spec:
      # Service类型
      type: ClusterIP

      # 会话亲和性
      sessionAffinity: ClientIP
      sessionAffinityConfig:
        clientIP:
          timeoutSeconds: 10800

      # 端口配置
      ports:
        – name: http
          port: 80
          targetPort: 8080
          protocol: TCP
        – name: ajp
          port: 8009
          targetPort: 8009
          protocol: TCP

      # 选择器
      selector:
        app: contract-api


    # Headless Service – 用于有状态服务
    apiVersion: v1
    kind: Service
    metadata:
      name: contract-api-headless
      namespace: production
      labels:
        app: contract-api
    spec:
      clusterIP: None
      ports:
        – name: http
          port: 8080
          targetPort: 8080
      selector:
        app: contract-api

    # 应用Service
    kubectl apply -f service.yaml

    # 查看Service
    kubectl get service -n production

    # 测试Service连通性(临时Pod)
    kubectl run -it –rm debug-pod –image=busybox:1.36 –restart=Never — sh
    # 在Pod内执行
    nslookup contract-api.production.svc.cluster.local
    curl http://contract-api.production.svc.cluster.local/actuator/health
    exit

    19.4.6 Ingress配置

    # ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: contract-api-ingress
      namespace: production
      labels:
        app: contract-api
      annotations:
        # 重写规则
        nginx.ingress.kubernetes.io/rewrite-target: /$2
        # CORS配置
        nginx.ingress.kubernetes.io/enable-cors: "true"
        nginx.ingress.kubernetes.io/cors-allow-origin: "*"
        nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, DELETE, PATCH, OPTIONS"
        nginx.ingress.kubernetes.io/cors-allow-headers: "Authorization,Content-Type,Accept,Origin,User-Agent,Cache-Control,Keep-Alive,X-Requested-With"
        # 连接超时
        nginx.ingress.kubernetes.io/proxy-connect-timeout: "60"
        nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
        nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
        # 速率限制
        nginx.ingress.kubernetes.io/limit-rps: "100"
        nginx.ingress.kubernetes.io/limit-connections: "50"
        # 代理头
        nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
    spec:
      ingressClassName: nginx
      tls:
        – hosts:
            – contract-api.example.com
          secretName: contract-api-tls
      rules:
        – host: contract-api.example.com
          http:
            paths:
              – path: /
                pathType: Prefix
                backend:
                  service:
                    name: contract-api
                    port:
                      number: 80

    ──────────────────────────────────────────────────

    HPA弹性伸缩配置

    19.5.1 HPA资源清单

    # hpa.yaml
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: contract-api-hpa
      namespace: production
      labels:
        app: contract-api
    spec:
      # 缩放目标
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: contract-api

      # 副本数范围
      minReplicas: 2
      maxReplicas: 20

      # metrics配置
      metrics:
        # CPU指标
        – type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 70

        # 内存指标
        – type: Resource
          resource:
            name: memory
            target:
              type: Utilization
              averageUtilization: 80

        # 自定义指标 – HTTP请求率
        – type: Pods
          pods:
            metric:
              name: http_requests_per_second
            target:
              type: AverageValue
              averageValue: "1000"

      # 行为策略
      behavior:
        # 扩容策略
        scaleUp:
          stabilizationWindowSeconds: 60
          policies:
            # 基于百分比扩容 – 每次最多增加100%副本
            – type: Percent
              value: 100
              periodSeconds: 15
            # 基于Pod数量扩容 – 每次最多增加4个Pod
            – type: Pods
              value: 4
              periodSeconds: 15
          selectPolicy: Max

        # 缩容策略
        scaleDown:
          stabilizationWindowSeconds: 300
          policies:
            # 每次最多删除1个Pod
            – type: Pods
              value: 1
              periodSeconds: 60
          selectPolicy: Min

    19.5.2 垂直 Pod 自动扩缩容 (VPA)

    # vpa.yaml
    apiVersion: autoscaling.k8s.io/v1
    kind: VerticalPodAutoscaler
    metadata:
      name: contract-api-vpa
      namespace: production
    spec:
      targetRef:
        apiVersion: "apps/v1"
        kind: Deployment
        name: contract-api
      updatePolicy:
        updateMode: "Auto"
      resourcePolicy:
        containerPolicies:
          – containerName: contract-api
            minAllowed:
              cpu: 250m
              memory: 512Mi
            maxAllowed:
              cpu: 4000m
              memory: 8Gi
            controlledResources: ["cpu", "memory"]

    19.5.3 HPA验证命令

    # 创建HPA
    kubectl apply -f hpa.yaml

    # 查看HPA状态
    kubectl get hpa -n production
    kubectl describe hpa contract-api-hpa -n production

    # 查看HPA推荐值
    kubectl get hpa contract-api-hpa -n production -o jsonpath="{.status}" | jq .

    # 手动触发扩容测试
    kubectl scale deployment contract-api –replicas=10 -n production

    # 查看当前副本数
    kubectl get pods -n production -l app=contract-api –watch

    # 删除HPA
    kubectl delete hpa contract-api-hpa -n production

    ──────────────────────────────────────────────────

    实际代码示例

    19.6.1 完整的Kubernetes资源清单

    # k8s-resources.yaml
    # ===================================================================
    # 命名空间
    # ===================================================================
    apiVersion: v1
    kind: Namespace
    metadata:
      name: production
      labels:
        name: production

    # ===================================================================
    # ConfigMap
    # ===================================================================
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: contract-api-config
      namespace: production
    data:
      application.yml: |
        spring:
          application:
            name: contract-api
          servlet:
            multipart:
              max-file-size: 100MB
              max-request-size: 100MB
        server:
          port: 8080
          tomcat:
            threads:
              max: 200
              min-spare: 10
            accept-count: 100
            max-connections: 10000

    # ===================================================================
    # Secret
    # ===================================================================
    apiVersion: v1
    kind: Secret
    metadata:
      name: contract-api-secret
      namespace: production
    type: Opaque
    stringData:
      DB_PASSWORD: production_db_password
      AI_API_KEY: sk-production-key

    # ===================================================================
    # Deployment
    # ===================================================================
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: contract-api
      namespace: production
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: contract-api
      template:
        metadata:
          labels:
            app: contract-api
        spec:
          containers:
            – name: contract-api
              image: contract-api:1.0.0
              ports:
                – containerPort: 8080
              resources:
                requests:
                  cpu: 500m
                  memory: 1Gi
                limits:
                  cpu: 2000m
                  memory: 4Gi
              livenessProbe:
                httpGet:
                  path: /actuator/health/liveness
                  port: 8080
                initialDelaySeconds: 60
                periodSeconds: 10
              readinessProbe:
                httpGet:
                  path: /actuator/health/readiness
                  port: 8080
                initialDelaySeconds: 30
                periodSeconds: 5

    # ===================================================================
    # Service
    # ===================================================================
    apiVersion: v1
    kind: Service
    metadata:
      name: contract-api
      namespace: production
    spec:
      type: ClusterIP
      ports:
        – port: 80
          targetPort: 8080
      selector:
        app: contract-api

    # ===================================================================
    # HPA
    # ===================================================================
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: contract-api-hpa
      namespace: production
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: contract-api
      minReplicas: 2
      maxReplicas: 20
      metrics:
        – type: Resource
          resource:
            name: cpu
            target:
              type: Utilization
              averageUtilization: 70

    # 一键部署所有资源
    kubectl apply -f k8s-resources.yaml

    # 验证部署
    kubectl get all -n production

    # 查看Pod事件
    kubectl describe pods -n production | grep -A 10 "Events:"

    # 清理所有资源
    kubectl delete -f k8s-resources.yaml

    19.6.2 Helm Chart打包

    # Chart.yaml
    apiVersion: v2
    name: contract-api
    description: A Helm chart for Contract API Service
    type: application
    version: 1.0.0
    appVersion: "1.0.0"
    keywords:
      – contract
      – api
      – spring-boot
    maintainers:
      – name: Contract Team
        email: team@example.com

    # values.yaml
    replicaCount: 3

    image:
      repository: contract-api
      tag: "1.0.0"
      pullPolicy: Always

    service:
      type: ClusterIP
      port: 80
      targetPort: 8080

    ingress:
      enabled: true
      className: nginx
      host: contract-api.example.com
      tls:
        enabled: true
        secretName: contract-api-tls

    resources:
      requests:
        cpu: 500m
        memory: 1Gi
      limits:
        cpu: 2000m
        memory: 4Gi

    hpa:
      enabled: true
      minReplicas: 2
      maxReplicas: 20
      targetCPUUtilizationPercentage: 70

    config:
      springProfiles: production

    # 打包Chart
    helm package ./chart

    # 安装Release
    helm install contract-api ./contract-api-1.0.0.tgz -n production

    # 升级Release
    helm upgrade contract-api ./contract-api-1.0.0.tgz -n production

    # 回滚Release
    helm rollback contract-api 1 -n production

    # 卸载Release
    helm uninstall contract-api -n production

    ──────────────────────────────────────────────────

    章节总结

    19.7 核心知识点回顾

    | 知识点 | 关键内容 |

    |——–|———-|

    | Docker多阶段构建 | Builder阶段构建 + Runtime阶段运行,减小80%镜像体积 |

    | Docker Compose | 一键启动完整开发环境,依赖管理,健康检查 |

    | Kubernetes资源 | Deployment/Service/ConfigMap/Secret/HPA |

    | HPA弹性伸缩 | CPU/内存/自定义指标,自动扩缩容策略 |

    | Helm Chart | 应用打包,版本管理,一键部署升级回滚 |

    19.8 最佳实践建议

  • **镜像优化**:始终使用多阶段构建,仅包含运行时必需的组件
  • 2. **资源配置**:合理设置requests和limits,避免资源浪费

    3. **健康检查**:配置livenessProbe和readinessProbe,确保服务可用性

    4. **弹性伸缩**:根据实际负载调整HPA阈值,建议CPU 70%,内存80%

    5. **日志收集**:统一日志格式,便于ELK收集和分析

    19.9 扩展学习方向

    • 学习Kubernetes Operator开发,实现自定义资源控制器
    • 研究Service Mesh(Istio)实现更精细的流量管理
    • 探索Knative实现serverless化的容器部署
    • 学习ArgoCD实现GitOps方式的持续部署

    ──────────────────────────────────────────────────

    下章预告

    第20篇将介绍**生产上线与持续迭代**相关内容:

    • 生产环境验收测试清单
    • 灰度发布与回滚策略
    • Prometheus + Grafana监控告警配置
    • ELK日志收集与分析
    • Jenkins/GitHub Actions持续集成部署

    ──────────────────────────────────────────────────

    *版权声明:本文为洛水石原创文章,版权所有,侵权必究。*

    图: docker multi stage build.png

    图: hpa scaling diagram.png

    图: kubernetes deployment architecture.png

    赞(0)
    未经允许不得转载:171主机测评 » Java 程序员第 42 阶段19:文档智能解析审核大模型实现合同摘要与合规校验,容器化部署与Kubernetes编排
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址