使用docker-compose设置容器的时区

65

我有一个docker-compose文件,运行了几个Dockerfile来创建我的容器。我不想编辑我的Dockerfile来设置时区,因为我的团队成员随时可能更改它们,并且我有一个docker-compose.override.yml文件来进行本地环境更改。然而,我的一个容器(基于Selenium的容器)似乎不能拉取主机的时区,这给我带来了问题。基于此,我想在所有容器中强制执行时区。目前我的Dockerfiles中是这样写的:

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

一切都正常运行。如何在docker-compose语法中复制相同的命令?


5
这是一个Docker Compose配置文件的示例,其中包括了设置容器时区的方法。它定义了一个名为"web"的服务,使用了一个基础镜像,并将主机上的一个目录挂载到了容器内的"/usr/share/nginx/html"目录。该服务还通过环境变量"TZ"来设置容器的时区为"Europe/Amsterdam"。 - Nehal J Wani
6个回答

72

这是简单的解决方案:

environment:
  - TZ=America/Denver

2
我在想是否需要像"TZ=America/Denver"这样的引号。 - perennial_noob
2
No. Quotes no need. - MxWild
2
我正在使用Node Alpine构建。缺少tzdata包。我需要在Dockerfile中添加“RUN apk add tzdata”才能使其正常工作。 - Jason Ching
1
它能工作,但不是对于每张图片。 - Мария Викторовна

55
version "2"

services:
  serviceA:
    ...
    environment:
      TZ: "America/Denver"
    command: >
      sh -c "ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && 
      echo $TZ > /etc/timezone &&
      exec my-main-application"

编辑:虽然问题并没有要求,但我刚刚添加了exec my-main-application以展示如何指定主进程。 exec在这里非常重要,以确保my-main-application接收到Ctrl-C(SIGINT / SIGKILL)。


1
请记住,docker-compose的"command"将覆盖默认命令(如果有)。参考:https://docs.docker.com/compose/compose-file/#/command - Claudio d'Angelis
1
@Claudiod'Angelis 没错,这也是这里所期望的行为。经过快速代码审核,我意识到我需要指定容器的主进程如何启动。现在正在添加它。 - Bernard
“my-main-application”应该填什么?它的命名从哪里来?服务名称?DLL文件的名称? - lenny
@lennyy 这是你容器内主可执行文件的名称。如果找不到,添加路径。 - Bernard
@Alkaline,我的dockerfile是由VS为docker项目生成的,其中包含ENTRYPOINT ["dotnet", "vote-server.dll"]。那么我的docker-compose命令是否应该是command: > sh -c "ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && exec dotnet vote-server.dll"?此外,每当我在docker-compose中使用命令时,它都无法启动,并显示找不到服务器容器的消息...我想这是因为命令没有启动实际程序,容器崩溃了,当它尝试与其一起工作时,它已经不存在了。 - lenny
如果您定义了ENTRYPOINT,则command将作为参数传递给ENTRYPOINT可执行文件。这不是您想要的。为了使它更简单,只需重新定义entrypoint: []并像上面所写的那样仅使用command:。有关说明,请参见https://medium.freecodecamp.org/docker-entrypoint-cmd-dockerfile-best-practices-abc591c30e21。 - Bernard

31

最简单的解决方案是在docker-compose.yml中分享卷,如下所示

ipchanger:
  image: codertarasvaskiv/ipchanger:raspberry
  volumes:
    - "/etc/localtime:/etc/localtime:ro"
  • ro - 表示容器只能从主机的 /etc/localtime 中读取,不能修改。

虽然我看到过评论说这并不总是有效,但它对我的容器起作用了。 - Hayden Thring
1
不幸的是,这在基于musl-libc的docker镜像上无法工作,比如一些Alpine镜像。我刚试过在homeassistant上。他们有意只支持TZ方法。 - FredG
它可以工作,但并非适用于每个图像。 - Мария Викторовна

15
version: '3.6'
services:
  mysql:
    image: mysql:5.6
    restart: always
    container_name: dev-mysql
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    restart: always
    environment:
     - TZ=Asia/Shanghai
     - MYSQL_ROOT_PASSWORD=password # set the root password
    ports:
      - '3306:3306'
    volumes:
      - "/etc/localtime:/etc/localtime:ro"
      - "/etc/timezone:/etc/timezone:ro"

这是我的MySQL的docker-compose.yaml文件。

提醒:如果您更改了yaml文件,则需要重新创建容器,而不是重新启动。

docker-compose -f docker-compose.yaml stop
docker-compose -f docker-compose.yaml rm
docker-compose -f docker-compose.yaml start

1

我在使用 Linux 容器的 Docker 引擎上遇到了同样的问题。

通过为安装 tzdata 包和设置时区的脚本添加到 DockerFile 的最终阶段,解决了这个问题。所有目标服务使用日期进程。时区在所有镜像之间共享,如下所示:

.env 文件

COMMON_TIME_ZONE=Europe/Paris

docker-compose.yml

services:
  matfront:
    build: 
      context: ./my-app
      args:
         - TIME_ZONE=$COMMON_TIME_ZONE

Dockerfile

FROM tomcat:9.0
ARG TIME_ZONE
RUN rm -rf /usr/local/tomcat/webapps/*
COPY --from=maven /tmp/ApiDemo/target/ApiDemo.war /usr/local/tomcat/webapps

### Here is the script block that defines the desired timezone ###
# Get the package tzdata that is not installed by default, then set the defined TZ
RUN apt-get install tzdata
RUN ln -snf /usr/share/zoneinfo/${TIME_ZONE} /etc/localtime && echo ${TIME_ZONE} > /etc/timezone

EXPOSE 8080
CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]

-2
 version: '2'
 services:
   ServiceA:
     image: image:
   - '/etc/localtime:/etc/localtime:ro'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接