容器环境 JVM 内存动态配置

容器环境 JVM 内存动态配置_第1张图片

  在微服务架构中, JAVA 框架占用了绝大部分的市场,比如 Spring CloudDubbo等,其中在使用容器化部署的时候经常碰到关于JVM的内存分配的大小的配置,以下来讲述自己所用到过的配置方式。

固定配置

此方式,顾名思义,就是将JVM参数进行固定化,比如在将JAR打包成容器镜像时

  FROM openjdk:8-jdk-alpine
LABEL maintainer="Shuhui<[email protected]>"

RUN set -xe \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk update \
    && apk add --no-cache ca-certificates ttf-dejavu fontconfig tzdata tini \
    && cp -rf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

COPY app.jar /
VOLUME ["/apps/logs"]

ENTRYPOINT ["/sbin/tini", "--", "java", "-jar", "-Xms1g", "-Xmx2g", "/scheduler.jar"]

可以看到,在容器运行时将JVM参数固定死了,也就是后续需要改动的话需要重新操作镜像。Em。。。 这种牵一发动全身的方式不可取。不推荐使用

环境变量

环境变量的方式可理解为固定配置的升级版本,就是将JVM参数包装成一个专用的环境变量,比如" JAVA_OPTS":

  FROM openjdk:8-jdk-alpine
LABEL maintainer="Shuhui<[email protected]>"

RUN set -xe \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk update \
    && apk add --no-cache ca-certificates ttf-dejavu fontconfig tzdata tini \
    && cp -rf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone

ENV JAVA_OPTS "-server -Xms1024m -Xmx2048m"

COPY app.jar /
VOLUME ["/apps/logs"]

ENTRYPOINT exec /sbin/tini -- java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar /app.jar

JVM参数直接引用一个叫 JAVA_OPTS的环境变量,后续需要改动时直接改动这个参数即可,比如,使用 configmap的方式:

  $ cat xx-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: xx-config
data:
  JAVA_OPTS: '-Xms1024m -Xmx2048m'

编排文件中引入

        containers:
      - image: #IMAGE_NAME#:#IMAGE_TAG#
        name: xx
        imagePullPolicy: IfNotPresent
        env:
        - name: JAVA_OPTS
          valueFrom:
            configMapKeyRef:
              name: xx-config
              key: JAVA_OPTS

当然,若你跟我一样,不喜欢套来套去--嫌弃使用 configmap繁琐,直接传参亦可:

          env:
        - name: JAVA_OPTS
          value: "-server -Xms2048m -Xmx4096m -Djava.security.egd=file:/dev/./urandom -Duser.timezone=GMT+08"

动态分配

jdk1.8.191的版本新增了以下 JVM参数,可以按容器所分配的内存资源大小去动态分配,我们无须去固定指定为个值的大小,这也是目前比较合理的一种方式,同时也是推荐的一种方式。。

参数 说明
-XX:InitialRAMPercentage=N 将初始堆大小设置为总内存的百分比
-XX:MinRAMPercentage=N 将最小堆大小设置为总内存的百分比
-XX:MaxRAMPercentage=N 将最大堆大小设置为总内存的百分比

提示: 如果已经配置了 -Xms, 那么 -XX:InitialRAMPercentage 参数将忽略,如果已经配置了 Xmx ,那么 -XX:MaxRAMPercentage 参数将忽略.

如果应用程序在容器中运行,并且指定了 -XX:+UseContainerSupport,则容器的默认堆大小(默认4分1的内存容量)。

示例: 通用的启动脚本中指定80%( -XX:MaxRAMPercentage=80.0 -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0)。那么以pod为1G的内存为例,服务就相当于设置了 -Xmx819m -Xms819m

  • Dockerfile 范例如下:
  FROM openjdk:8-jdk-alpine
LABEL maintainer="Qiu Shuhui<[email protected]>"

ARG user=shuhui
ARG group=shuhui
ARG uid=1000
ARG gid=1000
ARG APP_HOME=/app

ENV APP_HOME $APP_HOME
ENV JAVA_OPTS "-server -Djava.security.egd=file:/dev/./urandom"

RUN set -xe \
    && sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk update upgrade \
    && apk add --no-cache procps ca-certificates ttf-dejavu fontconfig curl tzdata tini bash \
    && cp -rf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
    && echo "Asia/Shanghai" > /etc/timezone \
    && rm -rf /var/cache/apk/*

RUN set -xe \
    && mkdir -p $APP_HOME \
    && chown ${uid}:${gid} $APP_HOME \
    && addgroup -g ${gid} ${group} \
    && adduser -h "$APP_HOME" -u ${uid} -G ${group} -s /bin/bash -D ${user}

COPY --chown=$user xx.jar $APP_HOME/app.jar

USER $uid
WORKDIR $APP_HOME


ENTRYPOINT ["/sbin/tini", "--"]
CMD ["java -XX:InitialRAMPercentage=80.0 -XX:MinRAMPercentage=80.0 -XX:MaxRAMPercentage=80.0 -jar /app.jar"]

此后,访问容器无需再设置 Xmx为固定值,随着CGroup的资源去动态分配。

参考引用

  • [1] https://blog.softwaremill.com/docker-support-in-new-java-8-finally-fd595df0ca54
  • [2] https://www.ibm.com/docs/en/sdk-java-technology/8?topic=options-xx-usecontainersupport
  • [3] https://stackoverflow.com/questions/54292282/clarification-of-meaning-new-jvm-memory-parameters-initialrampercentage-and-minr/54297753#54297753

你可能感兴趣的:(系统运维)