构建自定义JDK Docker镜像指南

构建自定义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. 常见问题处理
- 内存问题
# 限制容器内存
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
- 权限问题
# 检查文件权限
docker exec myapp ls -la /app
docker exec myapp id javauser
- JDK问题
# 验证JDK配置
docker exec myapp echo $JAVA_HOME
docker exec myapp java -XshowSettings:properties -version