Reputation: 871
I have a container with a running program inside tomcat. I need to change date only in this container and test my program behaviour. I have time sensitive logic, and sometimes need to see what happens in a few days or months later. Is it possible in docker? I read that if I change date in container, date will get changed on the host system. But it is a bad idea for me. I need to have a few instances of this application on one server and have possibilities of setting up different time for each instance.
But when I try to change date inside the container I get the error:
sudo date 04101812
date: cannot set date: Operation not permitted
Fri Apr 10 18:12:00 UTC 2015
Upvotes: 87
Views: 144187
Reputation: 101
The solutions shown using libfaketime
didn't quite work for me using an ARM Mac to run debian-based images
aarm64
make
after cloning the the source repo didn't work in DebianLuckily, libfaketime
is available via apt-get
on Debian, so I simply took my third-party image, installed libfaketime
, and set the LD_PRELOAD
variable. Here was the new dockerfile I created:
FROM <upstream image>
RUN apt-get update && apt-get install -y libfaketime
ENV LD_PRELOAD=/usr/lib/aarch64-linux-gnu/faketime/libfaketime.so.1
The path for libfaketime.so.1
will depend on the architecture of <upstream image>
, but you can find it by running dpkg -L libfaketime
from inside the container.
Then I just passed the FAKETIME
environment variable in and everything worked.
Upvotes: 0
Reputation: 1
If you want to change the date of a container, you would need to relax security on your container by adding the --cap-add SYS_TIME
flag to your container at startup.
ie:
docker run --rm -it --cap-add SYS_TIME alpine date -s 2020-08-25
This will provide you more permissions on the container, without need be a root.
Here's a link for reference
You can also do this in kubernetes:
apiVersion: v1
kind: Pod
metadata:
name: hello-world
spec:
spec:
containers:
- name: friendly-container
image: "alpine:3.4"
command: ["/bin/echo", "hello", "world", "date -s 2020-08-25"]
securityContext:
capabilities:
add:
- SYS_TIME
Upvotes: -1
Reputation: 10848
My solution: I run docker on top of a virtualbox vm via vagrant.
This is not as complex as it sounds. The Vagrantfile
below resets the datetime of the vm to a specific one, before the machine goes up. The corresponding docker-compose provisioner takes care of automatically running the docker-compose.yml
.
Vagrantfile:
Vagrant.configure("2") do |config|
config.vm.define "ubuntuvm" do |ubuntuvm|
config.vm.box = "ubuntu/focal64"
config.vm.provision :docker
ubuntuvm.trigger.before :up do |trigger|
trigger.info = "changing time"
trigger.ruby do |env,machine|
require 'time'
machineTime = "2022/07/02 00:20:00"
offset = DateTime.parse(machineTime).strftime("%Q").to_i - DateTime.now.strftime("%Q").to_i
puts "Updating machine time to: #{machineTime} by shifting biossystemtime #{offset} ms"
puts `VBoxManage setextradata #{machine.id} "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled" 1`
puts `VBoxManage modifyvm #{machine.id} --biossystemtimeoffset #{offset}`
end
end
end
config.vm.hostname = "ubuntuvm"
# config.vm.network "forwarded_port", guest: 80 host: 8080
# config.vm.synched_folter "../data"", "/vagrant_data"
config.vm.provider "virtualbox" do |vb|
# vb.memory = "1024"
end
config.vm.provision :docker_compose, yml: "/vagrant/docker-compose.yml", rebuild: true, run: "always"
end
Then I just need to do a the following:
# start the machine and run the docker-compose
vagrant up
Everytime I start the machine I see the messages:
ubuntuvm: Updating machine time to: 2022/07/02 00:20:00 by shifting biossystemtime -212710744 ms
ubuntuvm: Running docker-compose up...
other commands:
# get inside the machine with ssh to check its time and also check the container's time (docker commands already exist inside there due to the provisioner).
vagrant ssh ubuntuvm
# stop the machine
vagrant halt
# destroy the machine
vagrant destroy
On the first run only, vagrant up
will fail to update the time because for some reason the before-up trigger is executed even before the machine is created. On all other executions the machine is already there, so the time is reset as expected.
Upvotes: 3
Reputation: 23
docker exec -it [Container Id] /bin/bash
(exec into container)
rm /etc/localtime
(see time zone)
ln -s /usr/share/zoneinfo/Asia/Karachi /etc/localtime
(set new time zone)
Upvotes: -1
Reputation: 41560
I created a Docker image containing libfaketime for use with Alpine but the process can be done in other distributions.
Here's an example of using it Java using Groovy as an example. But Tomcat can be used as well.
FROM groovy:alpine
COPY --from=trajano/alpine-libfaketime /faketime.so /lib/faketime.so
ENV LD_PRELOAD=/lib/faketime.so \
DONT_FAKE_MONOTONIC=1
Then build and pass the FAKETIME
environment variable when doing a docker run for example
docker build -f fakedemo-java.Dockerfile . -t fakedemo
docker run --rm -e FAKETIME=+15d fakedemo groovy -e "print new Date();"
Source is in trajano / alpine-libfaketime | Github and the docker image is in trajano/alpine-libfaketime | dockerhub
I also created a variant of it based on Ubuntu: trajano / ubuntu-faketime | Github
Upvotes: 12
Reputation: 814
I was having the same problem with my jenkins docker instance following steps fixed my problem
exec into container
docker exec -it 9d41c699a8f4 /bin/bash
See time zone
cat /etc/timezone
: out put Etc/UTC
set new time zone, with nano : Asia/Colombo (your timezone here)
Restart the container
Upvotes: -2
Reputation: 328760
That's not possible with Docker. Docker uses the same clock as the outside kernel. What you need is full virtualization which emulates a complete PC.
The sudo
fails because it only makes you root
of the virtual environment inside of the container. This user is not related to the real root
of the host system (except by name and UID) and it can't do what the real root
could do.
If you use a high level language like Python or Java, you often have hooks where you can simulate a certain system time for tests or you can write code which wraps "get current time from system" and returns what your test requires.
Specifically for Java, use joda-time. There you can inject your own time source using DateTimeUtils.setCurrentMillis*()
.
Upvotes: 20
Reputation: 14656
It is very much possible to dynamically change the time in a Docker container, without effecting the host OS.
The solution is to fake it. This lib intercepts all system call programs use to retrieve the current time and date.
The implementation is easy. Add functionality to your Dockerfile as appropriate:
WORKDIR /
RUN git clone https://github.com/wolfcw/libfaketime.git
WORKDIR /libfaketime/src
RUN make install
Remember to set the environment variables LD_PRELOAD
before you run the application you want the faked time applied to.
Example:
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]
You can now dynamically change the servers time:
Example:
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())
Upvotes: 84
Reputation: 931
For me, I actually needed to set the actual date for testing. I found the following options work on Mac, but you have to realize you'll be changing the date for all of your containers because you're changing the date of the underlying Alpine VM that Docker uses for all of its containers.
OPTION 1: Change the date of your host machine & restart docker
Use this when:
Steps:
Run this sequence again to get back to the right date & time.
OPTION 2: Change the date of the Alpine VM
Use this when:
Steps:
screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty
date -s [hh:mm]
control-a :
and type d
To reset the time:
screen -r
ntpd -q
control-a :
and type quit
Upvotes: 4
Reputation: 159
This worked for me, maybe you could try it:
dpkg-reconfigure tzdata
Edit: Execute it inside the container you are having problems. An interface will appear. There you can edit the timezone and localtime for example, and set it correctly, that fixed my problem, that was the same as yours.
Good luck!
Upvotes: 2