构建自定义JDK Docker镜像指南

Jun 11, 2025·
Orochi
Orochi
· 3 min read

构建自定义JDK Docker镜像指南

1. 准备工作

1.1 下载JDK

从Oracle官网下载所需版本的JDK,例如:

  • JDK 8: jdk-8u381-linux-x64.tar.gz
  • JDK 11: jdk-11.0.20_linux-x64_bin.tar.gz
  • JDK 17: jdk-17.0.9_linux-x64_bin.tar.gz
  • JDK 21: jdk-21.0.2_linux-x64_bin.tar.gz

1.2 创建工作目录

# 创建工作目录
mkdir -p jdk_build/{jdk,app}
cd jdk_build

# 将下载的JDK文件复制到工作目录
cp /path/to/jdk-21.0.2_linux-x64_bin.tar.gz jdk/

2. 基础镜像构建

2.1 基础Dockerfile

# 使用轻量级基础镜像
FROM ubuntu:22.04

# 添加维护者信息
LABEL maintainer="your-email@example.com"
LABEL description="Custom JDK 21 Base Image"

# 设置工作目录
WORKDIR /opt

# 复制JDK压缩包
COPY jdk/jdk-21.0.2_linux-x64_bin.tar.gz .

# 安装必要的工具和依赖
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    curl \
    fontconfig \
    ca-certificates \
    tzdata \
    && rm -rf /var/lib/apt/lists/*

# 解压JDK并设置环境变量
RUN tar -xzf jdk-21.0.2_linux-x64_bin.tar.gz && \
    rm jdk-21.0.2_linux-x64_bin.tar.gz && \
    mv jdk-21.0.2 /opt/java

# 设置环境变量
ENV JAVA_HOME=/opt/java
ENV PATH=$JAVA_HOME/bin:$PATH

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    echo $TZ > /etc/timezone

# 验证安装
RUN java -version

3. 应用镜像构建

3.1 Spring Boot应用示例

# 使用我们的自定义JDK基础镜像
FROM custom-jdk:21.0.2

# 创建应用目录
WORKDIR /app

# 复制应用文件
COPY app/target/*.jar app.jar

# JVM配置
ENV JAVA_OPTS="\
    -Xms512m \
    -Xmx1024m \
    -XX:MetaspaceSize=128m \
    -XX:MaxMetaspaceSize=256m \
    -XX:+UseG1GC \
    -XX:MaxGCPauseMillis=200 \
    -Dfile.encoding=UTF-8 \
    -Duser.timezone=Asia/Shanghai \
    -Djava.security.egd=file:/dev/urandom"

# 创建非root用户
RUN groupadd -r javauser && \
    useradd -r -g javauser javauser && \
    chown -R javauser:javauser /app

# 切换到非root用户
USER javauser

# 暴露应用端口
EXPOSE 8080

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

4. 构建和使用说明

4.1 构建基础镜像

# 构建JDK基础镜像
cd jdk_build
docker build -t custom-jdk:21.0.2 -f Dockerfile .

# 验证基础镜像
docker run --rm custom-jdk:21.0.2 java -version

4.2 构建应用镜像

# 构建应用镜像
docker build -t myapp:1.0 -f Dockerfile.app .

# 运行应用容器
docker run -d \
    --name myapp \
    -p 8080:8080 \
    -v /data/logs:/app/logs \
    -e "SPRING_PROFILES_ACTIVE=prod" \
    myapp:1.0

5. 安全性建议

5.1 镜像安全

# 删除不必要的文件
RUN rm -rf $JAVA_HOME/lib/src.zip \
    $JAVA_HOME/man \
    $JAVA_HOME/lib/security/cacerts && \
    mkdir -p $JAVA_HOME/lib/security && \
    ln -s /etc/ssl/certs/java/cacerts $JAVA_HOME/lib/security/cacerts

# 限制容器权限
RUN chmod -R g-w /opt/java && \
    chmod -R o-w /opt/java

5.2 运行时安全

# 使用安全选项运行容器
docker run -d \
    --name myapp \
    --cap-drop ALL \
    --security-opt no-new-privileges \
    -p 8080:8080 \
    myapp:1.0

6. 监控和维护

6.1 健康检查

# 添加健康检查
HEALTHCHECK --interval=30s --timeout=3s \
    CMD curl -f http://localhost:8080/actuator/health || exit 1

6.2 日志配置

# 运行时配置日志
docker run -d \
    --name myapp \
    -p 8080:8080 \
    -v /data/logs:/app/logs \
    -e "LOGGING_FILE_PATH=/app/logs/app.log" \
    myapp:1.0

7. 常见问题处理

  1. 内存问题
# 限制容器内存
docker run -d \
    --name myapp \
    --memory="2g" \
    --memory-swap="2g" \
    -p 8080:8080 \
    myapp:1.0

# 使用docker-compose限制内存
cat > docker-compose.yml << EOF
version: '3.8'

services:
  myapp:
    image: myapp:1.0
    container_name: myapp
    ports:
      - "8080:8080"
    volumes:
      - /data/logs:/app/logs
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - JAVA_OPTS=-Xms512m -Xmx1024m
    deploy:
      resources:
        limits:
          memory: 2G
        reservations:
          memory: 1G
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
EOF

# 启动docker-compose
docker-compose up -d
  1. 权限问题
# 检查文件权限
docker exec myapp ls -la /app
docker exec myapp id javauser
  1. JDK问题
# 验证JDK配置
docker exec myapp echo $JAVA_HOME
docker exec myapp java -XshowSettings:properties -version
Orochi
Authors
充满活力和热情的软件从业者
在不同的公司和项目中工作过,担任过各种职务,做过各类项目(如企业站点、内部中台、边缘设备服务、客户端开发、大模型训练、大模型适配和任务调度等等),广泛的视野和经验.