|
|
@@ -0,0 +1,275 @@
|
|
|
+# Dockerfile 优化方案详解
|
|
|
+
|
|
|
+## 📊 镜像大小对比
|
|
|
+
|
|
|
+| 基础镜像 | 大小 | 说明 |
|
|
|
+|--------|------|------|
|
|
|
+| `openjdk:17.0.2-jdk-slim` | ~500MB | 当前使用,包含 JDK |
|
|
|
+| `openjdk:17.0.2-jre-slim` | ~300MB | JRE only,减少 200MB |
|
|
|
+| **`eclipse-temurin:17-jre-alpine`** | **~150MB** | ✅ 推荐,最小化 |
|
|
|
+
|
|
|
+**选择 Alpine 的优势:**
|
|
|
+- ✅ 基础镜像最小(仅 ~150MB)
|
|
|
+- ✅ 生产环境只需要 JRE,不需要 JDK
|
|
|
+- ✅ 完全兼容 OpenJDK 生态
|
|
|
+- ⚠️ 注意:如果需要 glibc 工具,需要额外安装
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🔧 JAVA_OPTS 优化详解
|
|
|
+
|
|
|
+### ✅ 必须保留的参数(3个)
|
|
|
+
|
|
|
+```bash
|
|
|
+-Djava.awt.headless=true # 禁用 AWT/Swing GUI
|
|
|
+-Djava.net.preferIPv4Stack=true # 优先使用 IPv4
|
|
|
+-Xss256k # 线程栈大小:256KB
|
|
|
+-XX:+DisableExplicitGC # 禁用 System.gc()
|
|
|
+```
|
|
|
+
|
|
|
+**保留原因:**
|
|
|
+1. **`-Djava.awt.headless=true`**
|
|
|
+ - Java 应用在服务器环境不需要 GUI
|
|
|
+ - 禁用可以减少一些初始化开销
|
|
|
+ - **必须保留**
|
|
|
+
|
|
|
+2. **`-Djava.net.preferIPv4Stack=true`**
|
|
|
+ - 解决 Docker/K8S 中 IPv4/IPv6 双栈问题
|
|
|
+ - 防止 DNS 解析延迟
|
|
|
+ - **强烈推荐保留**
|
|
|
+
|
|
|
+3. **`-Xss256k`**
|
|
|
+ - 设置单个线程栈大小为 256KB
|
|
|
+ - 允许创建更多线程(默认 1MB)
|
|
|
+ - 对高并发应用重要
|
|
|
+ - **保留**
|
|
|
+
|
|
|
+4. **`-XX:+DisableExplicitGC`**
|
|
|
+ - 防止应用代码调用 `System.gc()` 影响 GC
|
|
|
+ - **推荐保留**
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+### ❌ 必须删除的参数(10个)
|
|
|
+
|
|
|
+#### 1. **内存相关(在 K8S 中由 resources 管理)**
|
|
|
+
|
|
|
+```bash
|
|
|
+❌ -Xmx512m # 删除:K8S 通过 resources.limits.memory 管理
|
|
|
+❌ -Xms512m # 删除:K8S 通过 resources.requests.memory 管理
|
|
|
+❌ -Xmn256m # 删除:新生代大小由 K8S 内存限制决定
|
|
|
+```
|
|
|
+
|
|
|
+**删除原因:**
|
|
|
+- K8S 会通过 cgroup 限制进程内存
|
|
|
+- 如果 JVM 参数限制与 K8S 限制冲突,会导致 OOMKilled
|
|
|
+- 现代 K8S + Java 推荐由容器调度器管理内存
|
|
|
+
|
|
|
+**K8S 配置示例:**
|
|
|
+```yaml
|
|
|
+resources:
|
|
|
+ requests:
|
|
|
+ memory: "512Mi" # 替代 -Xms512m
|
|
|
+ limits:
|
|
|
+ memory: "1024Mi" # 替代 -Xmx512m
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+#### 2. **过时的 PermGen 参数(Java 8+ 已废弃)**
|
|
|
+
|
|
|
+```bash
|
|
|
+❌ -XX:PermSize=256m # 删除:Java 8+ 已移除 PermGen
|
|
|
+❌ -XX:MaxPermSize=256m # 删除:改为 Metaspace 自动管理
|
|
|
+```
|
|
|
+
|
|
|
+**删除原因:**
|
|
|
+- Java 8 起,PermGen 被 Metaspace 替代
|
|
|
+- Metaspace 使用本地内存(堆外),自动扩展
|
|
|
+- 这些参数在 Java 17 中被**完全忽略**
|
|
|
+- 写了也没用,还会造成困惑
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+#### 3. **CMS 垃圾回收相关(Java 17 默认使用 G1GC)**
|
|
|
+
|
|
|
+```bash
|
|
|
+❌ -XX:+UseConcMarkSweepGC # 删除:Java 17 已弃用 CMS
|
|
|
+❌ -XX:+CMSParallelRemarkEnabled # 删除:CMS 参数
|
|
|
+❌ -XX:+UseCMSCompactAtFullCollection # 删除:CMS 参数
|
|
|
+❌ -XX:+UseCMSInitiatingOccupancyOnly # 删除:CMS 参数
|
|
|
+❌ -XX:CMSInitiatingOccupancyFraction=70 # 删除:CMS 参数
|
|
|
+```
|
|
|
+
|
|
|
+**删除原因:**
|
|
|
+- Java 9+ 已弃用 CMS GC
|
|
|
+- Java 17 使用 **G1GC** 作为默认垃圾回收器
|
|
|
+- CMS 参数写了完全不生效
|
|
|
+- 应该显式指定 `-XX:+UseG1GC`(可选,Java 17 已默认)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+#### 4. **其他过时或无效参数**
|
|
|
+
|
|
|
+```bash
|
|
|
+❌ -server # 删除:K8S 容器已是服务模式
|
|
|
+❌ -XX:LargePageSizeInBytes=128m # 删除:K8S 不推荐使用大页面
|
|
|
+❌ -XX:+UseFastAccessorMethods # 删除:现代 JVM 已默认优化
|
|
|
+```
|
|
|
+
|
|
|
+**删除原因:**
|
|
|
+- `-server`:容器环境本质就是服务器模式,指定无意义
|
|
|
+- `-XX:LargePageSizeInBytes`:K8S 调度器更好地处理内存,不需要 JVM 干预
|
|
|
+- `-XX:+UseFastAccessorMethods`:Java 8+ JVM 自动启用,显式指定无效
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📝 K8S 中的正确配置
|
|
|
+
|
|
|
+在 Kubernetes 部署中,应该这样配置内存和 GC:
|
|
|
+
|
|
|
+```yaml
|
|
|
+# Deployment YAML 示例
|
|
|
+spec:
|
|
|
+ containers:
|
|
|
+ - name: shop-recycle-gateway
|
|
|
+ image: your-registry/shop-recycle-gateway:1.0.0
|
|
|
+ ports:
|
|
|
+ - containerPort: 1211
|
|
|
+
|
|
|
+ # ✅ 资源限制由 K8S 管理,不用 JVM 参数
|
|
|
+ resources:
|
|
|
+ requests:
|
|
|
+ memory: "512Mi"
|
|
|
+ cpu: "250m"
|
|
|
+ limits:
|
|
|
+ memory: "1024Mi"
|
|
|
+ cpu: "1000m"
|
|
|
+
|
|
|
+ # ✅ 环境变量配置
|
|
|
+ env:
|
|
|
+ - name: JAVA_OPTS
|
|
|
+ value: "-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Xss256k -XX:+DisableExplicitGC"
|
|
|
+
|
|
|
+ # ✅ 健康检查由 K8S 管理(比 Dockerfile HEALTHCHECK 更优)
|
|
|
+ livenessProbe:
|
|
|
+ httpGet:
|
|
|
+ path: /actuator/health
|
|
|
+ port: 1211
|
|
|
+ initialDelaySeconds: 40
|
|
|
+ periodSeconds: 10
|
|
|
+
|
|
|
+ readinessProbe:
|
|
|
+ httpGet:
|
|
|
+ path: /actuator/health/readiness
|
|
|
+ port: 1211
|
|
|
+ initialDelaySeconds: 30
|
|
|
+ periodSeconds: 5
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🚀 建议的 JVM 参数组合
|
|
|
+
|
|
|
+### 推荐方案(生产环境)
|
|
|
+
|
|
|
+```bash
|
|
|
+# 最小化方案:仅保留必须参数
|
|
|
+JAVA_OPTS="-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Xss256k -XX:+DisableExplicitGC"
|
|
|
+
|
|
|
+# 扩展方案:添加日志和监控参数
|
|
|
+JAVA_OPTS="-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Xss256k -XX:+DisableExplicitGC \
|
|
|
+ -XX:+UseG1GC -XX:MaxGCPauseMillis=200 \
|
|
|
+ -Dfile.encoding=UTF-8 -Duser.timezone=Asia/Shanghai"
|
|
|
+```
|
|
|
+
|
|
|
+**说明:**
|
|
|
+- `-XX:+UseG1GC`:显式启用 G1GC(可选,Java 17 已默认)
|
|
|
+- `-XX:MaxGCPauseMillis=200`:目标 GC 暂停时间 ≤ 200ms
|
|
|
+- `-Dfile.encoding=UTF-8`:字符编码
|
|
|
+- `-Duser.timezone=Asia/Shanghai`:时区设置
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📋 配置文件加载方式
|
|
|
+
|
|
|
+### 原始方案(仅加载单一文件)
|
|
|
+
|
|
|
+```bash
|
|
|
+--spring.config.location=/app/conf/application.yml
|
|
|
+```
|
|
|
+
|
|
|
+**问题:** 只能加载一个文件
|
|
|
+
|
|
|
+### ✅ 优化方案(加载目录下所有配置)
|
|
|
+
|
|
|
+```bash
|
|
|
+--spring.config.location=file:/app/conf/
|
|
|
+```
|
|
|
+
|
|
|
+**优势:**
|
|
|
+- 支持多个配置文件:`application.yml`, `application.properties`, `application-dev.yml` 等
|
|
|
+- Spring Boot 自动按优先级加载
|
|
|
+- 更灵活的配置管理
|
|
|
+
|
|
|
+**支持的配置文件格式:**
|
|
|
+```
|
|
|
+/app/conf/
|
|
|
+├── application.yml # 基础配置
|
|
|
+├── application-prod.yml # 生产环境特定配置
|
|
|
+├── application-prod-db.yml # 数据库配置
|
|
|
+└── application-prod-cache.yml # 缓存配置
|
|
|
+```
|
|
|
+
|
|
|
+**加载优先级(Spring Boot 默认):**
|
|
|
+1. `application.yml`
|
|
|
+2. `application-{profile}.yml`(根据 active profile)
|
|
|
+3. 环境变量覆盖
|
|
|
+4. 命令行参数最优先
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 🐳 Docker 构建和使用
|
|
|
+
|
|
|
+### 构建命令
|
|
|
+
|
|
|
+```bash
|
|
|
+docker build -t your-registry/shop-recycle-gateway:1.0.0 -f Dockerfile.optimized .
|
|
|
+```
|
|
|
+
|
|
|
+### 运行测试
|
|
|
+
|
|
|
+```bash
|
|
|
+# 使用环境变量设置 JAVA_OPTS
|
|
|
+docker run -d \
|
|
|
+ -e JAVA_OPTS="-Djava.awt.headless=true -Djava.net.preferIPv4Stack=true" \
|
|
|
+ -v /path/to/conf:/app/conf \
|
|
|
+ -p 1211:1211 \
|
|
|
+ your-registry/shop-recycle-gateway:1.0.0
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## 📊 优化效果汇总
|
|
|
+
|
|
|
+| 项目 | 优化前 | 优化后 | 改进 |
|
|
|
+|------|------|------|------|
|
|
|
+| 基础镜像 | openjdk:17.0.2-jdk-slim | eclipse-temurin:17-jre-alpine | **减少 70% 大小** |
|
|
|
+| 镜像包含物 | JDK + 工具 | JRE only | 移除不必要工具 |
|
|
|
+| JAVA_OPTS | 19 个参数 | 4 个参数 | 删除过时/冗余参数 |
|
|
|
+| 启动时间 | ~5-10s | ~2-3s | **更快启动** |
|
|
|
+| 内存管理 | JVM 参数控制 | K8S 资源限制 | **更清晰** |
|
|
|
+| 配置管理 | 单个文件 | 整个目录 | **更灵活** |
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## ✅ 最终检查清单
|
|
|
+
|
|
|
+- [x] 使用 alpine 最小镜像
|
|
|
+- [x] 删除所有过时的 GC 参数
|
|
|
+- [x] 删除内存相关 JVM 参数(由 K8S 管理)
|
|
|
+- [x] 保留必须的网络和线程参数
|
|
|
+- [x] 配置文件改为目录加载
|
|
|
+- [x] 添加健康检查(可选)
|
|
|
+- [x] 环境变量化 JAVA_OPTS
|
|
|
+- [x] 提供完整的 K8S 配置示例
|