资讯专栏INFORMATION COLUMN

处理Docker容器化部署Tomcat服务碰到的时区问题

jay_tian / 2127人阅读

摘要:用工具容器化部署服务之后,碰到的问题比较多。问题处理过程多笔数据都是刚刚好差异个小时,那一般都是时区问题了。加上我是用容器化部署的,所以,我开始估计是的时区没弄正确导致的问题。当容器时区和宿主时区不一致,可以修改。

用Docker工具容器化部署服务之后,碰到的问题比较多。
其中比较特出的问题是这个时区问题。

1 问题现象:

举个例子,有个小功能,需要记录计划开始时间。
前台输入的时间是:2018.4.24 00:00:00。
后台记录的计划开始时间却是:2018.4.23 16:00:00。
可以看出,整整提前了8个小时。

2 问题处理过程:

多笔数据都是刚刚好差异8个小时,那一般都是时区问题了。
加上我是用docker容器化部署的,所以,我开始估计是Docker的时区没弄正确导致的问题。

验证问题:
Docker宿主查看时间:

[apiuser@xygerp-api software]$ date
2018年 04月 24日 星期二 15:00:05 CST

说明宿主的时区是木有问题的。

UTC是世界时区,CST是东八区时间
CST应该是指(China Shanghai Time,东八区时间)
UTC应该是指(Coordinated Universal Time,标准时间)

接着,exec进入容器,查看容器的时间有没有问题:

备注:为方便测试,我新建了一个docker容器(timezone-test)。
sudo docker run --name timezone-test -p 8800:8080 -v /etc/localtime:/etc/localtime chaimm/tomcat:1.1

进入容器,查看容器的时间:

[apiuser@xygerp-api software]$ sudo docker exec -it timezone-test /bin/sh
sh-4.2$ date
Tue Apr 24 15:05:14 CST 2018

可以看出,时区是没问题的,但是为什么运行在该容器的Tomcat服务的时区(无论是操作DB的时间,还是Tomcat的Log的时间)都是UTC?
例如下面的日志,log时间是:24-Apr-2018 07:03:55.381
应该是:24-Apr-2018 15:03:55.381才对。

24-Apr-2018 07:03:55.381 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/host-manager
24-Apr-2018 07:03:55.410 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/host-manager has finished in 29 ms
24-Apr-2018 07:03:55.410 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/manager
24-Apr-2018 07:03:55.431 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/manager has finished in 21 ms
24-Apr-2018 07:03:55.437 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [http-nio-8080]
24-Apr-2018 07:03:55.447 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [ajp-nio-8009]
24-Apr-2018 07:03:55.450 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 886 ms

这个问题困扰了我蛮久,最后经过找一些资料,发现原来是Tomcat启动的时候,时区实际是java启动的默认时区。
这样子,实际上很多时区:

时区功能 时区说明
Java JVM启动时候的时区。如果不指定,则默认取系统时区,就是:System.getProperty("user.timezone")
MySQL 数据库有时区,直接用:select now()可以查看确认。但是,Java的JDBC直接新增的数据是不会参考Mysql本身的时区。举个例子:INSERT什么时间就是什么时间!
Docker宿主 实际上是操作系统OS的时区。如果安装系统的时候选择中国上海时区,那一般是CST(中国时区)。
Docker容器 容器本身也是一个操作系统(虚拟系统)。当容器时区和宿主时区不一致,可以修改。如果有疑问可以直接exec到容器里面查看容器时区。
Tomcat服务 Tomcat是运行Java的Web应用服务器,所以,它的时区实际上就是JVM的时区。

从上面的表格可以看出,实际上,在Java中处理的时区,说到底还是以JVM启动的时候的时区为主!
只不过,大部分情况下,JVM启动如果没指定时区,那默认=操作系统的时区。
问题来了,如何确认JVM默认启动的时区是哪个?
这里有个小办法:

sh-4.2$ vi TestTimezone.java
public class TestTimezone{
   public static void main(String[] args){
      System.out.println(new java.util.Date());
      System.out.println(System.getProperty("user.timezone"));
   }
}

然后再编译并且运行它,看结果就知道JVM默认启动的时区是哪个了:

sh-4.2$ javac TestTimezone.java
sh-4.2$ java TestTimezone
Tue Apr 24 07:27:30 UTC 2018
UTC

从上面可以看出,就算我在Docker容器里面的系统时间已经是CST时区,但是,System.getProperty("user.timezone")是UTC,导致Java启动的时候,以UTC时区启动。
所以就出现了我碰到的问题!
这个才是根本原因。

备注: 同样的办法,在宿主执行,发现宿主就能抓取正确的时区。
[apiuser@xygerp-api software]$ java TestTimezone
Tue Apr 24 15:31:03 CST 2018
Asia/Shanghai
3 问题解决方案

既然发现了问题,是在Docker容器环境下,System.getProperty("user.timezone")抓的值不是CST时区导致的问题。那其中一个简单的解决办法是,在Tomcat启动的 时候,指定时区即可。
具体办法:

[apiuser@xygerp-api software]$ sudo docker exec -it timezone-test /bin/sh
sh-4.2$ ls
LICENSE        TestTimezone.class        bin   scripts
NOTICE           TestTimezone.java        conf  temp
RELEASE-NOTES  apache-tomcat-7.0.82        lib   webapps
RUNNING.txt    apache-tomcat-7.0.82.tar.gz  logs  work
sh-4.2$ cd bin/
sh-4.2$ vi catalina.sh
修改这里:
JAVA_OPTS="$JAVA_OPTS -Djava.protocol.handler.pkgs=org.apache.catalina.webresources -Duser.timezone=GMT+08"

保存您的修改,再重启启动docker:

[apiuser@xygerp-api software]$ sudo docker restart timezone-test
timezone-test
[apiuser@xygerp-api software]$ 

再查看timezone-test容器的log:

[apiuser@xygerp-api ~]$ sudo docker logs -f --tail 1000 timezone-test
24-Apr-2018 15:41:27.436 INFO [main] org.apache.catalina.core.AprLifecycleListener.lifecycleEvent The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
24-Apr-2018 15:41:27.629 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["http-nio-8080"]
24-Apr-2018 15:41:27.647 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
24-Apr-2018 15:41:27.650 INFO [main] org.apache.coyote.AbstractProtocol.init Initializing ProtocolHandler ["ajp-nio-8009"]
24-Apr-2018 15:41:27.652 INFO [main] org.apache.tomcat.util.net.NioSelectorPool.getSharedSelector Using a shared selector for servlet write/read
24-Apr-2018 15:41:27.652 INFO [main] org.apache.catalina.startup.Catalina.load Initialization processed in 809 ms
24-Apr-2018 15:41:27.683 INFO [main] org.apache.catalina.core.StandardService.startInternal Starting service Catalina
24-Apr-2018 15:41:27.683 INFO [main] org.apache.catalina.core.StandardEngine.startInternal Starting Servlet Engine: Apache Tomcat/8.5.9
24-Apr-2018 15:41:27.697 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/ROOT
24-Apr-2018 15:41:28.153 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/ROOT has finished in 456 ms
24-Apr-2018 15:41:28.154 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/docs
24-Apr-2018 15:41:28.179 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/docs has finished in 25 ms
24-Apr-2018 15:41:28.179 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/examples
24-Apr-2018 15:41:28.492 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/examples has finished in 312 ms
24-Apr-2018 15:41:28.492 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/host-manager
24-Apr-2018 15:41:28.524 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/host-manager has finished in 32 ms
24-Apr-2018 15:41:28.525 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /opt/tomcat/webapps/manager
24-Apr-2018 15:41:28.548 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /opt/tomcat/webapps/manager has finished in 23 ms
24-Apr-2018 15:41:28.555 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [http-nio-8080]
24-Apr-2018 15:41:28.565 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler [ajp-nio-8009]
24-Apr-2018 15:41:28.567 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 914 ms

可以看到,里面的日志的时间已经正确啦!

备注:上面的只是其中一个解决办法,也可以通过调整Docker容器的System.getProperty("user.timezone")的值,来让JVM在启动的时候能正确找时区!
还是那句话:出现问题的话,必须要找到问题出错的地方,才好解决问题啊!我就是绕了许多的弯路才找到问题的原因。一开始一直以为是Docker容器虚拟机的时区问题,所以困扰了很久!

更新:
另外一个做法,也可以解决这个问题:
其实就是启动容器的时候,指定时区即可。

sudo docker run --name timezone-test2 -p 8800:8080 -e TZ="Asia/Shanghai" -v /etc/localtime:/etc/localtime chaimm/tomcat:1.1

参考链接:
https://segmentfault.com/a/11...
https://www.jianshu.com/p/5b1...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/27299.html

相关文章

  • 设置docker容器(container)时区

    摘要:不废话,继续看以下命令这里配置的环境变量就是我所需要的时区通过这样的启动方式,就是了。当然聪明人肯定不会自己每次都在启动的时候加这些配置,当然在基础镜像里面搞好咯。 利用docker来部署服务,经常遇到的一个问题是如何解决容器内的时区问题. 假设现在启动的镜像是tomcat:8.0.35-jre8 /*直接用宿主机器上的时区默认覆盖容器内的时区配置文件即可,也就是跟宿主机器同样的时区配...

    gaosboy 评论0 收藏0
  • 设置docker容器(container)时区

    摘要:不废话,继续看以下命令这里配置的环境变量就是我所需要的时区通过这样的启动方式,就是了。当然聪明人肯定不会自己每次都在启动的时候加这些配置,当然在基础镜像里面搞好咯。 利用docker来部署服务,经常遇到的一个问题是如何解决容器内的时区问题. 假设现在启动的镜像是tomcat:8.0.35-jre8 /*直接用宿主机器上的时区默认覆盖容器内的时区配置文件即可,也就是跟宿主机器同样的时区配...

    ZoomQuiet 评论0 收藏0
  • Spring Boot + MongoDB 应用 Docker 实践

    摘要:本文旨在通过将一个具体的项目进行化处理,从而对的基本用法进行一次实践。该项目化后,后端服务访问数据库正常,仍然可以打开后端服务托管的单页应用,总之项目运行状态符合预期。 本文旨在通过将一个具体的 Spring Boot + MongoDB 项目进行 Docker 化处理,从而对 Docker 的基本用法进行一次实践。该项目 Docker 化后,后端服务访问数据库正常,仍然可以打开后端服...

    546669204 评论0 收藏0
  • Spring Boot + MongoDB 应用 Docker 实践

    摘要:本文旨在通过将一个具体的项目进行化处理,从而对的基本用法进行一次实践。该项目化后,后端服务访问数据库正常,仍然可以打开后端服务托管的单页应用,总之项目运行状态符合预期。 本文旨在通过将一个具体的 Spring Boot + MongoDB 项目进行 Docker 化处理,从而对 Docker 的基本用法进行一次实践。该项目 Docker 化后,后端服务访问数据库正常,仍然可以打开后端服...

    Caizhenhao 评论0 收藏0
  • Spring Boot + MongoDB 应用 Docker 实践

    摘要:本文旨在通过将一个具体的项目进行化处理,从而对的基本用法进行一次实践。该项目化后,后端服务访问数据库正常,仍然可以打开后端服务托管的单页应用,总之项目运行状态符合预期。 本文旨在通过将一个具体的 Spring Boot + MongoDB 项目进行 Docker 化处理,从而对 Docker 的基本用法进行一次实践。该项目 Docker 化后,后端服务访问数据库正常,仍然可以打开后端服...

    yacheng 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<