【POD】golang:unknown time zone Asia/Shanghai
在迁移部门微服务到K8S集群时,golang基础镜像选择的是busybox:glic;
在运行过程中,查询Clickhouse时,发现报错:unknown time zone Asia/Shanghai;
定位
在网络上看到一篇文章:www.csyangchen.com/go-alpine-t… ,得知为ClickHouse中引用到了time.LoadLocation函数,导致程序需要获取zoneinfo具体信息,具体引用位置如下:
func open(dsn string) (*clickhouse, error) {
......
if err := ch.hello(database, username, password); err != nil {
ch.conn.Close()
return nil, err
}
}
||
||
↓↓
func (ch *clickhouse) hello(database, username, password string) error {
.....
switch packet {
case protocol.ServerException:
return ch.exception()
case protocol.ServerHello:
if err := ch.ServerInfo.Read(ch.decoder); err != nil {
return err
}
case protocol.ServerEndOfStream:
ch.logf("[bootstrap] <- end of stream")
return nil
default:
return fmt.Errorf("[hello] unexpected packet [%d] from server", packet)
}
}
func (srv *ServerInfo) Read(decoder *binary.Decoder) (err error) {
.....
if srv.Timezone, err = time.LoadLocation(timezone); err != nil {
return fmt.Errorf("could not load time location: %v", err)
}
}
func LoadLocation(name string) (*Location, error) {
....
if z, err := loadLocation(name, zoneSources); err == nil {
return z, nil
} else if firstErr == nil {
firstErr = err
}
}
linux下:
var zoneSources = []string{
"/usr/share/zoneinfo/",
"/usr/share/lib/zoneinfo/",
"/usr/lib/locale/TZ/",
runtime.GOROOT() + "/lib/time/zoneinfo.zip",
}
解释:
- 在clickhouse连接并且使用open的时候,会调用一个hello函数;
- hello函数调用serverinfo.Read()函数;
- 然后当服务器版本大于服务器最小版本时,会调用loadLocation获取当前时区;
- LoadLocation函数需要zoneSources包,在linux中会从多个目录去寻找;
测试
因为在程序已经在pod中运行,在没有测试成功的情况下,进行容器的重新编译,会浪费时间;所以可以先将zoneinfo.zip通过主机挂载的方式,挂载到pod内部进行测试,yaml如下:
spec:
containers:
- name: demo
image: busybox:lastest
volumeMounts:
- name: host-time
mountPath: /opt/zoneinfo.zip
env:
- name: ZONEINFO
value: /opt/zoneinfo.zip
volumes:
- name: host-time
hostPath:
path: /opt/zoneinfo.zip
结果为成功,说明将该zoneinfo放到容器中,就可以成功执行程序;
结语
在k8s迁移过程中,可以灵活的方式进行排查;不要用最笨的方式去测试,比如:重新编译容器;会浪费大量的时间;