docker容器 java 默认读取系统时区问题

2 篇文章 0 订阅
1 篇文章 0 订阅

基于alpine构建的java基础镜像时区问题

alpine简介

alpine 是一个面向安全的轻型的Linux发行版。大小只有几兆。

当然知道这些对应本次话题没啥太大的帮助。想具体了解可以看一下 官网

我们基于alpine基础镜像构建我们的docker image dockerfile配置如下:

FROM openjdk:8-jdk-alpine
COPY /target/app-0.0.1-SNAPSHOT.jar /app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
问题

启动服务查看日志,发现日志比现在的时间少8个小时,java时区默认读取的系统时区,随手执行了一下date -R

    # date -R
Wed, 05 Dec 2018 10:16:15 +0800

系统时区是东八区,java时区默认读取系统时区 时间不应该少8个小时,然后具体有分析了一遍TimeZone

/**
* 获取默认时区
*/
public static TimeZone getDefault() {
        return (TimeZone) getDefaultRef().clone();
    }

    /**
  * Returns the reference to the default TimeZone object. This
  * method doesn't create a clone.
  */
 static TimeZone getDefaultRef() {
     TimeZone defaultZone = defaultTimeZone;
     if (defaultZone == null) {
         // Need to initialize the default time zone.
         defaultZone = setDefaultZone();
         assert defaultZone != null;
     }
     // Don't clone here.
     return defaultZone;
 }

 private static synchronized TimeZone setDefaultZone() {
     TimeZone tz;
     // get the time zone ID from the system properties
     String zoneID = AccessController.doPrivileged(
             new GetPropertyAction("user.timezone"));

     // if the time zone ID is not set (yet), perform the
     // platform to Java time zone ID mapping.
     if (zoneID == null || zoneID.isEmpty()) {
         String javaHome = AccessController.doPrivileged(
                 new GetPropertyAction("java.home"));
         try {
            //重点这句话
             zoneID = getSystemTimeZoneID(javaHome);
             if (zoneID == null) {
                 zoneID = GMT_ID;
             }
         } catch (NullPointerException e) {
             zoneID = GMT_ID;
         }
     }
      //注意这句话
     // Get the time zone for zoneID. But not fall back to
     // "GMT" here.
     tz = getTimeZone(zoneID, false);

     if (tz == null) {
         // If the given zone ID is unknown in Java, try to
         // get the GMT-offset-based time zone ID,
         // a.k.a. custom time zone ID (e.g., "GMT-08:00").
         String gmtOffsetID = getSystemGMTOffsetID();
         if (gmtOffsetID != null) {
             zoneID = gmtOffsetID;
         }
         tz = getTimeZone(zoneID, true);
     }
     assert tz != null;

     final String id = zoneID;
     AccessController.doPrivileged(new PrivilegedAction<Void>() {
         @Override
             public Void run() {
                 System.setProperty("user.timezone", id);
                 return null;
             }
         });

     defaultTimeZone = tz;
     return tz;
 }

 /**
  * Gets the platform defined TimeZone ID.
  **/
 private static native String getSystemTimeZoneID(String javaHome);

最终发现getSystemTimeZoneID(String javaHome)方法为本地方法。当然具体深究的话需要看JDK源码(openJDK上有完整的JDK源代码)。随手百度是个好习惯,这篇文章写得不错;

在Linux系统上,大概过程为以下几步:

  1. 先找TZ变量,没有,到2。
  2. /etc/timezone,没有到3。
  3. 比较/etc/localtime文件与"/usr/share/zoneinfo目录下所有时区文件,如果有一致的,就为该时区,如果没有,到4,
  4. 默认为标准GMT。

大致知道了这个过程,然后开始分析docker container ,进入容器查看相应的目录结构,echo $TZ 无输出 到2,未找到timezone文件 转3 有localtime 文件(再启动容器的时候localtime是挂载进去的) 然后再去查看ls /usr/share/zoneinfo 未找到该目录,最终发现alpine基础镜像并没有时区文件。

ok 问题最终找到,解决此类问题几种解决方法:

第一种: 挂载时区文件;
第二种: 配置TZ环境变量;
第三种: Dockerfile 添加RUN echo "Asia/Shanghai" > /etc/timezone 配置

over 。 如有不正确的地方,欢迎指正!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值