Go操作etcd集群

2022-05-21

docker搭建etcd集群

yml

version: "3.0"
networks:
  etcd-net:
    driver: bridge

volumes:
  etcd1_data:
    driver: local
  etcd2_data:
    driver: local
  etcd3_data:
    driver: local

services:
  etcd1:
    image: bitnami/etcd:latest
    container_name: etcd1
    restart: always
    networks:
      - etcd-net
    ports:
      - "30000:2379"
      - "30001:2380"
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes                        # 运训不用密码登陆
      - ETCD_NAME=etcd1                                      # 名字
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:2380   # 列出这个成员的伙伴 URL 以便通告给集群的其他成员
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380            # 用于监听伙伴通讯的URL列表
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379         # 用于监听客户端通讯的URL列表
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379        # 列出这个成员的客户端URL,通告给集群中的其他成员
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster             # 在启动期间用于 etcd 集群的初始化集群记号
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380 # 为启动初始化集群配置
      - ETCD_INITIAL_CLUSTER_STATE=new                      # 初始化集群状态
    volumes:
      - "./data/etcd1_data:/bitnami/etcd"                           # 挂在的数据卷

  etcd2:
    image: bitnami/etcd:latest
    container_name: etcd2
    restart: always
    networks:
      - etcd-net
    ports:
      - "30002:2379"
      - "30003:2380"
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_NAME=etcd2
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd2:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - "./data/etcd2_data:/bitnami/etcd"

  etcd3:
    image: bitnami/etcd:latest
    container_name: etcd3
    restart: always
    networks:
      - etcd-net
    ports:
      - "30004:2379"
      - "30005:2380"
    environment:
      - ALLOW_NONE_AUTHENTICATION=yes
      - ETCD_NAME=etcd3
      - ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd3:2380
      - ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
      - ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
      - ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
      - ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
      - ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
      - ETCD_INITIAL_CLUSTER_STATE=new
    volumes:
      - "./data/etcd3_data:/bitnami/etcd"

docker-compose up -d

测试

etcd1 写入

docker exec -it etcd1 bash

I have no name!@77912e04a985:/opt/bitnami/etcd$ etcdctl put name "test"
OK

etcd2 读取

docker exec -it etcd2 bash
I have no name!@5972f7c68c5e:/opt/bitnami/etcd$ etcdctl get name
name
test

安装

etcd/client/v3

go get go.etcd.io/etcd/client/v3
func main() {
	cli, err := clientv3.New(clientv3.Config{
		Endpoints:   []string{"http://127.0.0.1:30000", "http://127.0.0.1:30002", "http://127.0.0.1:30004"},
		DialTimeout: 5 * time.Second,
	})

	if err != nil {
		fmt.Printf("connect to etcd failed, err: %v\n", err)
		return
	}

	defer cli.Close()
	fmt.Println("connect to etcd success...")

	go listen(cli)

	put(cli)
	get(cli)
	update(cli)
	del(cli)
}

func put(cli *clientv3.Client) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	_, err := cli.Put(ctx, "name", "test")
	cancel()
	if err != nil {
		fmt.Printf("put to etcd failed, err:%v\n", err)
		return
	}
}

func get(cli *clientv3.Client) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	res, err := cli.Get(ctx, "name")
	cancel()
	if err != nil {
		fmt.Printf("get to etcd failed, err:%v\n", err)
		return
	}
	for _, v := range res.Kvs {
		fmt.Printf("type: %s key: %s value: %s\n", "GET", v.Key, v.Value)
	}
}

func update(cli *clientv3.Client) {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	_, err := cli.Put(ctx, "name", "test2")
	cancel()
	if err != nil {
		fmt.Printf("put to etcd failed, err:%v\n", err)
		return
	}
}

func del(cli *clientv3.Client) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
	_, err := cli.Delete(ctx, "name")
	cancel()
	if err != nil {
		fmt.Printf("delete from etcd failed, err:%v\n", err)
		return
	}
}

func listen(cli *clientv3.Client) {
	wat := cli.Watch(context.Background(), "name")
	for w := range wat {
		for _, v := range w.Events {
			fmt.Printf("type: %s key: %s value: %s", v.Type, v.Kv.Key, v.Kv.Value)
		}
	}
	fmt.Println("out")
}