【问题标题】:Is it possible change date in docker container?docker容器中是否可以更改日期?
【发布时间】:2015-06-15 21:41:31
【问题描述】:

我有一个容器,里面有一个正在运行的程序的 tomcat。我只需要在这个容器中更改日期并测试我的程序行为。我有时间敏感的逻辑,有时需要看看几天或几个月后会发生什么。 在码头有可能吗?我读到如果我在容器中更改日期,主机系统上的日期将被更改。但这对我来说是个坏主意。我需要在一台服务器上拥有这个应用程序的几个实例,并且可以为每个实例设置不同的时间。

但是当我尝试更改容器内的日期时,我得到了错误:

sudo date 04101812
date: cannot set date: Operation not permitted
Fri Apr 10 18:12:00 UTC 2015

【问题讨论】:

标签: tomcat docker


【解决方案1】:

这在 Docker 中是不可能的。 Docker 使用与外部内核相同的时钟。您需要的是模拟完整 PC 的完全虚拟化。

sudo 失败,因为它只会使您成为容器内虚拟环境的root。此用户与主机系统的真实root 无关(名称和UID 除外),它不能做真实root 可以做的事情。

如果您使用 Python 或 Java 等高级语言,您通常可以使用挂钩来模拟特定系统时间进行测试,或者您可以编写包装“从系统获取当前时间”并返回测试所需内容的代码。

特别是对于 Java,使用 joda-time。在那里你可以使用DateTimeUtils.setCurrentMillis*() 注入你自己的时间源。

【讨论】:

  • Docker 使用与外部内核相同的时钟。这是否意味着可以更改主机日期和时间?
  • @otong 是的,但它会影响所有正在运行的容器和主机系统本身。
【解决方案2】:

在不影响主机操作系统的情况下,动态更改 Docker 容器中的时间是非常可能的。

解决方案是伪造它。 This lib 拦截所有用于检索当前时间和日期的系统调用程序。

实施很简单。根据需要向 Dockerfile 添加功能:

WORKDIR /
RUN git clone https://github.com/wolfcw/libfaketime.git
WORKDIR /libfaketime/src
RUN make install

请记住在运行要应用伪造时间的应用程序之前设置环境变量LD_PRELOAD

例子:

CMD ["/bin/sh", "-c", "LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1 FAKETIME_NO_CACHE=1 python /srv/intercept/manage.py runserver 0.0.0.0:3000]

您现在可以动态更改服务器时间:

例子:

def set_time(request):
    import os
    import datetime
    print(datetime.datetime.today())
    os.environ["FAKETIME"] = "2020-01-01"  #  string must be "YYYY-MM-DD hh:mm:ss" or "+15d"
    print(datetime.today())

【讨论】:

  • 这在 Docker 容器中工作。我 docker exec'd 安装库并使用 export 设置变量。
  • 这个解决方案也非常适合我。我按照上面 Roman 的建议做了,进入容器,使用 git 检查代码,运行 make install,然后将我的更改提交到图像,并使用以下方法重新启动容器 docker run -it --rm [various options omitted] spooforbrains/image1 /bin/bash -c "export LD_PRELOAD=/usr/local/lib/faketime/libfaketime.so.1; export FAKETIME_NO_CACHE=1; export FAKETIME=\"2016-05-01 12:00:00\"; node nodeimage"
  • 不,我在 Docker 容器中运行的网络服务器中使用该功能。该示例与设置无关。它只是配置后如何使用lib的示例。
  • 啊,所以一旦在 Dockerfile 中使用 CMD 加载库,您只需更改 FAKETIME 环境变量,时间会调整吗?漂亮。
  • 这不适用于 golang 应用程序和其他静态链接的东西
【解决方案3】:

这对我有用,也许你可以试试:

dpkg-重新配置 tzdata

编辑:在您遇到问题的容器内执行它。会出现一个界面。例如,您可以在那里编辑时区和本地时间,并正确设置它,这解决了我的问题,这与您的问题相同。

祝你好运!

【讨论】:

  • @zwolin 您需要在容器中安装包debconf(如果您使用的是 Debian 基础映像)。对于其他发行版,您需要查看他们的文档)
  • 这个是配置时区,这个不回答问题
  • 如何有 14 个人对不回答问题的答案投了赞成票?
【解决方案4】:

对我来说,我实际上需要设置实际的测试日期。我发现以下选项适用于 Mac,但您必须意识到您将更改所有容器的日期,因为您正在更改 Docker 用于其所有容器的底层 Alpine VM 的日期。

选项 1:更改主机的日期并重新启动 docker

在以下情况下使用它:

  • 你可以重启docker。
  • 您可以更改主机的日期

步骤:

  1. 停止容器。
  2. 通过日期和时间首选项更改机器的日期
  3. 重启 docker。
  4. 启动您的容器。

再次运行此序列以返回正确的日期和时间。

选项 2:更改 Alpine VM 的日期

在以下情况下使用它:

  • 您无法重新启动 docker。
  • 您无法设置主机的日期

步骤:

  1. screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
    • 屏幕开始空白,按回车几次。
  2. date -s [hh:mm]
    • 您的所有 docker 容器现在都将拥有您的新时间。你可以 也可以使用其他格式,查找有关“busybox date”的文档 它与其他 date 实现不太一样。
  3. 退出点击control-a :并输入d
    • 这会分离屏幕会话,但让 tty 继续运行。

重置时间:

  1. screen -r
    • 这会恢复您的 tty。
  2. ntpd -q
    • 这使用了 /etc/ntp.conf 中定义的服务器(这看起来像是回到主机时钟的魔法桥)
  3. 退出点击control-a :并输入quit
    • 这会终止您的 screen 和 tty 会话。

【讨论】:

    【解决方案5】:

    我创建了一个包含 libfaketime 的 Docker 映像以用于 Alpine,但该过程可以在其他发行版中完成。

    这是一个使用 Java 的例子,使用 Groovy 作为例子。但是也可以使用Tomcat。

    FROM groovy:alpine
    COPY --from=trajano/alpine-libfaketime  /faketime.so /lib/faketime.so
    ENV LD_PRELOAD=/lib/faketime.so \
        DONT_FAKE_MONOTONIC=1
    

    然后在执行 docker run 时构建并传递 FAKETIME 环境变量

    docker build -f fakedemo-java.Dockerfile . -t fakedemo
    docker run --rm -e FAKETIME=+15d fakedemo groovy -e "print new Date();"
    

    来源在trajano / alpine-libfaketime | Github,docker镜像在trajano/alpine-libfaketime | dockerhub

    我还创建了一个基于 Ubuntu 的变体:trajano / ubuntu-faketime | Github

    【讨论】:

      【解决方案6】:

      我的 jenkins docker 实例遇到了同样的问题,以下步骤解决了我的问题

      1. 执行到容器中

        docker exec -it 9d41c699a8f4 /bin/bash

      2. 查看时区 cat /etc/timezone : 输出等/UTC

      3. 使用 nano 设置新时区:亚洲/科伦坡(此处为您的时区)

      4. 重启容器

      【讨论】:

      • 原来的问题是设置日期而不是时区
      • 我得到:bash: /etc/timezone: Permission denied
      【解决方案7】:

      docker exec -it [Container Id] /bin/bash(执行到容器中)

      rm /etc/localtime(查看时区)

      ln -s /usr/share/zoneinfo/Asia/Karachi /etc/localtime(设置新时区)

      【讨论】:

      • 请为您的代码添加描述,以及您的代码实际在做什么。
      • 原来的问题是设置日期而不是时区
      猜你喜欢
      • 1970-01-01
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多