date显示的是CST标准时间,使用timedatectl查看localtime依旧为UTC时间。
时区为Asia/Shanghai,但是显示却为(UTC+0000)
查了很多网上的办法,都没解决。最后发现是/usr/share/zoneinfo/Asia/Shanghai里的内容被换成UTC的内容,最后找了虚拟机的正确文件替换了/usr/share/zoneinfo/Asia/Shanghai,
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 重新做软链
重启就发现UTC变成(+0800)啦
————————————————----------------------------------------------------------------------------
/etc/localtime是最重要的时间设置,运行容器时,如果想要修改docker镜像中默认的时区,只能通过-v /etc/localtime:/etc/localtime 挂载卷的方式(你不会想启动之后进到容器内部修改吧),/etc/timezone可以用相同的方式设置
TZ是系统内部变量,但此变量默认不存在,此时date命令会使用/etc/localtime中的设置。如果设置了TZ变量,则date命令会输出TZ变量设置的时区时间
1.1 /etc/localtime
/etc/localtime是用来描述 系统时间,如果系统时间不正确,通过修改该文件来修改时区
/etc/localtime文件通常是一个到/usr/share/zoneinfo/某时区文件的软链接,例如:`/etc/localtime -> /usr/share/zoneinfo/Etc/UTC`
/usr/share/zoneinfo/目录下是各种时区文件
可以通过软连接修改时区`ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime`,也可以通过`tzselect`修改时区。在容器中可以通过变量或挂载卷文件实现修改,具体要看Dockerfile文件的写法
1.2 /etc/timezone
/etc/timezone是用来描述本机所属时区的。有些程序是通过该文件获取时区的,比如:JAVA,也就是说/etc/timezone时区不正确,像java这样的程序,获取的时间可能不正确
修改时区:`echo 'Asia/Shanghai' >/etc/timezone`
2 我在gitlab中遇到的问题与解决方法
我在使用gitlab-ce:13.x.x版本的官方Docker镜像时(基于ubuntu 20.04),设置TZ变量后(TZ=“Asia/Shanghai”),在容器内部运行date,就会显示我设置的这个中国时区,但是gitlab备份计划生成的备份文件名却是UTC时间(gitlab.rb中的时区也已经设置为"Asia/Shanghai"了),此时我看到/etc/localtim是软链接到/usr/share/zoneinfo/Etc/UTC的,故,我把系统的/etc/localtime挂在到容器内部,再次执行备份计划就备份文件名的日期就变成正确的中国时间了
3 ubuntu官方镜像时区相关问题的测试
注:检验时,我用的是当前最新的ubuntu的官方镜像,是基于20.04的版本打造的。
3.0 官方原版测试
官方原版ubuntu镜像没有时区配置信息,也没有时区数据文件,你看:
结果:
date :UTC
/etc/timezone :不存在
/etc/localtime :不存在
/usr/share/zoneinfo :时区数据文件也是不存在的
过程:
[root@v-192-168-11-81-deploy:~]# docker run -it --name yyy ubuntu bash
root@2aa65bac6540:/#
root@2aa65bac6540:/# date
Fri Mar 10 14:48:00 UTC 2023
root@2aa65bac6540:/#
root@2aa65bac6540:/# cat /etc/timezone
cat: /etc/timezone: No such file or directory
root@2aa65bac6540:/#
root@2aa65bac6540:/# cat /etc/localtime
cat: /etc/localtime: No such file or directory
root@2aa65bac6540:/#
root@2aa65bac6540:/# ll /etc/localtime
ls: cannot access '/etc/localtime': No such file or directory
root@2aa65bac6540:/#
root@2aa65bac6540:/# ll /usr/share/zoneinfo
ls: cannot access '/usr/share/zoneinfo': No such file or directory
root@2aa65bac6540:/# exit
exit
[root@v-192-168-11-81-deploy:~]#
以上是因为没有安装软件包tzdata,故,我基于ubuntu官方镜像安装tzdata构建新的补丁版的镜像【new-ubuntu】,Dockerfile内容如下:
FROM ubuntu
MAINTAINER ZZXia
RUN apt-get update && apt-get install -y tzdata
我想gitlab-ce的官方镜像也是这么干的吧
构建他docker build -t new-ubuntu ./
运行它,你会发现上面不存在的文件都有了
另:安装完tzdata后,在交互模式下,你可以运行tzselect命令以设置时区,镜像构建时不行(不方便)。
3.1 不设置任何参数测试
结果:
date :UTC
/etc/timezone :UTC
/etc/localtime :UTC
/etc/localtime软链接 :UTC
过程:
[root@v-192-168-11-81-deploy:~]# docker run -it --name yyy new-ubuntu bash
root@3fde01074ae6:/#
root@3fde01074ae6:/# date
2023年 03月 10日 星期五 14:23:27 UTC
root@3fde01074ae6:/#
root@3fde01074ae6:/# cat /etc/timezone
Etc/UTC
root@3fde01074ae6:/#
root@3fde01074ae6:/# cat /etc/localtime
TZif2UTCTZif2UTC
UTC0
root@3fde01074ae6:/#
root@3fde01074ae6:/# ll /etc/localtime
lrwxrwxrwx 1 root root 27 Mar 9 15:10 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
root@3fde01074ae6:/# exit
exit
一切都在意料之中
3.2 只设置TZ="Asia/Shanghai"参数测试
结果:
date :CST
/etc/timezone :UTC
/etc/localtime :UTC
/etc/localtime软链接 :UTC
过程:
[root@v-192-168-11-81-deploy:~]# docker run -it --env TZ="Asia/Shanghai" --name yyy new-ubuntu bash
root@f85aa804a1fc:/#
root@f85aa804a1fc:/# date
2023年 03月 10日 星期五 22:24:11 CST
root@f85aa804a1fc:/#
root@f85aa804a1fc:/# cat /etc/timezone
Etc/UTC
root@f85aa804a1fc:/#
root@f85aa804a1fc:/# cat /etc/localtime
TZif2UTCTZif2UTC
UTC0
root@f85aa804a1fc:/#
root@f85aa804a1fc:/# ll /etc/localtime
lrwxrwxrwx 1 root root 27 Mar 9 15:10 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
root@f85aa804a1fc:/# exit
exit
/etc/timezone及/etc/localtime都是UTC,但date输出的却是CST时区,TZ这环境变量到底是怎么达成这个结果的。在我前面gitlab-ce镜像中备份任务中却使用的是UTC时间
3.3 只设置【-v /etc/localtime:/etc/localtime】参数测试,或设置【-v /etc/localtime:/etc/localtime 及 TZ="Asia/Shanghai"】参数测试(结果是一样的)
结果:
date :CST
cat /etc/timezone :UTC
cat /etc/localtime :CST
/etc/localtime软链接 :为UTC,实际生效的是`-v`挂载的这个,即CST
过程:
[root@v-192-168-11-81-deploy:~]# docker run -it -v /etc/localtime:/etc/localtime --name yyy new-ubuntu bash
root@b8d2b195f6bf:/#
root@b8d2b195f6bf:/# date
2023年 03月 10日 星期五 22:25:12 CST
root@b8d2b195f6bf:/#
root@b8d2b195f6bf:/# cat /etc/timezone
Etc/UTC
root@b8d2b195f6bf:/#
root@b8d2b195f6bf:/# cat /etc/localtime
TZif�����y��Y^�� �p�ӽ����|@�;>�Ӌ{��B���E"�L���<��fp���A|��R i�� ~��!I}�"g� #)_�$G� %|&'e &�^(G (�@~�p�CDTCSTTZif2
����~6C)�������������y������Y^������ �p�����ӽ������������|@�����;>�����Ӌ{������B�������E"�����L�������<������fp�����������A|��R i�� ~��!I}�"g� #)_�$G� %|&'e &�^(G (�@q�~�pLMTCDTCST
CST-8
root@b8d2b195f6bf:/#
root@b8d2b195f6bf:/# ll /etc/localtime
lrwxrwxrwx 1 root root 27 Mar 9 15:10 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
root@b8d2b195f6bf:/# exit
exit
一切都在意料之中,正与我在前面【我在gitlab中遇到的问题与解决方法】一节中讲到的一样,在date与计划任务中都能达成想要的结果
3.4 冲突测试:设置【TZ="Asia/Phnom_Penh"】(东7区),设置【-v /etc/localtime:/etc/localtime】(东8区)
结果:
date :+07
cat /etc/timezone :UTC
cat /etc/localtime :CST(+08)
/etc/localtime软链接 :UTC
过程:
[root@v-192-168-11-81-deploy:~]# docker run -it --env TZ="Asia/Phnom_Penh" -v /etc/localtime:/etc/localtime --name yyyx my-oracle-java-8 bash
root@29561a94da99:/#
root@29561a94da99:/# date
2023年 03月 11日 星期六 13:20:16 +07
root@29561a94da99:/#
root@29561a94da99:/# cat /etc/timezone
Etc/UTC
root@29561a94da99:/#
root@29561a94da99:/# cat /etc/localtime
TZif�����y��Y^�� �p�ӽ����|@�;>�Ӌ{��B���E"�L���<��fp���A|��R i�� ~��!I}�"g� #)_�$G� %|&'e &�^(G (�@~�p�CDTCSTTZif2
����~6C)�������������y������Y^������ �p�����ӽ������������|@�����;>�����Ӌ{������B�������E"�����L�������<������fp�����������A|��R i�� ~��!I}�"g� #)_�$G� %|&'e &�^(G (�@q�~�pLMTCDTCST
CST-8
root@29561a94da99:/#
root@29561a94da99:/# ll /etc/localtime
lrwxrwxrwx 1 root root 27 3月 9 14:10 /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
root@29561a94da99:/#
root@29561a94da99:/# exit
看到没,两个相互冲突的设置,最终date命令取得是TZ变量的设置,下节我们来测试下这个变量
3.5 测试变量【TZ】
测试环境为我的笔记本电脑(避开容器环境),结果如下:
kevin@TM1701-b38cbc23:~$ cat /etc/timezone #--- /etc/timezone 东8区
Asia/Shanghai
kevin@TM1701-b38cbc23:~$
kevin@TM1701-b38cbc23:~$ cat /etc/localtime #--- /etc/localtime 东8区
TZif2
������y��Y^�� �p�ӽ����|@�;>�Ӌ{��B���E"�L���<��fp���A|��R i�� ~��!I}�"g� #)_�$G� %|&'e &�^(G (�@q�~�pLMTCDTCSTTZif2
����~6C)�������������y������Y^������ �p�����ӽ������������|@�����;>�����Ӌ{������B�������E"�����L�������<������fp�����������A|��R i�� ~��!I}�"g� #)_�$G� %|&'e &�^(G (�@q�~�pLMTCDTCST
CST-8
kevin@TM1701-b38cbc23:~$
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$ export | grep TZ #--- 可以看出,原始安装不存在TZ变量,时间显示为东8区
kevin@TM1701-b38cbc23:~$ echo $TZ
kevin@TM1701-b38cbc23:~$ date
2023年 03月 28日 星期二 09:06:22 CST
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$ export TZ="Asia/Phnom_Penh" #--- TZ设置为东7区,时间显示为东7区
kevin@TM1701-b38cbc23:~$ date
2023年 03月 28日 星期二 08:09:01 +07
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$ export TZ= #--- 置空TZ变量,时间显示为UTC时间
kevin@TM1701-b38cbc23:~$ date
2023年 03月 28日 星期二 01:09:25 UTC
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$.
kevin@TM1701-b38cbc23:~$ unset TZ #--- 删除TZ变量,时间显示为东8区
kevin@TM1701-b38cbc23:~$ date
2023年 03月 28日 星期二 09:09:36 CST
4 一般用法
制作镜像:
FROM ubuntu:bionic
ARG TZF="Asia/Shanghai"
ENV TZ=${TZF}
RUN apt update
&& apt install -y tzdata
&& ln -sf /usr/share/zoneinfo/${TZF} /etc/localtime
&& echo ${TZF} > /etc/timezone
在运行了ln -sf /usr/share/zoneinfo/${TZF} /etc/localtime之后,可以运行dpkg-reconfigure -f noninteractive tzdata自动创建修改/etc/timezone
构建:
dockerbuild --build-argTZF="Asia/Phnom_Penh"-t new-ubuntu ./
运行:
docker run -it --env TZ="Asia/Phnom_Penh" new-ubuntu bash #--- date命令生效
docker run -it -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone new-ubuntu bash #--- 全部生效,此时变量TZ必须是unset的
docker run -it --env TZ="Asia/Phnom_Penh" -v /etc/localtime:/etc/localtime -v /etc/timezone:/etc/timezone new-ubuntu bash #--- 也是全部生效
TZF与``TZ只是为了演示他们生效的范围,一般用相同的就好,比如TZ`;
ARG参数只在构建时有效,可以在构建时从外部传入;
ENV参数在构建与运行时都有效,但只能在运行时传入;
TZ是内部变量,可以不存在,如果设置了,则date命令会使用他的设置;
5 最后
猜测:交互程序一般会使用date的结果,但计划任务之类的程序可能会使用/etc/localtime的设置(/etc/localtime可能属于系统级的)