Czas i strefa czasowa kontenera dokowania (nie będzie odzwierciedlać zmian)

135

Skąd kontenery Docker uzyskują informacje o czasie? Stworzyłem kilka kontenerów z podstawowego ubuntu: zaufanego obrazu, a kiedy go uruchamiam i żądam „daty”, otrzymuję czas UTC.

Przez jakiś czas omijałem to, wykonując następujące czynności w moim pliku Dockerfile:

RUN sudo echo "America/Los_Angeles" > /etc/timezone

Jednak z jakiegoś powodu przestał działać. Przeszukując online zobaczyłem poniższe sugestie:

docker run -v /etc/timezone:/etc/timezone [image-name]

Obie te metody poprawnie ustawiają strefę czasową!

$ cat /etc/timezone
America/Los_Angeles
$ date
Tue Apr 14 23:46:51 UTC 2015

Czy ktoś wie, co daje?

Chockomonkey
źródło
3
Jeśli używasz Alpine, musisz tzdatanajpierw zainstalować , patrz tutaj github.com/gliderlabs/docker-alpine/issues/136
Belter
1
Do Twojej wiadomości . . Chcę ustawić strefę czasową kontenera w czasie wykonywania dokera, a nie w czasie kompilacji / pliku dokera. Korzystanie z -v /etc/localtime:/etc/localtime:rorodzaju prac (CentOS). W wierszu polecenia data kontenera zwraca datę w oczekiwanym formacie strefy czasowej. ALE jenkins działający w kontenerze uważa, że ​​strefa czasowa to UTC. Dlaczego? / etc / localtime to dowiązanie symboliczne do ../usr/share/zoneinfo/UTC w wbudowanym kontenerze. Zawartość pliku UTC w kontenerze jest teraz nową strefą czasową. Ale Jenkins (i być może inne oprogramowanie oparte na Javie) używa nazwy dowiązania symbolicznego, które wciąż jest „UTC”. Poszukiwanie rozwiązania. . .
gaoithe
1
Potrzebujesz 2 rzeczy, 1. kiedy tworzony jest kontener, użyj skryptu init do ustawienia / etc / localtime symlink i / etc / timezone oraz 2. dla strefy czasowej Jenkinsa wziętej z dwóch opcji java, opcje te należy przekazać do skryptu init, który rozpoczyna proces Jenkinsa. np. „-Dorg.apache.commons.jelly.tags.fmt.timeZone = America / New_York -Duser.timezone = America / New_York”. Przepraszamy, jest to specyficzne dla Jenkinsa, ale mam nadzieję, że przydatne dla niektórych innych użytkowników Jenkinsa.
gaoithe

Odpowiedzi:

208

Sekret polega na tym, że dpkg-reconfigure tzdatapo prostu tworzy /etc/localtimejako kopię, hardlink lub dowiązanie symboliczne (preferowane jest dowiązanie symboliczne) do pliku w /usr/share/zoneinfo. Można to zrobić całkowicie z pliku Docker. Rozważać:

ENV TZ=America/Los_Angeles
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

Jako bonus, TZ również zostanie poprawnie ustawiony w kontenerze.

Jest to również niezależne od dystrybucji, więc działa z prawie każdym Linuksem.

Uwaga: jeśli używasz obrazu alpejskiego, musisz zainstalować tzdatapierwszy. (zobacz ten problem tutaj )

Wygląda tak:

RUN apk add --no-cache tzdata
ENV TZ America/Los_Angeles
Michael Hampton
źródło
5
W Ubuntu: 16.04 (i może w innej wersji) musisz mieć tzdatazainstalowany pakiet, aby to działało.
Opsse
5
Czy jestem jedynym, który uważa, że ​​kodowanie strefy czasowej w Dockerfile nie jest zbyt mądre?
Wolfgang
1
@Wolfgang To jest przykład. Możesz podać go w inny sposób, który zwykle udostępniasz zmienne środowiskowe, takie jak wiersz poleceń, docker-compose.yml itp.
Michael Hampton
Zauważyłem, że przynajmniej dla obrazów opartych na Alpach wystarczyło ustawienie TZzmiennej. Nie musiałem konfigurować dowiązań symbolicznych ani niczego innego.
code_dredd
58

Zwykle wystarczy ustawić zmienną środowiskową w kontenerze dokowanym, na przykład:

docker run -e TZ=Europe/Amsterdam debian:jessie date

Oczywiście to też zadziała docker-compose.

Victor Klos
źródło
2
To wydaje się być najbardziej eleganckim sposobem. Uważaj, aby jakiś obraz podstawowy, na przykład ubuntu:16.04, nie zawiera tzdatapakietu, który powinien zostać dodany w Dockerfile.
Julien Fastré
1
+1 - zgadzam się z Julienem; wydaje się to być najbardziej eleganckim podejściem do ustawiania stref czasowych w czasie wykonywania. Działa to dobrze z CentOS. Obraz Alpine wymaga instalacji pakietu „tzdata”, który jest preferowany w porównaniu z konfiguracjami harcodowania w czasie kompilacji, chyba że dodatkowy ładunek obrazu 3 MB nie może być tolerowany :)
Frelling
To wydaje się dobre, ale wydaje się nie działać dla mnie (z CentOS 7.5.1804 i tzdata-2018e-3.el7.noarch)? smutna twarz
gaoithe
22

Najbardziej popularny jest montaż /etc/localtimena obrazie, więc jest on zsynchronizowany z obrazem host -v.

Ale patrz problem 12084 :

nie jest poprawny, ponieważ nie działa, gdy oprogramowanie wymaga zamiast tego pliku /etc/timezonedo ustawienia.
W ten sposób używasz pozostawia go jako wartość domyślną etc/UTC.

Ustaliłem, że tak naprawdę nie ma niezawodnego, eleganckiego sposobu ustawienia strefy czasowej wewnątrz kontenera dokowanego.
W końcu zdecydowałem się na to rozwiązanie:

Plik dokera aplikacji:

# Relocate the timezone file
RUN mkdir -p /config/etc && mv /etc/timezone /config/etc/ && ln -s /config/etc/timezone /etc/

Skrypt punktu wejścia do aplikacji:

# Set timezone as specified in /config/etc/timezone
dpkg-reconfigure -f noninteractive tzdata

Plik /configdokowania woluminu danych , zlokalizowany w określonym kraju lub regionie:

# Set the time zone
RUN echo "Europe/London" > /config/etc/timezone

... nie jest elegancki, ponieważ obejmuje 3 osobne pliki i odtwarza się /etc/localtimeprzy każdym uruchomieniu kontenera środowiska wykonawczego. Co jest raczej marnotrawstwem.

Działa jednak poprawnie i skutecznie osiąga separację między obrazem aplikacji podstawowej a każdą lokalizowaną konfiguracją dla poszczególnych krajów.
W 3 liniach kodu.

VonC
źródło
1
Dla mnie było to: RUN echo "Europe/London" > /etc/timezone
jpmottin
@jpmottin Więc trochę jak w serverfault.com/a/856593/783 ?
VonC
18

Możesz dodać swoje lokalne pliki (/ etc / timezone i / etc / localtime) jako wolumin w kontenerze dokera.

Zaktualizuj swoje docker-compose.ymlza pomocą następujących wierszy.

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

Teraz czas kontenera jest taki sam jak na twoim hoście

dzięki
źródło
Jeśli na serwerze dystrybucyjnym CentOS wprowadzisz polecenie echo "Europe/Paris" > /etc/timezoneprzed ponownym uruchomieniem kontenera.
CrazyMax
Czy to działa na hoście MacOS?
Redsandro
Nie działa w MAC
Marcello de Sales
To kiedyś działało na MacOS, ale po prostu spróbowałem go ponownie po długim czasie i otrzymałem następujące. Nie jestem pewien, czy przyczyną tego była High Sierra lub zmiana dokera: „doker: Odpowiedź błędu od demona: Odmowa montażu: Ścieżka / etc / localtime nie jest udostępniana z OS X i nie jest znana Dockerowi. Możesz skonfigurować udostępnione ścieżki z Dockera - > Preferencje ... -> Udostępnianie plików. Aby uzyskać więcej informacji, zobacz docs.docker.com/docker-for-mac/osxfs/#namespaces . ”
gae123
1
Spowoduje to uszkodzenie bazy danych zoneinfo, ponieważ / etc / localtime jest dowiązaniem symbolicznym (dlatego / usr / share / zoneinfo / Some / Thing prawdopodobnie zostanie zamontowany jako / usr / share / zoneinfo / UTC wewnątrz kontenera). Nie wspominając o tym, że zmieszałeś plik db z hosta z plikiem w kontenerze.
ionelmc
12

W obrazie Ubuntu 16.04 jest błąd. Rozwiązaniem było

    ENV TZ 'Europe/Tallinn'
    RUN echo $TZ > /etc/timezone && \
    apt-get update && apt-get install -y tzdata && \
    rm /etc/localtime && \
    ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \
    dpkg-reconfigure -f noninteractive tzdata && \
    apt-get clean
qwerty
źródło
1
Poważnie ... to jedyne rozwiązanie, które zadziałało!
Gerrat
1
Musiałem to również zrobić - wydaje się, że tzdata nie jest już domyślnie w niektórych dystrybucjach.
Peter
4

jeśli używasz obrazu dokera na podstawie ubuntu:

# Change the docker default timezone from UTC to SGT
echo "Asia/Singapore" > /etc/timezone
dpkg-reconfigure tzdata
date
Xianlin
źródło
3

Dzięki VonC za informację i link do problemu. To wydaje się być tak zawiłym bałaganem, więc przetestowałem mój własny pomysł na rozwiązanie tego problemu i wydaje się, że działa świetnie.

>docker run -it ubuntu:trusty /bin/bash
#dpkg-reconfigure tzdata

(postępuj zgodnie z instrukcjami, aby wybrać moją strefę czasową)

>docker commit [container-id] chocko/ubuntu:local

Następnie zaktualizowałem moje pliki Docker, aby odzwierciedlić to:

FROM chocko/ubuntu:local

Coś musi być z tym nie tak, ponieważ wydaje się, że zbyt łatwo go przeoczyć ... Czy to jest do przyjęcia?

Chockomonkey
źródło
Tego też próbowałem, ale strefa czasowa wciąż resetuje się po I exitkontenerze. To jest na Debianie.
Mike Chamberlain,
@MikeChamberlain, czy zdarzyło Ci się spróbować zaakceptować odpowiedź Michaela Hamptona powyżej? Sam tego nie wdrożyłem, ale sądzę, że jest to dobra droga, biorąc pod uwagę opinie, które otrzymała.
Chockomonkey
2

Dodając tutaj moje dwa centy, ponieważ próbowałem kilku z nich, ale żadne nie działało na obrazach alpejskich.

Jednak to załatwiło sprawę:

ENV TZ=America/Toronto
RUN apk update
RUN apk upgrade
RUN apk add ca-certificates && update-ca-certificates
RUN apk add --update tzdata
RUN rm -rf /var/cache/apk/*

[ Źródło ]

Alfa
źródło
1

Bardziej ogólny sposób ustawiania strefy czasowej w docker runargumentach:

-e TZ=`ls -la /etc/localtime | cut -d/ -f8-9`

Lub do ponownego użycia:

function GET_TZ () {
    ls -la /etc/localtime | cut -d/ -f8-9
}

...
-e TZ=`GET_TZ`
Mugen
źródło
nie pomaga, jeśli obraz podstawowy jest alpejski (5 MB), na którym nie ma zainstalowanej „tzdata”
max4ever