1.Dockerfile文件
dockerfile
FROM alpine:3.17
CMD ["/bin/sh"]
MAINTAINER GLJ
ENV TIME_ZONE="Asia/Shanghai"
ENV ALPINE_GLIBC_PACKAGE_VERSION="2.34-r0"
# Install glibc
COPY locale.md glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk ./
COPY sgerrand.rsa.pub /etc/apk/keys/sgerrand.rsa.pub
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& apk add --no-cache ca-certificates libstdc++ fontconfig tzdata \
&& apk add --update ttf-dejavu \
&& fc-cache --force \
&& cp /usr/share/zoneinfo/$TIME_ZONE /etc/localtime \
&& echo $TIME_ZONE > /etc/timezone \
&& apk del tzdata \
&& mv /etc/nsswitch.conf /etc/nsswitch.conf.bak \
&& apk add --no-cache --force-overwrite glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk \
&& mv /etc/nsswitch.conf.bak /etc/nsswitch.conf \
&& cat locale.md | tr -d '\r' | xargs -i /usr/glibc-compat/bin/localedef -i {} -f UTF-8 {}.UTF-8 \
&& rm -f glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk locale.md \
&& rm -rf /var/cache/apk/* \
&& addgroup -g 2888 apps \
&& adduser -u 2888 -G apps -h /home/apps -D apps
# Support Chinese
ENV LANG=zh_CN.UTF-8
ENV LANGUAGE=zh_CN.UTF-8
# Install JDK1.8
ADD jdk-8u341-linux-x64.tar.gz /usr/local/jdk
ENV JAVA_HOME=/usr/local/jdk/jdk1.8.0_341
ENV JRE_HOME=$JAVA_HOME/jre
ENV CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
ENV PATH=$JAVA_HOME/bin:$PATH
FROM alpine:3.17
CMD ["/bin/sh"]
MAINTAINER GLJ
ENV TIME_ZONE="Asia/Shanghai"
ENV ALPINE_GLIBC_PACKAGE_VERSION="2.34-r0"
# Install glibc
COPY locale.md glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk ./
COPY sgerrand.rsa.pub /etc/apk/keys/sgerrand.rsa.pub
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& apk add --no-cache ca-certificates libstdc++ fontconfig tzdata \
&& apk add --update ttf-dejavu \
&& fc-cache --force \
&& cp /usr/share/zoneinfo/$TIME_ZONE /etc/localtime \
&& echo $TIME_ZONE > /etc/timezone \
&& apk del tzdata \
&& mv /etc/nsswitch.conf /etc/nsswitch.conf.bak \
&& apk add --no-cache --force-overwrite glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk \
&& mv /etc/nsswitch.conf.bak /etc/nsswitch.conf \
&& cat locale.md | tr -d '\r' | xargs -i /usr/glibc-compat/bin/localedef -i {} -f UTF-8 {}.UTF-8 \
&& rm -f glibc-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-bin-$ALPINE_GLIBC_PACKAGE_VERSION.apk glibc-i18n-$ALPINE_GLIBC_PACKAGE_VERSION.apk locale.md \
&& rm -rf /var/cache/apk/* \
&& addgroup -g 2888 apps \
&& adduser -u 2888 -G apps -h /home/apps -D apps
# Support Chinese
ENV LANG=zh_CN.UTF-8
ENV LANGUAGE=zh_CN.UTF-8
# Install JDK1.8
ADD jdk-8u341-linux-x64.tar.gz /usr/local/jdk
ENV JAVA_HOME=/usr/local/jdk/jdk1.8.0_341
ENV JRE_HOME=$JAVA_HOME/jre
ENV CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
ENV PATH=$JAVA_HOME/bin:$PATH
- 构建镜像
bash
docker build -t base-jdk8:v1
docker build -t base-jdk8:v1
2.第二种方式
dockerfile
# 基于alpine-glibc:alpine-3.17_glibc-2.34构建
FROM frolvlad/alpine-glibc:alpine-3.17_glibc-2.34
MAINTAINER GLJ
# Install JDK1.8
ADD jdk-8u341-linux-x64.tar.gz /usr/local/jdk
ENV JAVA_HOME=/usr/local/jdk/jdk1.8.0_341
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH=$JAVA_HOME/bin:$PATH
ENV TIME_ZONE="Asia/Shanghai"
# 安装 JRE
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& apk add --no-cache libstdc++ fontconfig tzdata \
&& apk add --update ttf-dejavu \
&& fc-cache --force \
&& cp /usr/share/zoneinfo/$TIME_ZONE /etc/localtime \
&& echo $TIME_ZONE > /etc/timezone \
&& apk del tzdata \
&& rm -rf /var/cache/apk/* \
&& addgroup -g 2888 apps \
&& adduser -u 2888 -G apps -h /home/apps -D apps
# 基于alpine-glibc:alpine-3.17_glibc-2.34构建
FROM frolvlad/alpine-glibc:alpine-3.17_glibc-2.34
MAINTAINER GLJ
# Install JDK1.8
ADD jdk-8u341-linux-x64.tar.gz /usr/local/jdk
ENV JAVA_HOME=/usr/local/jdk/jdk1.8.0_341
ENV JRE_HOME ${JAVA_HOME}/jre
ENV CLASSPATH .:${JAVA_HOME}/lib:${JRE_HOME}/lib
ENV PATH=$JAVA_HOME/bin:$PATH
ENV TIME_ZONE="Asia/Shanghai"
# 安装 JRE
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories \
&& apk add --no-cache libstdc++ fontconfig tzdata \
&& apk add --update ttf-dejavu \
&& fc-cache --force \
&& cp /usr/share/zoneinfo/$TIME_ZONE /etc/localtime \
&& echo $TIME_ZONE > /etc/timezone \
&& apk del tzdata \
&& rm -rf /var/cache/apk/* \
&& addgroup -g 2888 apps \
&& adduser -u 2888 -G apps -h /home/apps -D apps
3.镜像漏扫验证
使用第三方,一定的进行镜像扫描
4.java案例
dockerfile
FROM base-jdk8:v1
USER gzapps
COPY --chown=apps:apps app.jar /home/apps/app.jar
# env for application
ENV PORT=""
ENV JAVA_OPTS=""
ENV AGENT_ARGS=""
EXPOSE $PORT
WORKDIR /home/gzapps
ENTRYPOINT ["/bin/bash","-c","java ${AGENT_ARGS} ${JAVA_OPTS} -jar app.jar"]
#ENTRYPOINT exec java -Djava.security.egd=file:/dev/./urandom -jar -Xms512m -Xmx512m -Xmn200M app.jar > app.jar.log
FROM base-jdk8:v1
USER gzapps
COPY --chown=apps:apps app.jar /home/apps/app.jar
# env for application
ENV PORT=""
ENV JAVA_OPTS=""
ENV AGENT_ARGS=""
EXPOSE $PORT
WORKDIR /home/gzapps
ENTRYPOINT ["/bin/bash","-c","java ${AGENT_ARGS} ${JAVA_OPTS} -jar app.jar"]
#ENTRYPOINT exec java -Djava.security.egd=file:/dev/./urandom -jar -Xms512m -Xmx512m -Xmn200M app.jar > app.jar.log
5.使用jlink构建自定义 JRE 镜像
以用来打包Java应用的基础镜像有几种,包括:
- JDK Alpine基础镜像:这些镜像体积较小,但不适合所有应用,因此可能会面临一些库的兼容性问题。
- JDK Slim基础镜像:这些镜像基于Debian或Ubuntu,相较于完整的JDK镜像来说体积较小,但仍然比较大。
- JDK完整基础镜像:这些镜像体积较大,包含运行应用所需的所有模块和依赖项。
❌ 注意
不能使用JRE镜像而使用JDK镜像,从Java 11开始,JRE不再可用
为了对比大小,我们采用openjdk:17-jdk-slim,eclipse-temurin:17-jdk-alpine
yaml
FROM openjdk:17-jdk-slim
# 设置容器中的工作目录
WORKDIR /app
# 创建用户
RUN addgroup --system spring && adduser --system spring --ingroup spring
# 切换到用户
USER spring:spring
COPY target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
FROM openjdk:17-jdk-slim
# 设置容器中的工作目录
WORKDIR /app
# 创建用户
RUN addgroup --system spring && adduser --system spring --ingroup spring
# 切换到用户
USER spring:spring
COPY target/*.jar app.jar
EXPOSE 8080
CMD ["java", "-jar", "app.jar"]
yaml
FROM eclipse-temurin:17-jdk-alpine
ARG APPLICATION_USER=spring
# 创建一个用户来运行应用,不以root用户运行
RUN addgroup --system $APPLICATION_USER && adduser --system $APPLICATION_USER --ingroup $APPLICATION_USER
# 创建应用目录
RUN mkdir /app && chown -R $APPLICATION_USER /app
# 设置运行应用的用户
USER $APPLICATION_USER
# 将jar文件复制到容器中
COPY --chown=$APPLICATION_USER:$APPLICATION_USER target/*.jar /app/app.jar
# 设置工作目录
WORKDIR /app
# 暴露端口
EXPOSE 8080
# 运行应用
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
FROM eclipse-temurin:17-jdk-alpine
ARG APPLICATION_USER=spring
# 创建一个用户来运行应用,不以root用户运行
RUN addgroup --system $APPLICATION_USER && adduser --system $APPLICATION_USER --ingroup $APPLICATION_USER
# 创建应用目录
RUN mkdir /app && chown -R $APPLICATION_USER /app
# 设置运行应用的用户
USER $APPLICATION_USER
# 将jar文件复制到容器中
COPY --chown=$APPLICATION_USER:$APPLICATION_USER target/*.jar /app/app.jar
# 设置工作目录
WORKDIR /app
# 暴露端口
EXPOSE 8080
# 运行应用
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
- 完整案例
yaml
# 第一阶段,构建自定义 JRE
FROM eclipse-temurin:17-jdk-alpine AS jre-builder
RUN mkdir /opt/app
COPY . /opt/app
WORKDIR /opt/app
ENV MAVEN_VERSION 3.5.4
ENV MAVEN_HOME /usr/lib/mvn
ENV PATH $MAVEN_HOME/bin:$PATH
RUN apk update && \
apk add --no-cache tar binutils
RUN wget http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz && \
tar -zxvf apache-maven-$MAVEN_VERSION-bin.tar.gz && \
rm apache-maven-$MAVEN_VERSION-bin.tar.gz && \
mv apache-maven-$MAVEN_VERSION /usr/lib/mvn
RUN mvn package -DskipTests
RUN jar xvf target/spring-error-handling-rfc-9457-0.0.1-SNAPSHOT.jar
RUN jdeps --ignore-missing-deps -q \
--recursive \
--multi-release 17 \
--print-module-deps \
--class-path 'BOOT-INF/lib/*' \
target/spring-error-handling-rfc-9457-0.0.1-SNAPSHOT.jar > modules.txt
# 构建小型 JRE 镜像,--add-modules ALL-MODULE-PATH
RUN $JAVA_HOME/bin/jlink \
--verbose \
--add-modules $(cat modules.txt) \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /optimized-jdk-17
# 第二阶段,使用自定义 JRE 并构建应用镜像
FROM alpine:latest
ENV JAVA_HOME=/opt/jdk/jdk-17
ENV PATH="${JAVA_HOME}/bin:${PATH}"
# 从基础镜像复制 JRE
COPY --from=jre-builder /optimized-jdk-17 $JAVA_HOME
# 添加应用用户
ARG APPLICATION_USER=spring
# 创建用户以运行应用程序,不以 root 身份运行
RUN addgroup --system $APPLICATION_USER && adduser --system $APPLICATION_USER --ingroup $APPLICATION_USER
# 创建应用程序目录
RUN mkdir /app && chown -R $APPLICATION_USER /app
COPY --chown=$APPLICATION_USER:$APPLICATION_USER target/*.jar /app/app.jar
WORKDIR /app
USER $APPLICATION_USER
EXPOSE 8080
ENTRYPOINT [ "java", "-jar", "/app/app.jar" ]
# 第一阶段,构建自定义 JRE
FROM eclipse-temurin:17-jdk-alpine AS jre-builder
RUN mkdir /opt/app
COPY . /opt/app
WORKDIR /opt/app
ENV MAVEN_VERSION 3.5.4
ENV MAVEN_HOME /usr/lib/mvn
ENV PATH $MAVEN_HOME/bin:$PATH
RUN apk update && \
apk add --no-cache tar binutils
RUN wget http://archive.apache.org/dist/maven/maven-3/$MAVEN_VERSION/binaries/apache-maven-$MAVEN_VERSION-bin.tar.gz && \
tar -zxvf apache-maven-$MAVEN_VERSION-bin.tar.gz && \
rm apache-maven-$MAVEN_VERSION-bin.tar.gz && \
mv apache-maven-$MAVEN_VERSION /usr/lib/mvn
RUN mvn package -DskipTests
RUN jar xvf target/spring-error-handling-rfc-9457-0.0.1-SNAPSHOT.jar
RUN jdeps --ignore-missing-deps -q \
--recursive \
--multi-release 17 \
--print-module-deps \
--class-path 'BOOT-INF/lib/*' \
target/spring-error-handling-rfc-9457-0.0.1-SNAPSHOT.jar > modules.txt
# 构建小型 JRE 镜像,--add-modules ALL-MODULE-PATH
RUN $JAVA_HOME/bin/jlink \
--verbose \
--add-modules $(cat modules.txt) \
--strip-debug \
--no-man-pages \
--no-header-files \
--compress=2 \
--output /optimized-jdk-17
# 第二阶段,使用自定义 JRE 并构建应用镜像
FROM alpine:latest
ENV JAVA_HOME=/opt/jdk/jdk-17
ENV PATH="${JAVA_HOME}/bin:${PATH}"
# 从基础镜像复制 JRE
COPY --from=jre-builder /optimized-jdk-17 $JAVA_HOME
# 添加应用用户
ARG APPLICATION_USER=spring
# 创建用户以运行应用程序,不以 root 身份运行
RUN addgroup --system $APPLICATION_USER && adduser --system $APPLICATION_USER --ingroup $APPLICATION_USER
# 创建应用程序目录
RUN mkdir /app && chown -R $APPLICATION_USER /app
COPY --chown=$APPLICATION_USER:$APPLICATION_USER target/*.jar /app/app.jar
WORKDIR /app
USER $APPLICATION_USER
EXPOSE 8080
ENTRYPOINT [ "java", "-jar", "/app/app.jar" ]