跳转至

Build OpenJDK8u345(1001)

1)源镜像使用 frolvlad 封装好的 alpine-glibc 作为基础镜像. 再参考 fabric8io 的 jdk 构建方法,使用 run-java.sh 脚本进行构建封装,之后进行 JVM 调整并执行 Jar 包文件

FROM frolvlad/alpine-glibc:alpine-3.16_glibc-2.35

ARG JAVA_PACKAGE=8.345.01-r0
ARG RUN_JAVA_VERSION=1.3.8

ENV JAVA_APP_DIR=/deployments \
    JAVA_MAJOR_VERSION=8 \
    TZ=Asia/Shanghai \
    LANG='en_US.UTF-8' LANGUAGE='en_US:en'

RUN apk add --update tzdata curl openjdk8=${JAVA_PACKAGE} \
 && set -eux \
 && ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime \
 && echo ${TZ} > /etc/timezone \
 && rm -rf /var/cache/apk/* \
 && mkdir /deployments \
 && chown 1001 /deployments \
 && chmod "g+rwX" /deployments \
 && chown 1001:root /deployments \
 && echo "securerandom.source=file:/dev/urandom" >> /usr/lib/jvm/default-jvm/jre/lib/security/java.security \
 # 关闭安全套接字层SSL加密,防止与SQL_Server连接时报错,可按需忽略
 && sed -i 's/^jdk.tls.disabledAlgorithms=SSLv3/#&/' /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/java.security \
 && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
 && chown 1001 /deployments/run-java.sh \
 && chmod 540 /deployments/run-java.sh

USER 1001

CMD [ "/deployments/run-java.sh" ]

2)构建 APP 镜像,增加了 JAVA_OPTIONS 的 JVM 内存限制

PS:JAVA_APP_JARJAVA_MAIN_CLASS 可指定应用的入口 JAR 文件或 java 类,在未指定的情况下,脚本会查找根目录下唯一的 JAR 文件,应用根目录下必须有且仅有一个可执行的 JAR 文件,否则脚本会出错无法执行

FROM openjdk8:v1beta
ENV APP_PORT=8080
ENV JAVA_OPTIONS="-Xmx4096M -Xms4096M -Xmn1536M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M -XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+UseCGroupMemoryLimitForHeap -XX:+HeapDumpOnOutOfMemoryError -Djava.security.egd=file:/dev/./urandom -Dserver.port=8080"
# -Xms 定义堆的初始化大小,默认值是 物理内存的1/64(<1GB)
# -Xmx 定义最大堆的大小.默认为物理内存的1/4(< 1GB)
# -Xmn 定义年轻代的大小.整个JVM内存的大小 = 年轻代大小 + 老年代大小 + 持久代大小
# -Xss 设置每个线程的堆栈大小
# -XX:MetaspaceSize 元空间初始大小
# -XX:MaxMetaspaceSize 元空间最大可分配大小

# 创建工作目录(可选)
# WORKDIR /root/java

# 指定app暴露的端口
# EXPOSE 8080

COPY --chown=1001 app.jar /deployments/
COPY --chown=1001 healthcheck.sh /deployments/

USER 1001

# ENTRYPOINT ["sh","-c","java ${JAVA_OPTIONS} -jar /deployments/app.jar ${0} ${@}"]
ENTRYPOINT [ "/deployments/run-java.sh" ]

# HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost/${APP_PORT}/hello || exit 1
HEALTHCHECK --interval=5m --timeout=5s --retries=6 \
 CMD /bin/sh /deployments/healthcheck.sh

JVM 内存限制参考值

1
2
3
4
- 2G:-Xmx1344M -Xms1344M -Xmn448M  -XX:MaxMetaspaceSize=192M -XX:MetaspaceSize=192M
- 4G:-Xmx2688M -Xms2688M -Xmn960M  -XX:MaxMetaspaceSize=256M -XX:MetaspaceSize=256M
- 6G:-Xmx4096M -Xms4096M -Xmn1536M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M
- 8G:-Xmx5440M -Xms5440M -XX:MaxMetaspaceSize=512M -XX:MetaspaceSize=512M

3)创建健康检查脚本 healthcheck.sh

#!/bin/bash

# argv

# functions

function _main
{
  curl -sS 'http://localhost:8080/hello' > /dev/null
  [ $? -ne 0 ] && exit 1

  indexCount=`curl -sS 'http://localhost:8080/doc.html' | wc -l`
  [ $indexCount -eq 0 ] && exit 1

  exit 0
}

# main

_main "$@"

启动镜像容器,同时限制可用内存

1
2
3
4
5
6
$ docker run -itd --name=app-example \
-m 3g --memory-swap=4g \
--net host \
--restart always \
--spring.profiles.active=prod \
app:v1beta