解决.net core3.1部署到Linux CentOS docker时区问题
解决.net core3.1部署到Linux CentOS docker时区问题
最近遇到一个“.net core3.1部署到Linux CentOS docker时区“问题,总是不对,始终晚8个小时,程序取到的是UTC时间而不是我想要的东8北京时间。
一、主要技术及框架
1、.Net Core3.1
2、Docker(镜像:mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine)
3、Linux CentOS
4、ElasticSearch,Kibana
5、NLog
二、问题现象
看日志记录的时间戳,始终晚了8个小时,导致通过NLog根据日期没提案生成一个日志索引就有问题,比如6月1号8点之前的日志数据就会落在了5月31号的索引中。如下图:
这个问题虽然通过Kibana选择时间筛选最终可以选择到对应的日志(会自动做一个时区转换),但是始终存在一个问题(8小时的差异),有些日志要到前一天的索引中去查询。这就给我们统计查询带来了不便。
那么我们要怎么修正这个问题呢?
三、分析原因
首先先,我们来看看ES记录的原始信息:
@timestamp记录的是es的date类型,被自动转换成了带时区的字符串:2020-05-31T16:00:00.1209997+00:00
后面加就是相对UTC的时区,加00就表示是UTC时间。
最开始我通过构建docker镜像的时候使用下面命令:
docker cp /usr/share/zoneinfo/Asia/Shanghai lanhusoft-docker:/etc/localtime
其中lanhusoft-docker为容器名。
刚开始以为解决了,最后才知道是暂时解决了,把容器的时间改为了CST,通过date命令查看时间是北京时间了。
但是,过了一段时间重新使用jenkin重新构建,又发现不对了。但是在另外一个程序相同代码,相同构建时间又是正常啊的。(不知道为啥?不知道是不是.net core bug?)
进入容器使用date查看时间又是北京时间,而且宿主机器也是北京时间。奇怪的是.NET Core程序取到的当前时间却是UTC时间。
通过TimeZoneInfo.Local.DisplayName查看找到了原因,返回的是UTC时区时间,而且直接打印DateTime.Now到页面也是跟北京时间晚了8个小时。
看来通过上面的的方法不是完美和根本解决办法,因为alpine镜像先默认是UTC时间。
推荐:
需要指定北京时间,需要安装包tzdata。
四、解决方案
alpine安装包命令是apk add,如果每次构建镜像的时候现安装包tzdata,因为网络原因会很慢,导致影响Jenkin构建的速度。所以我自己写了一个镜像。
aspnet-3.1-alpine-lanhu.dockerfile:
- FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine
- MAINTAINER www.lanhusoft.com <2351310751@qq.com>
- #设置alpine时区
- ENV TIMEZONE Asia/Shanghai
- # Install base packages
- RUN apk update && apk add curl bash tree tzdata \
- && cp -r -f /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
- && echo "${TIMEZONE}" > /etc/timezone \
- && echo -ne "Alpine Linux 3.4 image. (`uname -rsv`)\n" >> /root/.built
- # Define bash as default command
- CMD ["/bin/bash"]
在docker文件aspnet-3.1-alpine-lanhu.dockerfile所在目录运行下面命令构建docker镜像:
docker build -f aspnet-3.1-alpine-lanhu.dockerfile -t aspnet-3.1-alpine-lanhu:latest .
说明:-f镜像脚本文件,-t镜像名称,冒号后面是tag。
最后,在项目的Dockerfile中引用这个新生成的镜像:
- FROM aspnet-3.1-alpine-lanhu AS base
- ARG app_env=development
- WORKDIR /app
- EXPOSE 80
- COPY . ./
- ENV ASPNETCORE_ENVIRONMENT $app_env
- ENTRYPOINT ["dotnet", "XX.Web.dll"]
这样每次构建就会很快,基本上10多秒就搞定。