前言
当我们把应用部署到容器里面之后,基本都会要和时间/时区打交道!!
大部分的应用,多多少少都会有获取当前时间的操作,试想一下应用拿到的时间不对,那么业务极有可能会乱套,造成严重的损失。
时间和时区是浑然一体的,我们在东八区,看到的是8点钟,同一时间点,别人在另外的时区看到的可能是10点钟。
所以我们要对这个问题有个简单的认知,这样才能避免在实际使用的时候踩坑。
下面来简单看看 Docker 和时区的一些内容吧。
常用镜像
比较常用的基础镜像应该是 Alpine,Ubuntu,Debian 和 CentOS 这 4 个了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f976f93cd515e89f3011688a587ea00.png)
看看分别启动对应的容器,执行 date
命令,看看输出的时间。
![](https://i-blog.csdnimg.cn/blog_migrate/69a9e29e0b3a937b4b3a4976a43ac019.png)
从上面的图可以看出,这些镜像基本上都采用 UTC 时间,默认时区为零时区。
图片中,这些容器的时间都是 5 点多, 老黄本地的电脑则输出的是 13 点。
在国内的大多数应用,可能用的时间会是 13 点的比较多。
知道了这个背景,那么要怎么对容器的时区进行调整的。
时区调整
回想一下,.NET Core 的应用,在部署的时候,一般会在启动的时候指定环境变量 -e TZ=Asia/Shanghai
,或者是在Dockerfile里面直接加一个 ENV TZ=Asia/Shanghai
来指定当前用的时区。
下面先来尝试一下这种方式行不行。
![](https://i-blog.csdnimg.cn/blog_migrate/a86c16ea2eb2a7b57d28814a2cf76533.png)
可以看到, debian 和 centos 在指定这个环境变量后是可以正常获取到正确的时间的,但是 alpine 和 ubuntu 却不行。
影响这个时区的,其实是一个叫 tzdata 的东西,可以理解成是一个时区的数据库。
可以参考下面的资料:
https://en.wikipedia.org/wiki/Tz_database
之所以上面 debian 和 centos 可以通过指定环境变量来切换时区,是因为这两个镜像里面已经安装了 tzdata 。
可以查看一下 /usr/share/timezone
目录。
![](https://i-blog.csdnimg.cn/blog_migrate/ff8aa6355a5fb4a1c0baad663f44e587.png)
那么,alpine 和 ubuntu 这两个镜像我们要怎么操作才可以适配。
下面以比较常用的 alpine 为例,重新构建一个镜像。
加时区的可以参考下面这个 wiki 地址
https://wiki.alpinelinux.org/wiki/Setting_the_timezone
先写一个 Dockerfile
FROM alpine:3.13
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add tzdata
再来构建
docker build -t alpine:3.13-tz -f Dockerfile.alpine .
下面来看看通过运行时指定环境变量的方式来获取当前时间是否是正确的。
![](https://i-blog.csdnimg.cn/blog_migrate/e787503c0f17238736701919ca2d62e3.png)
从上面的图可以看到,时间是正确的了,同样也可以看到一堆时区信息了。
再来看看,加了 tzdata 后,镜像的大小如何。
![](https://i-blog.csdnimg.cn/blog_migrate/92bd39e90f00df0d4323dfd31d9485ef.png)
相比原始的多了 2M,还可以接受。
写在最后
时区这个问题,其实比较简单,只是要特别注意。
如果时间存储用的是时间戳,展示的时候,再根据参数转成对应的本地时间,也可以一定程度的避免踩到时区这个坑。