前一阵子碰到Go写的一项目,使用viper和ETCD进行Toml文件的存储与写入。在当我安装新版本的ETCD和升级Go依赖包之后出现了不兼容的问题。旧版viper为1.10版本,使用github.com/coreos/go-etcd v2.0.0+incompatible
作为请求包。看了源码之后发现新的版本中废弃掉了很多内容,所以既然升级了ETCD,那不如将逻辑重写了。
目前使用的包版本
github.com/spf13/viper v1.15.0
go.etcd.io/etcd/client/v3 v3.5.9
代码如下:
go
package main
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"github.com/spf13/viper"
"io/ioutil"
"log"
"os"
"time"
_ "github.com/spf13/viper/remote"
clientv3 "go.etcd.io/etcd/client/v3"
)
type etcdClient struct {
cli *clientv3.Client
}
func initClient(endpoint string) *etcdClient {
log.SetFlags(log.LstdFlags | log.Lshortfile)
// 这里的证书只是释意,我没有配置证书下面跳过验证了
cert, err := tls.LoadX509KeyPair("healthcheck-client.crt", "healthcheck-client.key")
if err != nil {
log.Fatalf("Failed to load client cert and key: %v", err)
}
caCert, err := ioutil.ReadFile("ca.crt")
if err != nil {
log.Fatalf("Failed to read ca certificate: %v", err)
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{endpoint},
DialTimeout: 10 * time.Second,
TLS: &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
InsecureSkipVerify: false,
},
})
if err != nil {
log.Fatalf("Failed to connect to etcd: %v", err)
}
fmt.Println("init client...")
return &etcdClient{
cli: cli,
}
}
func (cli *etcdClient) Put(key string, fileName string) {
fmt.Println("write config to etcd...")
data, err := os.ReadFile(fileName)
if err != nil {
log.Fatalf("Failed to read config file: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
_, err = cli.cli.Put(ctx, key, string(data))
cancel()
if err != nil {
log.Fatalf("Failed to write config to etcd: %v", err)
}
}
func (cli *etcdClient) Get(key string) {
fmt.Println("get config from etcd...")
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
resp, err := cli.cli.Get(ctx, key)
cancel()
if err != nil {
log.Fatalf("Failed to get config from etcd: %v", err)
}
viper.SetConfigType("toml")
if len(resp.Kvs) > 0 {
err = viper.ReadConfig(bytes.NewBuffer(resp.Kvs[0].Value))
if err != nil {
log.Fatalf("Failed to read configuration: %v", err)
}
} else {
log.Fatalf("No config found in ETCD")
}
fmt.Println("读取的配置信息:", viper.Get("god_job.repo.k8s"))
}
func viperDemo(endpoint, key string) {
v := viper.New()
v.SetConfigType("toml")
err := v.AddRemoteProvider("etcd3", endpoint, key)
if err != nil {
log.Fatalf("Failed to add remote provider: %v", err)
}
err = v.ReadRemoteConfig()
fmt.Println("读取的配置信息:", v.Get("god_job.repo.k8s"))
}
func main() {
fileName := "conf.dev.toml"
keyString := "/dev/conf.dev.toml"
endpoint := "http://127.0.0.1:23791"
cli := initClient(endpoint)
cli.Put(keyString, fileName)
cli.Get(keyString)
cli.cli.Close()
viperDemo(endpoint, keyString)
}
注意点!
1. Viper包中是不支持配置证书的,旧版remote可以绕过HTTPS,(目前我没找到,有大佬可以在评论区告诉我),所以如果ETCD有证书的话建议先读出来然后使用Viper解析。
2. ETCD V2 版本的API存入的数据使用v3是读不出来的,也就是说v2存v2读,v3存v3读。