etcd编译时,报undefined: strings.Builder
错误,如何解决?
etcd镜像版本过低,如何拿到高版本的etcd镜像?
etcd为什么本机能连,容器连不上?
etcd如何进行服务注册,服务发现?
etcd 是一个非常好用的中间件服务,职能很多,这里只介绍服务发现,其它的不多说了~
etcd作服务发现时,整个工程可以分为四个角色:
客户端、app主服务节点、app子服务节点,etcd中间件,
它们是怎么运作服务发现的呢?
{
"/login-srv/node/1": "172.21.41.11:8080",
"/login-srv/node/2": "172.21.41.12:8080",
"/login-srv/node/3": "172.21.41.13:8080",
"/login-srv/node/4": "172.21.41.14:8080",
}
"/login-srv"
索引(匹配到了上述所有),拿到所有子服务的对应端口和ip列表,并通过一定hash来抉择使用哪个结点。通过docker search etcd,最多人start的是v2,版本很久。所以我们需要从官网从新拉取最新版的编译并打包进容器里。
官网: https://github.com/etcd-io/etcd
通过git clone
/ go get
/ download zip
/ 下载至%GOPATH%/src/go.etcd.io/etcd
cd %GOPATH%/src/go.etcd.io/etcd
跳至下好的etcd文件夹GOOS=linux GOARCH=amd64 go build -o etcd
交叉编译成镜像环境的可执行etcd程序,产出一个etcd文件cd %GOPATH%/src/go.etcd.io/etcd/etcdctl
跳至etcdctl文件夹GOOS=linux GOARCH=amd64 go build -o etcdctl
交叉编译成镜像环境的可执行etcdctl程序,产出一个etcdctl文件%GOPATH%/src/go.etcd.io/etcd
下的Dockerfile-release
和前两步准备好的etcd,etcdctl,复制并放在一个新文件夹里docker build -f Dockerfile-release .
docker image ls
后,可以看到一个刚打包好的双none镜像,docker tag <双none的镜像id> etcd:latest
docker run -itd -p 2379:2379 -p 2380:2380 --rm -e ETCD_ADVERTISE_CLIENT_URLS=http://0.0.0.0:2379 -e ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379 etcd:latest
运行该容器main.go
package main
import (
"github.com/coreos/etcd/clientv3"
"fmt"
"time"
"context"
)
func main() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:2379", "localhost:22379", "localhost:32379"},
// Endpoints: []string{"localhost:4001"},
DialTimeout: 5 * time.Second,
})
if err != nil {
fmt.Println("connect failed, err:", err)
return
}
fmt.Println("connect succ")
defer cli.Close()
//设置1秒超时,访问etcd有超时控制
t1:=time.Now()
ctx, _ := context.WithCancel(context.TODO())
//操作etcd
_, err = cli.Put(ctx, "key", "v")
//操作完毕,取消etcd
// cancel()
t2 :=time.Now()
fmt.Println("put耗时",t2.Sub(t1))
if err != nil {
fmt.Println("put failed, err:", err)
return
}
//取值,设置超时为1秒
ctx, _ = context.WithTimeout(context.Background(), 10*time.Second)
t1= time.Now()
resp, err := cli.Get(ctx, "key")
fmt.Println("get 耗时:",time.Now().Sub(t1))
// cancel()
if err != nil {
fmt.Println("get failed, err:", err)
return
}
for _, ev := range resp.Kvs {
fmt.Printf("%s : %s\n", ev.Key, ev.Value)
}
//测试redis
}
输出:
connect succ
put耗时 9.0007ms
get 耗时: 3.998ms
key : v
使用了 https://www.jianshu.com/p/7c0d23c818a5 这里的工具,作了一点路径和包的修改。
程序比较简单,封装后,只有app子服务方添加自己的ip和端口进etcd,和客户端从etcd获取满足的ip和端口。
package main
import (
"fmt"
core "github.com/mistaker/etcdTool"
"time"
)
// 测试前,确保etcd run in 2379
func main() {
// 模拟服务方将服务注册进etcd
ser, e := core.NewServiceReg([]string{"localhost:2379"}, 5)
if e!=nil {
panic(e)
}
if e := ser.PutService("/user-login/node/111/", "10.0.1.1:8081"); e != nil {
panic(e)
}
if e := ser.PutService("/user-login/node/112/", "10.0.1.1:8082"); e != nil {
panic(e)
}
time.Sleep(7 * time.Second)
// 模仿客户端从etcd获取服务路径
cli, e := core.NewClientDis([]string{"localhost:2379"})
if e!=nil {
panic(e)
}
rs, e := cli.GetService("/user-login/")
fmt.Println(rs, e)
select {}
}
输出
续租成功
[10.0.1.1:8081 10.0.1.1:8082] <nil>
2019-07-03 18:23:46.995901 I | set data key : /user-login/node/111/ val: 10.0.1.1:8081
2019-07-03 18:23:46.995901 I | set data key : /user-login/node/112/ val: 10.0.1.1:8082
关键点是容器的环境变量,需要设定
ETCD_ADVERTISE_CLIENT_URLS=http://0.0.0.0:2379
ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
默认发起的主服务是监听127.0.0.1,这个ip在容器里,只会听内环,听不到宿主机的一些网段,改为0.0.0.0则通听!
本地编译时,需要使用go版本1.12↑,这个错误,在我用1.9时出现了,查了一下百度,是1.9之后添加的东西~~