Guide: fix all time and timezone problems in Docker
Adjust time and timezone on Linux
Before covering the Docker part of this guide, it is necessary to remember how to set up the time and timezone of Linux servers, because it’s the same methods that we are going to use afterwards to synchronize our containers, which are based on Linux.
First thing first, let’s take a look at the current time:
$ date
Tue Nov 17 15:26:20 CET 2020
There are two important things here:
- The timezone, here it’s CET for Central European Time, in short it’s Paris time.
- The hour itself, which can be well synchronized or not. You can compare it for example with this one.
In order to change the timezone on Linux, it’s pretty simple. You just need to run this command and follow the given instructions:
dpkg-reconfigure tzdata
To synchronize the clock with the right time, we use a service called NTP, for Network Time Protocol. Let’s make sure that it’s properly installed and enabled in systemd
.
Adapte these commands to your OS, here for Debian 10:
apt install ntp
systemctl enable ntp
systemctl start ntp
It’s not necessary to install
ntp
in Docker containers, as their clock is based on the host one.
Well, now that we covered the bases, we need to make sure that our Docker containers have their clock properly synchronized, are on the right timezone, and stop having interaction issues due to their datetime.
Use host machine configuration
This is the simplest solution for setting the time of your containers: using the time and time zone of the host machine, the one that hosts the Docker service.
On the other hand, this solution only works if you have control of the host, and it is not applicable if you send your containers into any cloud solution.
To do this, we will mount two volumes in read-only mode on the configuration files of the host clock in our containers.
In docker run
command, we add two volumes:
docker run -d \
-v /etc/timezone:/etc/timezone:ro \
-v /etc/localtime:/etc/localtime:ro \
[...]
Or with a docker-compose.yml
file:
services:
service_name:
volumes:
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
Set the time zone of the containers
If the previous method cannot be applied, either because you don’t have control over the host, or if it is necessary to have different time zones between different containers, then you need to be able to set the timezone directly in the Docker image.
First, for Alpine Linux, package tzdata
is not installed by default, so it’s necessary to add it manually in your Dockerfile:
RUN apk add --no-cache tzdata
To change the time zone of our Linux containers, instead of using dpkg-reconfigure
which is interactive, we will use a little subtlety and do the manipulation manually in our Dockerfile.
What this command does is on the one hand to update the /etc/timezone
file with the correct time zone, but also to create a copy of the binary associated with the timezone in /etc/localtime
. So let’s do this:
FROM alpine
ENV TZ=Europe/Paris
RUN apk add --no-cache tzdata
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
This method works everywhere, and allows you to directly define the TZ
environment variable detailed in the next section.
You can test your file this very easily with the command :
docker build -t tzalpine . && docker run -it --rm tzalpine
$ date
# the date must have the right time zone here
The OS is now up to date inside the containers, whatever the configuration or environment. All that’s left to do is to make sure that the different software takes the time zone into account.
TZ
environment variable
A good part of modern programming languages and/or frameworks rely on the same environment variable: TZ
. This is the case for example to set the time in Python and NodeJS.
By defining it, and together with the operating system one, you should cover a good majority of use cases.
Beware however, this variable can usually be overloaded, if it is the choice of the developers. In these cases, there is usually an option available in the configuration of the tool you are using, or sometimes in its UI.
You just have to set it when you launch your container :
docker run -d \
-e TZ=Europe/Paris \
[...]
Or in docker-compose.yml
:
services:
service_name:
environment:
- TZ=Europe/Paris
Configuration PHP
Obviously, PHP uses a different way and does not take into account the TZ
environment variable.
To set the time in PHP, you need to set the value of the date.timezone
parameter in the php.ini
file.
[Date]
; Be careful to remove the semicolon, which means it's a comment.
date.timezone = Europe/Paris
Conclusion
There, we should have covered the whole subject. I’ve updated most of my containers to take these changes into account, and everything seems to be running smoothly.
If you ever encounter cases where the manipulations described in this article are not sufficient, don’t hesitate to let me know - I will update this guide.
Ressources :
- https://serverfault.com/questions/683605/docker-container-time-timezone-will-not-reflect-changes
- https://stackoverflow.com/questions/24551592/how-to-make-sure-dockers-time-syncs-with-that-of-the-host/
- https://docs.docker.com/engine/reference/run/
- https://docs.docker.com/engine/reference/builder/
- https://github.com/nodejs/help/issues/36
- https://help.pythonanywhere.com/pages/SettingTheTimezone/
- https://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone