在Docker容器中部署Django的時區問題
現在容器化部署已經非常成熟瞭,我們很多服務都會使用容器部署,更新恢復都非常方便,但是有一個問題比較麻煩,就是時區處理,通常情況下,都采用註入 TZ 環境變量來解決,但是實際這種處理方式在 django 中卻是不行的。
Django 中與時區有關的配置
在Django的配置文件 settings.py 中,有兩個配置參數是跟時間與時區有關的,分別是TIME_ZONE和USE_TZ。我們期望著通過在 settings.py 中配置以後,Django 就能正確地獲取本地時間,但是實際上卻事與願違,我們看一看這兩個設置有什麼作用。
USE_TZ=True
如果 USE_TZ 設置為 True 時,Django 會使用系統默認設置的時區,此時的 TIME_ZONE 的設置基本是無效的,也就是無論有沒有設置都不起作用。
USE_TZ=False
如果 USE_TZ 設置為 False
- TIME_ZONE 設置為 None
- Django 還是會使用默認的時區
- 若 TIME_ZONE 設置為其它時區的話
如果是 Windows 系統,則 TIME_ZONE 設置是沒用的,Django會使用本機的時間
如果是其他系統,則會使用該時區的 UTC 時間
例如設置 USE_TZ = False, TIME_ZONE = ‘Asia/Shanghai’, 則使用上海的 UTC 時間。
到這一步,可能你會認為時間已經好瞭,但是實際上還沒有,我們還需要關註系統時區的設置。
Linux 容器中時區的設置
現在我本地時間是:16:15,Django 中設置為:USE_TZ = False, TIME_ZONE = ‘Asia/Shanghai’
不註入 TZ=Asia/Shanghai 環境變量
進入容器查看容器時間和時區
系統時間顯示的是 UTC 時區,時間為:08:15,剛好差 8 個小時
進入 Django 環境查看時間和時區
python manage.py shell from datetime import datetime datetime.now() # 輸出 datetime.datetime(2021, 10, 8, 8, 24, 8, 289230) from django.utils import timezone timezone.get_current_timezone_name() # 輸出 'Asia/Shanghai'
註入環境變量 TZ=Asia/Shanghai
進入容器查看時間和時區
系統時間顯示的是 Asia 時區,但是時間依然是 UTC 時間,並沒有顯示真正的本地時間
進入 Django 環境查看時間和時區
python manage.py shell from datetime import datetime datetime.now() # 輸出 datetime.datetime(2021, 10, 8, 8, 24, 8, 289230) from django.utils import timezone timezone.get_current_timezone_name() # 輸出 'Asia/Shanghai'
可以看到,雖然時區變瞭,但是時間卻還是 UTC 時間,無論是容器本身還是 Django 中
通過在網上查詢,我們知道修改 Linux 系統時區要修改 /etc/localtime 文件
修改 Linux 容器時區
通常的做法是將宿主機的 /etc/localtime 文件拷貝到容器的 /etc/localtime 文件,但是我們通過查詢發現 /etc/localtime 文件實際隻是一個軟連接,實際的文件是:/usr/share/zoneinfo/Asia/Shanghai
docker cp /usr/share/zoneinfo/Asia/Shanghai test:/etc/localtime
在不給容器註入 TZ=Asia/Shanghai 環境變量的情況下,我們登錄容器發現,容器的系統時間已經正確獲取到本地時間和時區瞭
如果註入瞭 TZ=Asia/Shanghai 環境變量,即使把 /etc/localtime 文件替換瞭,也隻是時區改變瞭,時間依然是 UTC 時間
進入 Django 環境查看時間
python manage.py shell from datetime import datetime datetime.now() # 輸出 datetime.datetime(2021, 10, 8, 8, 43, 43, 754698)
Linux 系統時間已經正常瞭,但是 Django 環境中的時間還是不正確,依然是 UTC 時間,這時候很多人就有點抓狂瞭,可能覺得是 settings.py 中的 USE_TZ 和 TIME_ZONE 設置有問題,其實問題並不在這裡。原因是因為 datetime 庫會去 /usr/share/zoneinfo/ 目錄下尋找 Asia/Shanghai 這個文件,而我們的鏡像中不包含這個目錄,所以 Django 還是使用瞭 UTC 時區。解決的辦法非常簡單:創建 /usr/share/zoneinfo/Asia 目錄,拷貝文件到這個目錄下就行瞭
# 在容器內(如不不存在這個目錄) mkdir -p /usr/share/zoneinfo/Asia # 在容器外 docker cp /usr/share/zoneinfo/Asia/Shanghai test:/usr/share/zoneinfo/Asia/Shanghai
然後登錄到容器內,進入 Django 環境下查看時間
python manage.py shell from datetime import datetime datetime.now() #輸出 datetime.datetime(2021, 10, 8, 16, 49, 32, 57)
這下時間就完全正確瞭。
總結
對於容器時區的問題,建議在容器制作階段,安裝並設置好 /etc/localtime,例如在 dockerfile 中添加如下語句
ADD /usr/share/zoneinfo/Asia/Shanghai /usr/share/zoneinfo/Asia/Shanghai RUN ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
這樣我們的容器在啟動時就無需關註時區問題瞭,如果容器已經制作好瞭,在啟動的時候掛載一下時區文件
docker run -d -v /etc/localtime:/etc/localtime -v /usr/share/zoneinfo/Asia/Shanghai:/usr/share/zoneinfo/Asia/Shanghai imageName
這種方式就比較麻煩。還有一種情況就是我們現在碰到的,服務已經上線瞭,發現時間有問題,就手動拷貝一下那兩個文件到容器中,然後重啟一下容器
docker cp /usr/share/zoneinfo/Asia/Shanghai test:/etc/localtime docker cp /usr/share/zoneinfo/Asia/Shanghai test:/usr/share/zoneinfo/Asia/Shanghai docker restart test
到此這篇關於在Docker容器中部署Django的時區問題的文章就介紹到這瞭,更多相關Docker部署Django時區內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- django時區問題的解決
- 解決docker中mysql時間與系統時間不一致問題
- Docker Alpine鏡像時區問題完美解決方案
- PyCharm創建Django項目的簡單步驟記錄
- Docker Compose搭建WordPress服務實現詳解