【POD】golang:unknown time zone Asia/Shanghai

2,565 阅读2分钟

【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迁移过程中,可以灵活的方式进行排查;不要用最笨的方式去测试,比如:重新编译容器;会浪费大量的时间;

引用文章

www.csyangchen.com/go-alpine-t…