JVM输出日志-时区差异

2023-01-12  本文已影响0人  偷油考拉

故障现象

容器内时间,已经通过 ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 修正好了。

root@094bd0f1b1b2:/usr/local/tomcat# date
Fri Jan 13 11:09:02 AM CST 2023
root@e41641d35798:/usr/local/tomcat# date +%Z
CST
root@e41641d35798:/usr/local/tomcat# date +'%:z %Z'
+08:00 CST
root@e41641d35798:/usr/local/tomcat# ll /etc/localtime 
lrwxrwxrwx 1 root root 33 Jan 13 13:18 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
root@e41641d35798:/usr/local/tomcat# cat /etc/timezone 
Etc/UTC
root@e41641d35798:/usr/local/tomcat# echo $TZ


但是,docker logs 显示时间仍然不正常

2023-01-13 03:07:50.363  INFO 1 --- [nio-8080-exec-1] c.s.lis.pubfun.OptimisticLockDataCheck   : 不做校验
2023-01-13 03:07:50.398  INFO 1 --- [nio-8080-exec-1] c.s.lis.pubfun.OptimisticLockDataCheck   : 不做校验
2023-01-13 03:07:50.404  INFO 1 --- [nio-8080-exec-1] c.s.lis.pubfun.OptimisticLockDataCheck   : 不做校验

JVM怎么获取timezone信息

https://docs.oracle.com/en/industries/health-sciences/data-management-workbench/3.0/install-guide/verify-time-zone-setting-used-java-virtual-machine-jvm.html

  1. JVM uses the environment variable TZ if it is set.
  2. If TZ is not set, then JVM looks for the file /etc/sysconfig/clock and finds the ZONE entry.
  3. If neither TZ nor ZONE is set, JVM compares the contents of /etc/localtime to the files in /usr/share/zoneinfo looking for a match. The matching path and filename under /usr/share/zoneinfo provides the time zone.

故障分析

Java 在 unix 系统下如何判断 time zone ? 翻译如下

当没有设置 TZ 环境变量的时候, POSIX specification 并没有指定如何判断 timezone 。我在 Linux Standard Base 上没有找到相关资料。 base system library (GNU libc) 使用 /etc/localtime 来判断 timezone。在非嵌入式Linux上,/etc/localtime 是存储 timezone 信息的地方,理想情况这个故事就到此结束了。

(然而, FreeBSD 、NetBSD 、 OpenBSD 使用 /etc/localtime。 Solaris 还有一些其他系统使用 /etc/TIMEZONE。参考 Rosetta Stone for UnixDietlibc (used in some embedded Linux systems) 使用 /etc/localtime, uClibc 使用 /etc/TZ (unless patched).)

然而,Java 不是这么做的。DebianUbuntu 有一个 /etc/timezone 文件保存 timezone 的信息。这个文件用于系统打包,这样它就可以记住像Europe/Amsterdam这样的地理名称,而不仅仅是时区的描述(比如:CET、CEST和CEDT)。这不仅对利于人类理解,而且在更新地理区域设置时更坚实。Sun (现在是 Oracle) Java 偏向使用 /etc/timezone (Red Hat发行版对应于 /etc/sysconfig/clock ) see bug #6456628 而不是 /etc/localtimeOpenJDKgcj 随之效防。

参考:
How do I find the current system timezone?
Java Time Zone is messed up.

解决方案很简单:同时更新 /etc/timezone/etc/localtime 文件。在 DebianUbuntu上, 官方推荐使用 dpkg-reconfigure tzdata。只对一个应用设置时区,设置 TZ 环境变量即可 (在所有unix平台适用)。

解决方案

echo "Asia/Shanghai" > /etc/timezone 
dpkg-reconfigure -f noninteractive tzdata
sudo ln -fs /usr/share/zoneinfo/Europe/Dublin /etc/localtime
sudo dpkg-reconfigure -f noninteractive tzdata

Dockerfile 范例

FROM tomcat:9.0.69-jdk8-temurin
VOLUME $CATALINA_HOME/logs
ARG WAR_FILE=target/*.war
COPY $WAR_FILE ./webapps/
COPY ./docker-entrypoint.sh .
RUN set -eux; \
        \
        ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && dpkg-reconfigure -f noninteractive tzdata; \
        chmod +x ./docker-entrypoint.sh
EXPOSE 8080
ENTRYPOINT ["./docker-entrypoint.sh"]
CMD ["catalina.sh", "run"]
上一篇下一篇

猜你喜欢

热点阅读