在Docker容器内运行Python脚本时,时区显示错误

11

我正在Docker容器(python:3.6)中运行脚本,但在日志中显示的时间不正确。当我在Python控制台中(容器内部)使用以下Python代码时,它会给出正确的时区。

import datetime
datetime.datetime.now()
datetime.datetime(2019, 8, 3, 17, 26, 25, 662809)

另外,当在容器内运行date命令时,它会显示正确的时区。

但是,我的脚本中有这个打印语句:

print("Updating....", datetime.datetime.now())

然而,这给了我错误的时区(比实际晚了2个小时)。

enter image description here

这是我的docker-compose.yml:

version: '3'
services:
  app:
    container_name: app
    build: .
    restart: unless-stopped
    environment:
      TZ: Europe/Amsterdam
    depends_on:
      - db
  db:
    container_name: db
    image: mariadb
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: x
      MYSQL_DATABASE: x
      MYSQL_USER: x
      MYSQL_PASSWORD: x
      TZ: Europe/Amsterdam
    volumes:
      - /volumes/x/db:/var/lib/mysql

这是我的crontab文件(在应用容器内运行)

CRON_TZ=Europe/Amsterdam

*/5 * * * * cd /usr/src/app && /usr/local/bin/python3.6 -u -m x > /proc/1/fd/1 2>/proc/1/fd/2
0,30 * * * * cd /usr/src/app && /usr/local/bin/python3.6 -u -m x > /proc/1/fd/1 2>/proc/1/fd/2
5 0 * * * cd /usr/src/app && /usr/local/bin/python3.6 -u -m x > /proc/1/fd/1 2>/proc/1/fd/2

我尝试在docker-compose.yml中设置时区,这对于date命令和Python控制台有效。我尝试在crontab文件中设置时区,但脚本仍然显示了错误的时区。

如何在crontab中为Python设置时区,以便日志记录具有正确的时区?另外,我需要在00:05而不是22:05运行脚本,现在可以实现吗?


你是在将脚本作为cronjob运行时才会得到错误的时间吗?看起来你得到的时间是UTC,因为中欧夏令时是UTC+02:00。 - Håken Lid
我不确定debian/ubuntu的cron版本是否使用CRON_TZ环境变量。(默认的python docker镜像是基于debian的) 我认为你需要按照@nick-rundle的答案建议,在容器中更改系统时区。在debian 10“buster”的[crontab(5)](https://manpages.debian.org/buster/cron/crontab.5.en.html)的manpage中没有提到CRON_TZ。 - Håken Lid
7个回答

8

如果您想要将容器内的时区与主机同步,可以将时区设置从主机映射过来。以下卷已成功实现了这一操作:

-v /etc/localtime:/etc/localtime

或者在您的docker-compose.yml文件中:

volumes:
    - /etc/localtime:/etc/localtime

在容器中使用不同的时区也是可能的。欧洲/阿姆斯特丹是中欧时间,所以这应该可以工作。/usr/share/zoneinfo/CET:/etc/localtime。(至少对于Debian/Ubuntu来说是这样。在其他发行版中路径可能会有所不同)。在Dockerfile中构建时也应该可以做到(作为root用户)。ln -sf /usr/share/zoneinfo/CET /etc/localtime - Håken Lid

3

对于大多数用户来说,在docker-compose.yml中为您的Python容器设置环境变量如下所示,应该足够有效:

   environment:
      TZ: America/New_York

这是使用CPython 3.8测试的。设置后请记得重新创建容器而不仅仅是重启容器。


致谢:Harsh Nagarkar的评论。


这应该是 TZ=America/New_York(等号而不是冒号)。否则,我可以确认这个工作得很好! - Avandale
2
@Avandale环境可以是地图或数组。如果它是一个地图,就像这个答案一样是正确的。如果它是一个数组,那么请注意前导破折号- key=value - The Fool

2

我曾经碰到过同样的问题,不过很遗憾,我不记得确切的解决方法了。但是这里有一些提示:

1)问题出在Docker上,而不是Python或datetime等其他东西。Docker容器难以知道时间。你要查找的是如何将容器内的时间与主机同步。

2)有许多建议处理容器中的时间的方法,但我记得它们都是某种程度上的解决方法。据我最后一次检查,还没有明确的解决方案。

3)我强烈建议您不要将cron作业放在容器中。如果您需要在特定的时间运行任务,请将cron作业放在主机上,并在需要时启动容器。这样更加可靠。


2
对于那些想知道他在说什么的人,他告诉你要添加这一行 ENV TZ="Africa/Lusaka"。谢谢。@Neil - Harsh Nagarkar
有人可以编辑这篇文章,将更多细节(比如上面的时区修复)整合到答案中吗?谢谢。 - Jean-François Fabre
对于任何直接查看此答案的人,虽然它是正确的,但你可能正在寻找来自Nick Rundle的答案。您需要将主机上的 /etc/localtime 复制到容器中。您可以使用Docker Compose中的“volumes”或使用docker run中的 -v 来完成此操作。 - Carvell Wakeman

0
非常奇怪的是,我有一个Python脚本将时间写入日志(以及其他内容)。
import time 
print(time.strftime("%c"))

例如,将返回“2022年3月15日星期二14:25:31”。 如果我连接到容器并启动python3,手动执行命令,则返回“2022年3月15日星期二15:25:31”。

容器的时区设置为TZ参数,如果我从容器中的shell运行“date”,则时间确实是预期的本地时间。如果我省略TZ,则会恢复为UTC时间。

我被迫将TZ作为参数传递给python脚本并进行处理。

import time
import os
os.environ['TZ'] = a
time.tzset()
print(time.strftime("%c"))

其中'a'是传递的参数

在我的Github项目中非常清晰:https://github.com/TrueOsiris/docker-godaddypy,因为它只有一个Dockerfile、一个bash脚本和一个python脚本。


0
你可以尝试在代码开头使用time.tzset(),或者你可以使用:
import detetime
import pytz

datetime.now(tz=pytz.timezone('Europe/Amsterdam'))

# or datetime.now(tz=pytz.timezone(os.environ.get('TZ'))

另外,请检查this


0

我通过将TZ环境变量传递给容器,并在logging.Formatter.converter中提供一个转换函数来解决了这个问题,如https://docs.python.org/3/library/logging.html所述。

根据https://www.redhat.com/sysadmin/tick-tock-container-time的说法,“通常,时区设置为构建镜像或基础镜像的位置,或者设置为UTC±00:00”。因此,我使用--tz=<时区>参数将时区传递给podman容器。如果是podman play kube,您可以将TZ值作为环境变量传递,如下所示。这将设置容器的时区。

....
spec:
  containers:
  - name: python
    env:
    -name: TZ
     value: "Asia/Colombo"
....

然后我修改了我的Python代码,分配了一个转换器函数。由于我想要容器的本地时间(即“亚洲/科伦坡”),所以我将下面的内容分配给了转换器。

logging.Formatter.converter = time.localtime


0

在构建镜像时,告诉您的Docker容器应该使用哪个时区。

例如,使用Dockerfile安装tzdata并设置ENV变量TZ。更多说明和Docker Engine和Compose的指令请参见此处

FROM ubuntu:16.04
 
# tzdata for timzone
RUN apt-get update -y
RUN apt-get install -y tzdata
 
# timezone env with default
ENV TZ=America/Bogota

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接