最近我在自己的樹莓派上使用docker跑java程序,發現幾個關於時區時間的設置問題,記錄如下
數據庫中的時間和編碼都不正確,
我檢查發現是我的jdbcurl中沒有配置不對,於是我把jdbcUrl改成如下:
jdbc:mysql://localhost:3306/daily?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
修改之後發現數據庫中的亂碼正常了,但是時間還是不對。
鏡像中時區不對
我使用docker exec -it 容器名 /bin/bash
命令進入容器中,使用date -R
命令查看時間發現時間相差八小時, 這應該是經典的時區設置不對了。
於是我進行大量百度,發現各種解決辦法, 於是我挑了一個看起來靠譜的方法。
docker run -v /etc/localtime:/etc/localtime -p 8443:8443 鏡像名稱:v1
原理是:百度的原因都是容器中時區文件/etc/localtime
不存在或者設置不對, 我想着既然宿主機的時區是對的, 我就把宿主機的時區設置進容器中,這樣容器不就和宿主機一樣的時區了。
運行起來後發現容器中的時間
date -R
命令查看後是正確的, 於是我以爲時間問題已經解決,便沒有在關注時間了
再次發現時區不對
我的程序運行一段時間後,我查看數據庫發現時間還是不對,我就十分鬱悶。 我再次進入容器查看時區發現是正確的, 也就是我的java程序在容器中的時區不正確,於是我再次開啓百度,發現這篇好文章 : Java程序與操作系統時區不一致問題的處理 這篇文章詳細講明白了java程序如何獲取時區信息的。 此處我在摘抄下文章中關於獲取時區的描述:
首先我們來看下Java程序是怎樣取得時區信息的。通過Oracle的官方文檔,我們可以知道其默認時區的獲取方式:
- Use the user.timezone property value as the default time zone ID if it’s available.
- Detect the platform time zone ID. The source of the platform time zone and ID mapping may vary with implementation.
- Use GMT as the last resort if the given or detected time zone ID is unknown.
從上面可以知道java顯示通過用戶的配置 user.timezone
作爲時區信息的, 如果user.timezone
沒有配置就會獲取運行平臺(linux)的配置的Zone ID作爲時區信息的,如果最後程序還是沒有獲取到時區信息 就會使用GMT時間作爲最後的時區信息(就是使用GMT+0)作爲最後的時區信息。
這篇文章中推薦解決辦法是在增加-Duser.timezone=Asia/Shanghai
啓動參數來解決問題。 這是一種方案。
但是我還是沒有弄明白我之前的解決方案爲何不行, 因爲我的解決方法應該符合java獲取時區的第二種方式的。 最後我還是在這篇文章中找到原因,文章中說的centos的系統的/etc/localtime
文件是使用軟連接的方式指向 /usr/share/zoneinfo/Asia/Shanghai
的。所以centos的時區就是Asia/Shanghai
。 於是我就懷疑我的宿主機(ubuntu)也是使用的軟連接的方式, 於是我運行命令:
ubuntu@ubuntu ~ % ls -li /etc/localtime
1346 lrwxrwxrwx 1 root root 33 May 21 06:21 /etc/localtime -> /usr/share/zoneinfo/Asia/Shanghai
發現確實如此啊, 我使用docker的-v 掛載的/etc/localtime 實際上只是宿主機的一個軟連接,所以容器中得時區不對
解決辦法: 將真實的宿主機的時區文件掛載到容器的時區文件中就可以解決時區不對的問題
下面是我的Dockerfile文件和啓動命令
FROM adoptopenjdk:11-jre-hotspot
# 設置容器的時區
RUN mkdir /opt/app
ADD xSpider-1.0-SNAPSHOT /opt/app/spider
EXPOSE 8443
VOLUME /log
VOLUME /home/ubuntu/mzitu
# 掛載時區的目錄
VOLUME /usr/share/zoneinfo
# 設置時區爲上海
ENV TZ=Asia/Shanghai
# 設置時區信息
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 啓動程序的腳本
ENTRYPOINT ["/opt/app/spider/bin/xSpider"]
啓動命令:
sudo docker run -d -v /home/ubuntu/projects/spider/log:/log -v /media/newsmy/mzi:/home/ubuntu/mzitu -v /usr/share/zoneinfo:/usr/share/zoneinfo --name xspider -p 8443:8443 xspider:v1
問題解決