标签归档:libfaketime

使用 libfaketime 修改 docker 容器时间

容器的时间问题:

如果想要直接进入容器,使用date -s修改日期,则会出现一个date: cannot set date: Operation not permitted的错误,而且也不会成功。

这是由于docker容器的隔离是基于Linux的Capability机制实现的, Linux的Capability机制允许你将超级用户相关的高级权限划分成为不同的小单元。目前Docker容器默认只用到了以下的Capability.

CHOWN, 
DAC_OVERRIDE, 
FSETID, 
FOWNER, 
MKNOD, 
NET_RAW, 
SETGID,  
SETUID, 
SETFCAP, 
SETPCAP, 
NET_BIND_SERVICE, 
SYS_CHROOT, 
KILL, 
AUDIT_WRITE

而要修改系统时间需要有SYS_TIME权限。使用 --cap-add, --cap-drop 可以添加或禁用特定的权限。--privileged参数也可以达到开放权限的作用, 与--cap-add的区别就是, --privileged是将所有权限给容器.

docker使用--privileged, --cap-add, --cap-drop 来对容器本身的能力进行开放或限制。

那么使用如下命令就可以直接改变时间了:

docker run -it --cap-add SYS_TIME --name centos centos /bin/bash

接着进入容器实行date命令修改时间,如果没有修改成功,,那么可能就是因为宿主机做了共享主机的localtime(比如laradock就做了):

docker run --name <name> -v /etc/localtime:/etc/localtime:ro  .... 
docker cp /etc/localtime:【容器ID或者NAME】/etc/localtime

如果修改成功一会就又恢复了,那么就可能要查看一下宿主机是否做了定时校准的任务。

但是如此执行之后,那就是容器时间变更为5月28日之后,宿主机的时间也跟着变更了, 因为上边操作的 --cap-add SYS_TIME是为了将宿主机的内核时间挂载进来与容器共享,因此容器时间更改了,宿主机时间也会跟着更改。

使用 libfaketime

由此可见,直接修改docker容器的时间是比较危险的,所以选择如下方案。

首先在宿主机上安装:libfaketime

git clone https://github.com/wolfcw/libfaketime.git
cd libfaketime  && make install

安装完成之后,把安装后的库文件拷贝到docker中:

docker cp /usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 e6e239e5fba7:/usr/local/lib/

然后再进入docker中执行命令改变环境变量:

export LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-5d"

改变环境变量之后,再执行脚本会发现时间已经改变。若想要恢复,直接把环境变量修改为空即可:

export LD_PRELOAD=

LD_PRELOAD是Linux系统的一个环境变量,它可以影响程序的运行时的链接(Runtime linker),它允许你定义在程序运行前优先加载的动态链接库。这个功能主要就是用来有选择性的载入不同动态链接库中的相同函数。通过这个环境变量,我们可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数库。一方面,我们可以以此功能来使用自己的或是更好的函数(无需别人的源码),而另一方面,我们也可以以向别人的程序注入程序,从而达到特定的目的。

如果需要修改容器中的各种web服务的时间,只需要在改变环境变量之后,重启服务即可。但是注意,镜像必须使用比较基础的镜像,因为如果直接使用服务的镜像(例如php镜像),会在重启的时候,整个容器会退出,faketime就会修改无效。

例如:

pkill php-fpm ; /usr/local/php/sbin/php-fpm

修改 faketime 步骤

第一步:需要通过dockerfile把libfaketime拷贝部分制作到基础镜像当中。 第二步:通过uuid来寻找要执行的pod。 第三步:修改pod的yaml文件(容器启动),把export LD_PRELOAD=/usr/local/lib/libfaketime.so.1 FAKETIME="-5d" 加入yaml,重启pod(会自动重启相应服务php、kong、nginx、go等),此时faketime生效。

参考:

时间测试神器libfaketime的使用

在做开发测试的时候,时常会遇到一些需要时间设置的问题,通常的时候,我们就是直接修改系统时间来完成,但是由于一般服务器上会跑着很多服务,一旦修改难免会影响到其他的程序,所以我们得找到一个方便的,只对自己需要使用的服务或进程修改时间,而不影响其他的,且修改方便的神器。好在有这么一款好用的:

根据其官方介绍如下:

 libfaketime会拦截程序用于检索的各种系统调用当前日期和时间。然后报告并修改(伪造)的日期和时间(由您用户指定的)到这些程序。这意味着您可以修改系统时间一个程序不需要改变系统范围内的时间。 libfaketime 允许您指定绝对日期(例如,01/01/2004)和相对日期(如10天前)。 例如,libfaketime可以用于各种目的 -确定构建过程 -调试与时间相关的问题,如过期的SSL证书 -测试软件在2038是否依旧合规

libfaketime附带一个名为“faketime”的命令行包装,易于使用,但不公开libfaketime的所有功能。如果你的 用例没有被faketime命令覆盖到,请确保查看此命令文档它是否可以通过直接使用libfaketime来实现。

当然还有很多的小伙伴,用它来破解一些macos下的有时间限制的软件。

安装使用

    git clone https://github.com/wolfcw/libfaketime.git

    cd libfaketime  && make install

ubuntu用户也可以使用这个:

    sudo apt-get update -y
    sudo apt-get install -y faketime

使用faketime命令

安装完成之后,就可以直接先查看一下faketime命令:

看一下此时的时间

date
2019年 11月 26日 星期二 14:46:25 CST

直接指定时间:

faketime '2018-03-27 21:04:52' date
20180327日 星期二 21:04:52 CST

指定时间从10天前开始

faketime -f '-10d' date
20191116日 星期六 14:48:43 CST

使用环境变量

这里我们使用一下php的脚本来执行测试一下,把php这个脚本的时间指定到15天前

php -r "echo date('Y-m-d H:i:s');"
2019-11-26 14:53:16

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="-15d" php -r "echo date('Y-m-d H:i:s');"
2019-11-11 14:53:16

首先这里要找到并确定libfaketime.so.1的安装位置,才可以直接赋予环境变量。

一些具体的使用方法可以在https://github.com/wolfcw/libfaketime/blob/master/test/test.sh 中查看。

示例

指定绝对日期2003-01-01 10:00:05作为运行测试程序

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="2003-01-01 10:00:05" php -r "echo date('Y-m-d H:i:s');"

# 该时间会一直保持不变

2003-01-01 10:00:05

在指定开始日期@2005-03-29 14:14:14的情况下运行测试程序

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="@2005-03-29 14:14:14" php -r "echo date('Y-m-d H:i:s');"

# 时间会从这里往后递增

2005-03-29 14:14:14

在指定10天前的情况下运行测试程序

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="-10d" NO_FAKE_STAT=1 php -r "echo date('Y-m-d H:i:s');"

# 时间会到10天前

在指定10天后并有加速因子的情况下运行测试程序

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1 FAKETIME="+10d x1" NO_FAKE_STAT=1 php -r "echo date('Y-m-d H:i:s'); sleep(10); echo PHP_EOL; echo date('Y-m-d H:i:s');"

2019-12-06 15:05:52
2019-12-06 15:06:02