Zeitzonen in Docker-Container

Zeitzonen in Docker-Container

Beim Auswerten der Logs diverser Docker-Container stieß ich auf ein Problem: Docker-Container hatten teilweise die lokale Zeitzone (CET, die auch auf dem Host konfiguriert ist), teilweise UTC-Zeit konfiguriert. Interessanterweise fand ich beim Debuggen noch eine weitere Zeitzone in einem anderen Docker-Container. Der Grund dafür: jeder Entwickler kann in seinem Dockerfile in 1 - 2 Zeilen Code eine beliebige Zeitzone setzen - was natürlich definitiv keine gute Praxis ist, aber dennoch in einem von mir verwendeten Container vorkam. Standard für die meisten Container ist übrigens UTC.

$ docker run --rm debian date
Tue Mar 23 19:13:37 UTC 2021

Um alle Container nun zu normalisieren (und die Logs dann auch leichter verarbeiten zu können) hat sich bei mir eine Kombination aus zwei Maßnahmen bewiesen:

Zeitzone per /etc/localtime setzen

Der Symlink /etc/localtime steuert in sämtlichen gängigen Linux-Distributionen die Zeitzone. Er verweist auf die entsprechende Datei unter /usr/share/zoneinfo.

$ ls -lah /etc/localtime
lrwxrwxrwx 1 root root 33 Feb  4 20:23 /etc/localtime -> /usr/share/zoneinfo/Europe/Berlin

Der einfachste Weg um die korrekte Zeitzone in einem Docker-Container zu konfigurieren ist die Datei /etc/timezone des Host-Systems zu mounten. Da der Container die Datei nicht ändern können soll, mounten wir sie einfach read-only.

$ docker run -v /etc/localtime:/etc/localtime:ro --rm debian date
Tue Mar 23 20:13:37 CET 2021

Die so gesetzte Zeitzone greift aber leider nicht für alle Anwendungen innerhalb eines des Docker-Containers:

$ docker run -v /etc/localtime:/etc/localtime:ro openjdk /bin/sh -c 'curl -s https://gist.githubusercontent.com/tldev-de/8a1c0247b59042dd4faa5c50b65d4754/raw/241697e9602ef79aac67a84b4594ef69290836c7/GetTimeZone.java > GetTimeZone.java && java GetTimeZone.java'

sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]

In diesem Minimalbeispiel downloaden wir eine Java-Klasse per wget, welche wir anschließend innerhalb des openjdk-Container ausführen. Als Zeitzone liefert uns Java GMT statt CET.

Zeitzone per Environment Variable setzen

Glücklicherweise gibt es einen weiteren Weg, wie wir die Zeitzone innerhalb eines Docker-Containers setzen können: die Environment-Variable TZ. Je nach Docker-Container ersetzt die Verwendung der Environment-Variable auch das Mounten der /etc/localtime: ist das Paket tzdata installiert, genügt das Überschreiben durch die Environment-Variable.

$ docker run -e TZ=Europe/Berlin openjdk /bin/sh -c 'curl -s https://gist.githubusercontent.com/tldev-de/8a1c0247b59042dd4faa5c50b65d4754/raw/241697e9602ef79aac67a84b4594ef69290836c7/GetTimeZone.java > GetTimeZone.java && java GetTimeZone.java'

sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]

Fazit

Ich für mich habe beschlossen den sicheren Weg zu ergreifen und beide Lösungen zu kombinieren. So habe ich bei allen meinen aktuell genutzten Containern die gleiche Zeitzone konfiguriert

$ docker run -e TZ=Europe/Berlin -v /etc/localtime:/etc/localtime:ro --rm debian date
Tue Mar 23 20:13:37 CET 2021


$ docker run -v /etc/localtime:/etc/localtime:ro -e TZ=Europe/Berlin openjdk /bin/sh -c 'curl -s https://gist.githubusercontent.com/tldev-de/8a1c0247b59042dd4faa5c50b65d4754/raw/241697e9602ef79aac67a84b4594ef69290836c7/GetTimeZone.java > GetTimeZone.java && java GetTimeZone.java'

sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]]