Régler l’heure et la timezone sur Linux

Avant d’attaquer la partie Docker, il est nécessaire de rappeler comment régler le fuseau horaire et l’heure de nos serveurs Linux, puisque finalement ce sont les mêmes méthodes que nous allons utiliser pour synchroniser nos containers Docker basés sur Linux.

Avant toute chose, voyons l’état de l’heure courante :

$ date
Tue Nov 17 15:26:20 CET 2020

Il y a deux choses importantes ici :

  • Le fuseau horaire (timezone), ici CET pour Central European Time, l’heure de Paris pour faire court.
  • L’heure en elle-même, qui peut être ou non bien synchronisée. À comparer avec par exemple celle-ci.

Pour changer le fuseau horaire sur Linux, c’est très simple, il suffit de lancer la commande suivante et de suivre les instructions:

dpkg-reconfigure tzdata

Pour synchroniser l’horloge avec la bonne heure, on utilise un service qui s’appelle NTP pour Network Time Protocol. Assurons-nous que le service est bien installé et activé dans systemd.

Adaptez ces commandes à votre OS, ici pour Debian 10.

apt install ntp
systemctl enable ntp
systemctl start ntp

Il n’est pas nécessaire d’installer ntp dans les containers Docker, parce que leur horloge est basée sur celle du host.

Bien, maintenant que nous avons couvert les bases, assurons nous que nos containers Docker aient une horloge synchronisé, soient sur le bon fuseau horaire, et arrêtent de décaler chaque élément.

Utiliser la configuration de la machine host

C’est la solution la plus simple pour caler l’heure de vos containers : s’appuyer sur l’heure et le fuseau horaire de la machine host, celle qui héberge le service Docker.

En revanche cette solution ne fonctionne que si vous avez la maîtrise du host, et elle n’est pas applicable si vous envoyez vos containers dans un quelconque solution cloud.

Pour cela, on va monter en lecture seule deux volumes sur les fichiers de configuration de l’horloge du host dans nos containers.

Dans un docker run, on ajoute deux volumes :

docker run -d \
   -v /etc/timezone:/etc/timezone:ro \  
   -v /etc/localtime:/etc/localtime:ro \
   [...]

Ou avec un docker-compose.yml :

services:
  service_name:
    volumes:
      - "/etc/timezone:/etc/timezone:ro"
      - "/etc/localtime:/etc/localtime:ro"

Régler le fuseau horaire des containers

Si la méthode précédente ne peut pas s’appliquer, parce que vous n’avez pas la main sur le host, ou s’il est nécessaire d’avoir des fuseaux horaires différents sur différents containers, alors il faut pouvoir régler la timezone directement dans l’image Docker.

Avant tout, pour Alpine Linux, le paquet tzdata n’est pas inclus par défaut, il est donc nécessaire de l’ajouter manuellement dans le Dockerfile :

RUN apk add --no-cache tzdata

Pour changer le fuseau horaire de nos containers Linux, plutôt que d’utiliser dpkg-reconfigure qui est interactif, on va utiliser une petite subtilité et faire la manipulation manuellement dans notre Dockerfile.

Ce que fait cette commande, c’est d’une part de mettre à jour le fichier /etc/timezone avec le bon fuseau horaire, mais aussi de créer une copie du binaire associé à la timezone dans /etc/localtime. Faisons donc ça :

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

Cette méthode fonctionne partout, et permet de définir directement la variable d’environnement TZ détaillée dans la section suivante.

Vous pouvez tester ça très facilement avec la commande :

docker build -t tzalpine . && docker run -it --rm tzalpine
$ date
# la date doit avoir le bon fuseau horaire ici

L’OS est maintenant à jour à l’intérieur des containers, quels que soit la configuration et l’environnement. Il ne reste plus qu’à s’assurer que les différents logiciels prennent bien en compte le fuseau horaire.

La variable d’environnement TZ

Une bonne partie des langages de programmation et/ou frameworks modernes s’appuient sur la même variable d’environnement : TZ. C’est le cas par exemple pour régler l’heure en Python et sur NodeJS.

En la définissant, et avec celle du système d’exploitation, vous devriez couvrir une bonne majorité des cas d’utilisation.

Attention toutefois, cette variable peut être généralement être surchargée, si c’est le choix des développeurs. Dans ces cas là, il y a généralement une option disponible dans la configuration de l’outil que vous utilisez, ou parfois dans son UI.

Il suffit de la définir au lancement de votre container :

docker run -d \
   -e TZ=Europe/Paris \
   [...]

Ou dans le docker-compose.yml:

services:
  service_name:
    environment:
      - TZ=Europe/Paris

Configuration PHP

Évidemment, PHP utilise un fonctionnement différent et ne prend pas en compte la variable d’environnement TZ.

Pour régler l’heure en PHP, il faut définir la valeur du paramètre date.timezone dans le fichier php.ini.

[Date]
; Attention à bien enlever le point-virgule, qui signifie commentaire.
date.timezone = Europe/Paris

Conclusion

Voilà, en principe on a fait le tour du sujet. J’ai mis à jour la plupart des mes containers pour qu’ils prennent en compte ces modifications, et tout semble rouler à la perfection.

Si jamais vous rencontrez des cas où les manipulations décrites dans cet article ne sont pas suffisantes, n’hésitez pas à me le faire remonter - je mettrais à jour ce guide.


Ressources :