Docker can be super useful tool for DevOps. Suppose you need to test time sensitive software (behavior depends on the date). Other common time related use cases, such as running legacy software with y2k bugs, testing software for year-2038 compliance, debugging time-related issues, such as expired SSL certificates, running software which ceases to run outside a certain time frame, deterministic build processes.
You need to change time in Docker container to desire time zones. Changing time in Docker container environment can be done in several ways. We’ll go through that in this tutorial.
How to change time in Docker container
There are 6 ways to change time in a Docker container as we know as this tutorial written. To know the current time, the
date command can be used.
# docker exec -it <container-id> date
container-id with your container name or id.
To check the timezone configured in a Docker container, the
/etc/timezone file has to be checked.
# ￼docker exec -it <container-id> cat /etc/timezone# ￼docker exec -it <container-id> cat /etc/localtime
Or following command
# docker exec -it <container-id> bash -c "timedatectl | grep -i "time zone""Time zone: Europe/Prague (CEST, +0200)
1. Using date command
The easiest way to change date time in a Docker container is to change the time using
date command after connecting to the container.
# docker exec -it <container-id> /bin/bash# date +%T -s "11:03:00"11:03:00
Though the time zone change usually reflects immediately, in some cases, the container needs to be restarted to have effect.
2. Using environment variables
The timezone of a container can be set using an environment variable in the docker container when the container created for the first time.
# docker run -e TZ=Asia/Jakarta ubuntu date
Refer to this database time zones to get the list of database name.
tzdata is the time zone data needs to be installed in the container for setting this timezone variable. Usually, it is already installed inside the container. If not, you can install it yourself inside the container.
3. Using Dockerfile
In an enviroenment when there are many container and similar base containers to be spun up, the easiest way to manage is using Dockerfile and build Docker image yourself.
Dockerfile contains the basic configuration settings for each container. To change time in Docker container you need to add an entry to enable time zone that you desire in the corresponding Dockerfile.
The settings in the Dockerfile would reflect when a container is built or newly created. The following entry will add timezone to Dockerfile:
RUN sudo echo "Asia/Hongkong" > /etc/timezoneRUN sudo dpkg-reconfigure -f noninteractive tzdata
The installation command for
tzdata package would vary depend on the OS image that the container is using.
We also update the
/etc/timezone of the containers to include the timezone settings. This ensures that the date would be applied whenever the container is restarted.
4. Using volumes
A problem with Docker containers is that the data in the container is not persistent over restarts. That’s not best practice and against Docker philosophy. We use Docker data volumes overcome it with docker-compose solution.
Data volumes in Docker machines are shared directories that contains the data in the host and in the containers. The data in volumes are persistent and will not be lost during recreation of the containers.
/usr/share/zoneinfo in Docker contains the container time zones information. The time zone value from this folder can be copied to
/etc/localtime file, to set as default time.
This time zone files of the host machine can be set in Docker volume and shared among the containers by configuring it in the volumes parameter in the
docker-compose.yml as following.
volumes: - "/etc/timezone:/etc/timezone:ro" - "/etc/localtime:/etc/localtime:ro"
The containers built output from this
docker-compose.yml will have the same timezone as the host OS (as set in /etc/localtime file). Or, if you can put it in docker run as environment as following example.
docker run -d --restart=always --name mariadb -p 3306:3306 -v /etc/localtime:/etc/localtime:ro -v /etc/timezone:/etc/timezone:ro mariadb/server:10.3
5. Using NTP Server
We will use docker-ntp image as our NTP server. Pull and run using following command.
docker run --name=ntp \ --restart=always \ --detach=true \ --publish=123:123/udp \ --cap-add=SYS_NICE \ --cap-add=SYS_RESOURCE \ --cap-add=SYS_TIME \ cturra/ntp
To see status of NTP server:
docker exec ntp ntpctl -s status4/4 peers valid, clock synced, stratum 2
To sync your container with NTP server container, you need to have
ntpdate available, and do following step.
ntpdate -q <DOCKER_HOST_IP>
Here some output example
# ntpdate -q 10.10.102.182server 10.10.102.182, stratum 3, offset 0.010089, delay 0.0258529 Apr 07:20:52 ntpdate: adjust time server 10.10.102.182 offset 0.010089 sec
6. Using libfaketime
Another solution to change date time is to fake it in the container. This lib, libfaketime, intercepts all system call programs use to retrieve the current time and date.
The implementation is easy peachy. Add functionality to your Dockerfile as followings:
WORKDIR /RUN git clone https://github.com/wolfcw/libfaketime.gitWORKDIR /libfaketime/srcRUN make install
Remember to set the environment variables
LD_PRELOAD before you run the application you want the faked time applied to.
Following example how to use libfaketime.
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.
import osdef set_time(request): print(datetime.today()) os.environ["FAKETIME"] = "2020-01-01" # Note: time of type string must be in the format "YYYY-MM-DD hh:mm:ss" or "+15d" print(datetime.today())
But bee aware that this solution will not work for Golang applications or other statically linked exes.
There are many work around to change date time in your container. Choose your best practice