Docker Container время и часовой пояс (не будет отражать изменения)

Где контейнеры Docker получают информацию о времени? Я создал несколько контейнеров из базового Ubuntu: надежного образа, и когда я запускаю его и запрашиваю "дату", я получаю время UTC.

Некоторое время я обходил это, делая следующее в моем Dockerfile:

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

Однако почему-то перестал работать. Поиск в Интернете, я увидел ниже предложенный:

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

Оба эти метода правильно устанавливают часовой пояс!

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

Кто-нибудь знает, что дает?

12 ответов

Решение

Секрет в том, что dpkg-reconfigure tzdata просто создает /etc/localtime в качестве копии, жесткой ссылки или символической ссылки (символическая ссылка предпочтительнее) к файлу в /usr/share/zoneinfo, Так что это можно сделать полностью из вашего Dockerfile. Рассматривать:

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

И в качестве бонуса, TZ будет правильно установлен в контейнере.

Это также не зависит от распространения, поэтому работает практически с любым Linux.

Примечание: если вы используете альпийское изображение, вы должны установить tzdata первый. (см. эту проблему здесь)

Выглядит так:

RUN apk add --no-cache tzdata
ENV TZ America/Los_Angeles

Обычно достаточно установить переменную окружения в контейнере Docker, например, так:

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

Конечно, это будет работать и с docker-compose,

Вы можете добавить свои локальные файлы (/etc/timezone и /etc/localtime) в виде тома в ваш docker-контейнер.

Обновите свой docker-compose.yml со следующими строками.

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

Теперь время контейнера такое же, как на вашем хосте.

Монтаж /etc/localtime на изображении, поэтому он синхронизируется с host -v самый популярный

Но смотрите выпуск 12084:

это не правильно, потому что это не работает, когда программное обеспечение требует вместо файла /etc/timezone установить.
Таким образом, вы используете, оставляет его в качестве значения по умолчанию etc/UTC,

Я определил, что на самом деле не существует надежного элегантного способа установить часовой пояс внутри контейнера докера.
Итак, наконец-то остановились на этом решении:

Приложение dockerfile:

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

Скрипт точки входа в приложение:

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

Объем данных /config Dockerfile, локализованный для конкретной страны или региона:

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

... это не элегантно, потому что включает в себя 3 отдельных файла, и воссоздание /etc/localtime при каждом запуске контейнера во время выполнения. Что довольно расточительно.

Однако он работает правильно и успешно обеспечивает разделение между базовым образом приложения и локализованной конфигурацией каждой страны.
В 3 строки кода.

В образе Ubuntu 16.04 есть ошибка. Решение было

    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

Если вы используете образ докера на основе ubuntu:

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

Здесь я добавляю свои два цента, потому что я пробовал несколько из них, но ни один не работал на альпийских изображениях.

Тем не менее, это сделало свое дело:

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

[ Источник]

Использование контейнера Fedora (вероятно, будет работать и с Ubuntu):

Самым простым решением, которое я нашел, было использование следующего в docker-compose.yml:

      environment: 
  TZ: "${TZ:-America/Los_Angeles}"

Затем в вашем файле .env (который автоматически читает docker-compose)

      TZ=America/Los_Angeles

Это позволяет вам поставить docker-compose.yml под контроль версий и использовать настроенный файл .env, который может игнорироваться git.

Вы получаете значение по умолчанию для контейнера и получаете возможность настройки, лучшее из обоих миров.

Для Fedora никаких других изменений не потребовалось, она просто работает!

В базовом образе alpine (пример использования узла:10.16.0-alpine):

Dockerfile

FROM node:10.16.0-alpine

ENV TZ=America/Los_Angeles

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

WORKDIR /app

COPY package.json package-lock.json ./

RUN npm i --production

COPY . .

CMD node index.js

Спасибо VonC за информацию и ссылку на проблему. Это кажется таким запутанным беспорядком, поэтому я проверил свою идею о том, как решить эту проблему, и это, кажется, прекрасно работает.

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

(следуйте инструкциям, чтобы выбрать мой часовой пояс)

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

Затем я обновил свои файлы Docker, чтобы отразить это:

FROM chocko/ubuntu:local

Должно быть, с этим что-то не так, потому что кажется, что это слишком легко игнорировать... Или это приемлемо?

Более общий способ установить часовой пояс в docker run аргументы:

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

Или для повторного использования:

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

...
-e TZ=`GET_TZ`

Самый простой способ — добавить-eвариант илиENVдиректива для установкиTZпеременная среды, поскольку debian, ubuntu и т. д. уже включеныtzdata.

Кто-то рекомендует смонтировать часовой пояс с хоста:

      $ docker run -it --rm \
-v /etc/localtime:/etc/localtime \
-v /etc/timezone:/etc/timezone \
debian:bullseye date
Mon Jul  3 19:41:30 CST 2023

Это может сработать, но это опасно. Потому что/etc/localtimeна самом деле это ссылка на символ (в некоторых новых дистрибутивах), и Docker по умолчанию следует по ссылке на символ. В результате данные часового пояса (вместо самой ссылки на символ) переопределяются автоматически.

      $ docker run -it --rm debian:bullseye \
sh -c 'ls -l /etc/localtime && tail -n1 /etc/localtime'
lrwxrwxrwx 1 root root 27 Mar 20 00:00 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
UTC0
$ docker run -it --rm -v /etc/localtime:/etc/localtime debian:bullseye \
sh -c 'ls -l /etc/localtime && tail -n1 /etc/localtime'
lrwxrwxrwx 1 root root 27 Mar 20 08:00 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
CST-8

Вот почему это не работает:

      $ docker run -it --rm \
-v /usr/share/zoneinfo:/usr/share/zoneinfo \
-v /etc/localtime:/etc/localtime \
-v /etc/timezone:/etc/timezone \
debian:bullseye date
Mon Jul  3 11:41:59 UTC 2023
Другие вопросы по тегам