前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >容器化Go应用--基础镜像的未知时区问题

容器化Go应用--基础镜像的未知时区问题

作者头像
KevinYan
发布2020-07-22 15:46:29
2.5K0
发布2020-07-22 15:46:29
举报
文章被收录于专栏:网管叨bi叨网管叨bi叨

Go开发的应用程序的一个优势在于,可以从"零"开始构建应用的Docker镜像,镜像中仅需要包含Go应用程序编译后的二进制文件,不需要额外安装其他执行环境。这样一来Go应用镜像占用的空间确实很小(通常是几MB),而且也会更安全些。常用的alpine镜像(alpine是专门为容器设计的小型Linux发行版)中存在一个安全漏洞,该漏洞为大量生产容器留下了空的root用户密码,所以如果你的的Go应用程序在没有alpine(或任何其他操作系统)的容器中运行,黑客就不能利用操作系统的漏洞去攻击容器里的应用。

使用Docker的多阶段构建,从头开始构建映像非常简单,上一期的文章《线上Go项目的Docker镜像应该怎么构建?》已经介绍了怎么从"scratch"基础镜像,使用多阶段构建制作Go应用程序的镜像。今天接着上期的话题继续说一个从零构建的应用镜像的容器时区设置的问题。

如果你的应用程序在初始化函数init里有设置时区的操作,那么在启动应用容器时会遇到下面这个运行时panic

代码语言:javascript
复制
unknown time zone Asia/Shanghai

如果你在应用程序里不显示地设置时区,应用容器确实是能正常启动的,只不过这样time包里的函数统一用的是UTC时区,等你发现问题时再在程序里去显示设置时区仍然会遇到上面的运行时错误。

下面我们来做个试验,看看上面说的问题的现象。

首先写一个简单的Go应用程序

代码语言:javascript
复制
package main

import (
   "fmt"
   "time"
)

func main() {
   // 输出当前的时区
   fmt.Print("Local time zone ")
   fmt.Println(time.Now().Zone())
   fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
}

然后写一个用来构建应用镜像的Dockerfile,使用的就是之前介绍的多阶段构建。

代码语言:javascript
复制
FROM golang:alpine as build
RUN apk --no-cache add tzdata
WORKDIR /app
ADD . /app
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp

FROM scratch as final

COPY --from=build /app/myapp .
ENV TZ=Asia/Shanghai

CMD ["/myapp"]

Dockerfile里,我们用ENV指令设置了TZ这个环境变量。Go运行时会查找TZ这个环境变量来设置自己的时区,上面我们把TZ设置成了Asia/Shanghai,接下来我们看看在容器里应用是不是能如期运行,输出正确的时区和时间。

代码语言:javascript
复制
➜  docker build -t go_timezone .


➜  docker run --rm go_timezone
Local time zone UTC 0
2020-07-17 04:47:37

根据运行结果发现时区的设置并没生效。

Linux系统下Go运行时会从多个来源读取时区信息,在$GOROOT/src/time/zoneinfo.unix文件里能够找到Go运行时是从哪些地方读取时区信息的。

代码语言:javascript
复制
// Many systems use /usr/share/zoneinfo, Solaris 2 has
// /usr/share/lib/zoneinfo, IRIX 6 has /usr/lib/locale/TZ.
var zoneSources = []string{
   "/usr/share/zoneinfo/",
   "/usr/share/lib/zoneinfo/",
   "/usr/lib/locale/TZ/",
   runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}

于是我就进到刚才镜像的容器里看了看,上面列的几个目录都没有找到。到这里算是定位到问题了,scratch镜像里并不包含这些时区文件。那么解决办法就是从build阶段的镜像里拷贝时区文件到最终的应用镜像。

代码语言:javascript
复制
FROM golang:alpine as build
RUN apk --no-cache add tzdata
WORKDIR /app
ADD . /app
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp

FROM scratch as final

COPY --from=build /app/myapp .
### 下面这行是新加的
COPY --from=build /usr/share/zoneinfo /usr/share/zoneinfo
ENV TZ=Asia/Shanghai

CMD ["/myapp"]

重新构建镜像、运行容器后就能发现时区设置已经正常了,Go运行时按照环境变量TZ里指定的时区打印了当前时间。

代码语言:javascript
复制
➜  docker image rm go_timezone
➜  docker run --rm go_timezone
Local time zone CST 28800
2020-07-17 13:12:18.206 CST
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 网管叨bi叨 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档