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
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)