Docker Timezones
Vor einiger Zeit hatte ich den Fall, dass innerhalb eines Docker-Containers die falsche Zeitzone eingestellt war. Das hat damit zu tun, dass Docker Containern eine eigene “interne” Zeitzone haben und nicht die des Host-OS nehmen.
Das Kommando im Container ergibt aber:
Wie man sieht, ist der Unterschied eine Stunde, im Container ist anscheinend UTC als Zeitzone Standard konfiguriert (Coordinated Universal Time). Auf dem Host jedoch CET (Central European Time) als Zeitzone.
In Linux-Containern lässt sich das relativ leicht beheben indem man die Datei /etc/localtime
aus dem Host in den Container mounted. Das gleicht die Zeitzone des Containers an die des Hosts an. Da der Container nicht auf die Datei schreiben können soll, fügt man :ro
hinter den Aufruf an: -v /etc/localtime:/etc/localtime:ro
. (Das ro
steht für read-only)
Der Aufruf wäre dann für das obige Beispiel:
Siehe hierzu auch: https://github.com/docker/docker/issues/3359
Das ganze wurde noch etwas vertrackter, da innerhalb des Containers dann eine JVM immernoch die falsche Zeit angezeigt hat.
JVM Timezones
Der Container hatte zwar die richtige Zeitzone, aber innerhalb der JVM wurde nicht die richtige Zeitzone aufgelöst.
Oracle hatte hierzu wenig hilfreiche Information https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/time-zone.html
Der offizielle Lösungsweg ist, ein JVM-Argument user.timezone
mitzugeben und dort den richtigen Eintrag anzugeben. Beispielsweise für Deutschland: Europe/Berlin
:
Es gibt jedoch auch einen einfacheren Weg, denn die Umgebungsvariable TZ wird ebenfalls ausgewertet. Diese kann einfach beim Start eines Containers mitgegegeben werden:
Das hat für unseren Anwendungsfall ausgereicht um innerhalb der JVM die korrekte Default TimeZone zu erhalten.
Selbst ausprobieren
In einem Ordner folgenden Inhalt in eine Datei TZ.java kopieren:
Keine Zeitzone setzen
Starten wir einen Docker-Container und rufen dann unser kleines Programm auf:
Wie man sieht ist der Container ist auf UTC gesetzt.
Zeitzone über Environment-Variable TZ setzen
Setzen wir eine Zeitzone mit -e TZ=Europe/Berlin
Das Ergebnis ist wie gewünscht Europe/Berlin
Setzen wir eine nicht existierend Zeitzone als TZ:
user.timezone
Nutzen wir das Property user.timezone erhalten wir folgendes Ergebnis
Interessanterweise ist es egal ob man einen ungültigen TZ-Wert mitgibt, wie man im nächsten Abschnitt sieht.
user.timezone und ungültiger TZ-Wert
TZ und user.timezone gleichzeitig? user.timezone gewinnt
Setzt man mit -Duser.timezone
eine unterschiedliche Zeitzone, so hat TZ keinen Effekt.
Ungültige Parameter für user.timezone
Setzt man einen ungültigen Parameter, so wird GMT genutzt, obwohl ein gültiger Wert für TZ gesetzt wurde.
Fazit
Die Grundeinstellung für Container ist UTC. Die Zeitzone kann man durch Umgebungsvariablen und durch Properties ändern.
Wenn user.timezone gesetzt ist, wird es auch ausgewertet. Das heißt: setzt man die Umgebungsvariable TZ und user.timezone, so hat TZ keinen Einfluss.
Wenn user.timezone fehlerhaft ist, wird das als GMT interpretiert.
Wichtige Empfehlung / Hinweis
Das hier ist eine Untersuchung, wie man im Container die Zeitzone korrekt setzen kann und wie sich das im Zusammenspiel mit der JVM verhält.
- Ich empfehle UTC zu nutzen.* - das muss ich hier nochmals wiederholen. Hintergründe gibt es unter anderem in diesem Artikel: http://yellerapp.com/posts/2015-01-12-the-worst-server-setup-you-can-make.html