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 :