1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
# 第一阶段:使用基础镜像来下载和安装JDK
FROM alpine:3.18 as builder
# 设置 JDK 下载链接、SHA256 散列值和安装目录
ARG JDK_URL='https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.9%2B9/OpenJDK17U-jdk_x64_alpine-linux_hotspot_17.0.9_9.tar.gz'
ARG JDK_SHA256='c2a571a56e5bd3f30956b17b048880078c7801ed9e8754af6d1e38b9176059a9'
ARG JDK_DIR=/usr/lib/jvm/java17
# 安装必要的工具 ,binutils 是使用jlink所需的工具
RUN set -eux; \
apk add --no-cache wget tar gzip binutils;
# 下载并校验 JDK
RUN set -eux; \
wget -O jdk.tar.gz ${JDK_URL}; \
echo "${JDK_SHA256} *jdk.tar.gz" | sha256sum -c -; \
mkdir -p ${JDK_DIR}; \
tar --extract \
--file jdk.tar.gz \
--directory ${JDK_DIR} \
# 去除归档中每个文件路径的第一部分,因为每个JDK压缩包都有一个不同名的根文件夹
--strip-components 1 \
--no-same-owner; \
# 删除源文件,虽然这里删不删都不影响第二阶段
rm -f jdk.tar.gz ${JDK_DIR}/lib/src.zip;
# 设置环境变量
ENV JAVA_HOME=${JDK_DIR}
ENV PATH=$JAVA_HOME/bin:$PATH
# 编译用于检查 file.encoding 的 Java 类,在第二阶段中,由于没有javac,需要提前编译
RUN echo 'public class CheckEncoding { public static void main(String[] args) { System.out.println(System.getProperty("file.encoding")); } }' > CheckEncoding.java && \
javac CheckEncoding.java && \
rm CheckEncoding.java
# 使用 jlink 创建自定义 JRE,扫描jmods目录添加除GUI、实验性孵化模块以外的所有模块
# 特别注意的是,如果你使用spring程序,务必保留 jdk.unsupported 模块
# 否则会导致objenesis无法跳过构造函数创建代理,从而对没有默认构造函数的BEAN引发NoSuchMethodException
# https://stackoverflow.com/questions/51332334/nosuchmethodexception-springframework-boot-autoconfigure-http-httpmessageconver
# 如果是java 21+ 应使用 compress=zip-6 https://bugs.openjdk.org/browse/JDK-8293667
RUN set -eux; \
MODULES=$(ls ${JAVA_HOME}/jmods | sed 's/.jmod$//' | grep -vE 'java.desktop|jdk.incubator.foreign|jdk.incubator.vector' | tr '\n' ',' | sed 's/,$//') \
&& $JAVA_HOME/bin/jlink \
--module-path ${JAVA_HOME}/jmods \
--add-modules $MODULES \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /jre;
# 为最终镜像设置新的基础镜像
FROM alpine:3.18
# 注意第一阶段的变量无法保留到第二阶段
ARG JDK_HOME_DIR=/opt/java/jdk17
# 复制自定义 JRE 和 CheckEncoding.class 到新镜像
COPY --from=builder /jre ${JDK_HOME_DIR}
COPY --from=builder /CheckEncoding.class /CheckEncoding.class
# 设置环境变量
ENV JAVA_HOME=${JDK_HOME_DIR}
ENV PATH=$JAVA_HOME/bin:$PATH
# 添加所需软件
RUN set -eux; \
apk add --no-cache \
# utilities for keeping Alpine and OpenJDK CA certificates in sync
# https://github.com/adoptium/containers/issues/293
ca-certificates p11-kit-trust \
# locales ensures proper character encoding and locale-specific behaviors using en_US.UTF-8
musl-locales musl-locales-lang \
tzdata \
; \
rm -rf /var/cache/apk/*;
# 设置其它环境变量
ENV TZ='Asia/Shanghai'
ENV LANG=C.UTF-8
# 检查JAVA运行环境并删除 CheckEncoding.class
RUN set -eux; \
echo "Verifying install ..."; \
echo "java --version"; java --version; \
echo "file.encoding:"; java -cp / CheckEncoding | grep -q 'UTF-8'; \
rm -f /CheckEncoding.class; \
echo "Complete.";
|