Conteneur Docker heure et fuseau horaire (ne refléteront pas les changements)

136

Où les conteneurs Docker obtiennent-ils leurs informations de temps? J'ai créé des conteneurs à partir de la base ubuntu: trusty image, et lorsque je l'exécute et demande la «date», j'obtiens l'heure UTC.

Pendant un certain temps, j'ai contourné cela en procédant comme suit dans mon fichier Docker:

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

Cependant, pour une raison quelconque qui a cessé de fonctionner. En recherchant en ligne, j'ai vu ce qui suit:

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

Cependant, ces deux méthodes définissent correctement le fuseau horaire!

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

Quelqu'un sait ce qui donne?

Chockomonkey
la source
3
Si vous utilisez Alpine, vous devez d' tzdataabord l' installer , voir ici github.com/gliderlabs/docker-alpine/issues/136
Belter
1
FYI. . . Je souhaite définir le fuseau horaire du conteneur au moment de l'exécution du menu fixe, pas au moment de la compilation / du fichier de base. En utilisant -v /etc/localtime:/etc/localtime:ro(CentOS) sorte de travaux. La date dans la ligne de commande du conteneur à l'intérieur renvoie la date dans le format de fuseau horaire prévu. MAIS Jenkins s'exécutant dans un conteneur pense que le fuseau horaire est au format UTC. Pourquoi? / etc / localtime est un lien symbolique vers ../usr/share/zoneinfo/UTC dans un conteneur construit. Le contenu du fichier UTC dans le conteneur est maintenant le nouveau fuseau horaire. Mais jenkins (et peut-être d'autres logiciels basés sur Java) utilisent le nom du lien symbolique qui est toujours "UTC". À la recherche d'une solution. . .
Gaoithe
1
Besoin de 2 choses, 1. lorsque le conteneur est créé, utilisez un script init pour définir les liens symboliques / etc / localtime et / etc / timezone et 2. pour jenkins, le fuseau horaire est extrait de deux options java. Ces options doivent être transmises au script démarre le processus Jenkins. Par exemple, "-Dorg.apache.commons.jelly.tags.fmt.timeZone = America / New_York -Duser.timezone = America / New_York". Toutes mes excuses, cela est spécifique à Jenkins mais, espérons-le, utile pour d'autres utilisateurs de Jenkins.
Gaoithe

Réponses:

210

Le secret ici est que dpkg-reconfigure tzdatacrée simplement /etc/localtimecomme une copie, lien dur ou lien symbolique (un lien symbolique est préférable) à un fichier dans /usr/share/zoneinfo. Il est donc possible de le faire entièrement à partir de votre fichier Docker. Considérer:

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

Et en prime, TZ sera également correctement défini dans le conteneur.

Ceci est également indépendant de la distribution, donc cela fonctionne avec à peu près tout Linux.

Remarque: si vous utilisez une image alpine, vous devez installer la tzdatapremière. (voir ce numéro ici )

Ressemble à ça:

RUN apk add --no-cache tzdata
ENV TZ America/Los_Angeles
Michael Hampton
la source
20
Liste des noms de TZ: fr.wikipedia.org/wiki/List_of_tz_database_time_zones
BillyTom
5
Avec Ubuntu: 16.04 (et peut-être une autre version), vous devez tzdatainstaller un paquet pour que cela fonctionne.
Opsse
6
Suis-je le seul à penser qu'il n'est pas très intelligent de coder en dur un fuseau horaire dans le fichier Dockerfile?
Wolfgang
1
@ Wolfgang Ceci est un exemple. Vous pouvez le fournir de toute autre manière que vous fournissez normalement des variables d'environnement, telles que la ligne de commande, docker-compose.yml, etc.
Michael Hampton
J'ai remarqué que, du moins pour les images alpines, il TZsuffisait de définir la variable. Je n'ai pas eu à configurer les liens symboliques ou quoi que ce soit d'autre.
code_dredd
59

Généralement, il suffit de définir une variable d'environnement dans le conteneur de menu fixe, comme suit:

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

Bien sûr, cela fonctionnerait aussi avec docker-compose.

Victor Klos
la source
2
Cela semble être le moyen le plus élégant. Veillez à ce qu'une image de base, par exemple ubuntu:16.04, ne contienne pas le tzdatapackage à ajouter dans Dockerfile.
Julien Fastré
1
+1 - Je suis d'accord avec Julien. cela semble être l'approche la plus élégante pour définir des fuseaux horaires lors de l'exécution. Cela fonctionne bien avec CentOS. L'image Alpine nécessite l'installation du package 'tzdata', ce qui est préférable aux configurations de codage lors de la construction, à moins que la charge utile de l'image supplémentaire de 3 Mo ne puisse être tolérée :)
Frelling
Cela semble bon mais semble ne pas fonctionner pour moi (avec CentOS 7.5.1804 et tzdata-2018e-3.el7.noarch)? visage triste
gaoithe
22

Monter /etc/localtimedans l'image, donc il est synchronisé avec host -vest le plus populaire.

Mais voir le numéro 12084 :

il n'est pas correct car il ne fonctionne pas lorsque le logiciel nécessite à la place que le fichier /etc/timezonesoit défini.
De cette façon, vous utilisez le laisse comme valeur par défaut etc/UTC.

J'ai déterminé qu'il n'existait en fait aucun moyen élégant et infaillible de définir le fuseau horaire à l'intérieur d'un conteneur de menu fixe.
Alors avons finalement opté pour cette solution:

App dockerfile:

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

Script de point d'entrée d'application:

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

/configFichier docker de volume de données , localisé dans un pays ou une région spécifique:

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

... il n’est pas élégant car il implique 3 fichiers distincts et est recréé /etc/localtimeà chaque démarrage du conteneur d’exécution. Ce qui est plutôt inutile.

Cependant, il fonctionne correctement et permet de séparer correctement l'image de l'application de base et chaque configuration localisée par pays.
En 3 lignes de code.

VonC
la source
1
Pour moi, c'était: RUN echo "Europe/London" > /etc/timezone
jpmottin
@ jpmottin Donc, un peu comme dans serverfault.com/a/856593/783 alors?
VonC
18

Vous pouvez ajouter vos fichiers locaux (/ etc / timezone et / etc / localtime) en tant que volume dans votre conteneur Docker.

Mettez à jour votre docker-compose.ymlavec les lignes suivantes.

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

Maintenant, l'heure du conteneur est la même que sur votre hôte

thhan
la source
Si votre hôte sur CentOS distrib, entrez la commande echo "Europe/Paris" > /etc/timezoneavant de redémarrer le conteneur.
CrazyMax
Est-ce que cela fonctionne sur l'hôte MacOS?
Redsandro
Ne fonctionne pas sous MAC
Marcello de Sales le
Cela fonctionnait sur MacOS mais je l’ai réessayé après un long moment et j’obtiens ce qui suit. Vous ne pouvez pas savoir si High Sierra ou un changement de menu fixe a causé: "docker: réponse d'erreur du démon: Montages refusés: le chemin / etc / localtime n'est pas partagé à partir d'OS X et n'est pas connu de Docker. Vous pouvez configurer les chemins d'accès partagés à partir de Docker - > Préférences ... -> Partage de fichiers. Voir docs.docker.com/docker-for-mac/osxfs/#namespaces pour plus d'informations. "
Gae123
1
Cela corrompra votre base de données zoneinfo car / etc / localtime est un lien symbolique (ainsi, / usr / share / zoneinfo / Some / Thing risque d'être monté en tant que / usr / share / zoneinfo / UTC dans le conteneur). Sans oublier que vous mélangez le fichier db de l'hôte avec celui du conteneur.
ionelmc
12

Dans ubuntu 16.04 image il y a un bug. La solution était

    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
la source
1
Sérieusement ... c'est la seule solution qui a fonctionné!
Gerrat
1
Je devais également le faire - il semble que tzdata ne soit plus dans certaines distributions par défaut.
Peter
4

si vous utilisez une image fixe en fonction de ubuntu:

# Change the docker default timezone from UTC to SGT
echo "Asia/Singapore" > /etc/timezone
dpkg-reconfigure tzdata
date
Xianlin
la source
3

Merci à VonC pour les informations et le lien vers le problème. Cela ressemble à un gâchis si compliqué, alors j'ai fait quelques essais sur ma propre idée de la façon de résoudre ce problème et cela semble bien fonctionner.

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

(suivez les instructions pour choisir mon fuseau horaire)

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

Ensuite, j'ai mis à jour mes fichiers Dockerfiles pour refléter ceci:

FROM chocko/ubuntu:local

Il doit y avoir quelque chose qui ne va pas avec cela car il semble trop facile d’être négligé ... Ou est-ce acceptable?

Chockomonkey
la source
C’est aussi ce que j’ai essayé, mais le fuseau horaire se réinitialise quand même après exitle conteneur. Ceci est sur Debian.
Mike Chamberlain
@ MikeChamberlain avez-vous déjà essayé la réponse acceptée par Michael Hampton ci-dessus? Je ne l'ai pas implémenté moi-même, mais j'estime que c'est la voie à suivre compte tenu des upvotes qu'il a reçues.
Chockomonkey
2

J'ajoute mes deux sous ici, car j'ai essayé plusieurs de ces solutions, mais aucune n'a fonctionné avec des images alpines.

Cependant, cela a fait l'affaire:

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/*

[ Source ]

Alpha
la source
1

Une manière plus générique de définir le fuseau horaire en docker runarguments:

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

Ou pour la réutilisation:

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

...
-e TZ=`GET_TZ`
Mugen
la source
ne vous aide pas si votre image de base est alpine (5 Mo) sans "tzdata" installée
max4ever