Saki's 研究记录

docker-compose部署ETCD

字数统计: 1.8k阅读时长: 8 min
2021/11/18

简介

ETCDCoreOS团队发起的一个开源项目,实现了分布式键值存储和服务发现,etcdZooKeeper/Consul非常相似,都提供了类似的功能,以及REST API的访问操作,具有以下特点:

简单:安装和使用简单,提供了 REST API 进行操作交互
安全:支持 HTTPS SSL 证书
快速:支持并发 10 k/s 的读写操作
可靠:采用 raft 算法,实现分布式系统数据的可用性和一致性

零. 服务部署

环境信息:

机型: 1核 1GB 1Mbps 腾讯云服务器
系统: CentOS Linux release 8.4.2105 (Core)

搭建一个不通过SSL认证的单机ETCD,安装部署步骤如下:

  1. 随便创建一个文件夹,并进入。
    1
    mkdir etcd & cd etcd
  2. 创建一个 docekr-compose.yml 文件件, 并将下面配置全部拷贝进去。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    version: "3"
    services:
    etcd1:
    # etcd uses gcr.io/etcd-development/etcd as a primary container registry, and quay.io/coreos/etcd as secondary.
    image: quay.io/coreos/etcd:v3.5.1 # 镜像
    container_name: etcd1 # 容器名 --name
    restart: always # 总是重启
    networks:
    - etcd-net # 使用的网络 --network
    ports: # 端口映射 -p
    - "20000:2379"
    - "20001:2380"
    environment: # 环境变量 --env
    - ALLOW_NONE_AUTHENTICATION=yes # 允许不用密码登录
    - ETCD_NAME=etcd1 # etcd 的名字
    - 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 # 为启动初始化集群配置
    - ETCD_INITIAL_CLUSTER_STATE=new # 初始化集群状态
    - ETCDCTL_API=3 # 升级api版本,使用最新的v3 API
    volumes:
    - $PWD/etcd1_data:/etcd-data # 挂载的数据卷
    - /etc/localtime:/etc/localtime

    etcd2:
    image: quay.io/coreos/etcd:v3.5.1
    container_name: etcd2
    restart: always
    networks:
    - etcd-net
    ports:
    - "20002:2379"
    - "20003: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
    - ETCD_INITIAL_CLUSTER_STATE=new
    - ETCDCTL_API=3
    volumes:
    - $PWD/etcd2_data:/etcd-data
    - /etc/localtime:/etc/localtime

    networks:
    etcd-net: # 网络
    driver: bridge # 桥接模式

壹. 测试验证

  1. docker-compose的基础操作
    ETCD文件夹运行以下命令,拉起服务:

    1
    docker-compose up

    或者后台启动:

    1
    docker-compose up -d

    停止服务:

    1
    docker-compose down
  2. ETCD 的基础操作
    通过etcdctl version 命令查看ETCD的版本:

    1
    2
    3
    docker exec -it etcd1 etcdctl version
    etcdctl version: 3.5.1
    API version: 3.5

    查看节点启动情况:

    1
    2
    3
    4
    5
    docker-compose ps
    Name Command State Ports
    ----------------------------------------------------------------------------------------------------------------------------
    etcd1 /usr/local/bin/etcd Up 0.0.0.0:20000->2379/tcp,:::20000->2379/tcp, 0.0.0.0:20001->2380/tcp,:::20001->2380/tcp
    etcd2 /usr/local/bin/etcd Up 0.0.0.0:20002->2379/tcp,:::20002->2379/tcp, 0.0.0.0:20003->2380/tcp,:::20003->2380/tcp

    查看挂载的数据卷:

    1
    2
    3
    4
    5
    docker volume ls
    DRIVER VOLUME NAME
    local 7982f1ed038a84127d5c08baa59b2e95cbc0474db6750494be4d001a38c7a68d
    local etcd_etcd1_data
    local etcd_etcd2_data

    查看指定数据卷的挂载详情:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    # 注意:没有加 internal 选项时,自动生成卷名时会加上项目名前缀
    docker volume inspect etcd_etcd1_data
    [
    {
    "CreatedAt": "2021-11-17T14:56:05+08:00",
    "Driver": "local",
    "Labels": {
    "com.docker.compose.project": "etcd",
    "com.docker.compose.version": "1.29.2",
    "com.docker.compose.volume": "etcd1_data"
    },
    "Mountpoint": "/var/lib/docker/volumes/etcd_etcd1_data/_data",
    "Name": "etcd_etcd1_data",
    "Options": null,
    "Scope": "local"
    }
    ]

    观察集群状态:

    1
    2
    3
    4
    docker exec -it etcd2 /bin/sh
    etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379 endpoint health
    http://etcd1:2379 is healthy: successfully committed proposal: took = 8.244662ms
    http://etcd2:2379 is healthy: successfully committed proposal: took = 8.300642ms

    获取节点 ID:

    1
    2
    3
    4
    docker exec -it etcd2 /bin/sh
    etcdctl member list
    ade526d28b1f92f7, started, etcd1, http://etcd1:2380, http://etcd1:2379, false
    d282ac2ce600c1ce, started, etcd2, http://etcd2:2380, http://etcd2:2379, false

    移除节点:

    1
    2
    docker exec -it etcd2 /bin/sh
    etcdctl --endpoints=http://etcd1:2379,http://etcd2:2379 member remove ade526d28b1f92f7

贰. 关于数据的 CRUD + Watch

CURL

  1. v3 restful api
    我们往一个node上上传数据,在另一个node上就能查询到, 因为键和值字段定义为字节数组,因此必须使用JSON进行base64编码。
    1
    2
    3
    4
    5
    6
    curl -L http://localhost:20000/v3/kv/put -X POST -d '{"key": "Zm9v", "value": "YmFy"}'
    {"header":{"cluster_id":"10220489627942555976","member_id":"12530464223947363063","revision":"3","raft_term":"3"}}
    # 注意:这里使用的key与value是basse64加密过的: foo=>Zm9v, bar=>YmFy
    # 不然会报错: use curl , illegal base64 data at input byte 4
    curl -L http://localhost:20000/v3/kv/range -X POST -d '{"key": "Zm9v"}'
    {"header":{"cluster_id":"10220489627942555976","member_id":"12530464223947363063","revision":"3","raft_term":"3"},"kvs":[{"key":"Zm9v","create_revision":"2","mod_revision":"3","version":"2","value":"YmFy"}],"count":"1"}
  2. etcdctl
    使用命令行工具etcdctl
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # 进入节点etcd1, 设置 foo => "bar"
    docker exec -it etcd1 etcdctl put foo bar
    OK
    # 进入节点etcd2, 获取key为 foo 所对应的 value,如果能获得且为 bar,即搭建成功
    docker exec -it etcd2 etcdctl get foo
    # 按前缀读取:
    docker exec -it etcd2 etcdctl get --limit=1 --prefix foo
    foo // key
    bar // value
    # 上面同时返回了 key 和 value,怎么只读取 key 对应的值呢:
    docker exec -it etcd2 etcdctl get foo --print-value-only
    bar // value
    # 所有键值:
    docker exec -it etcd2 etcdctl get '' --prefix
    foo
    bar
    # 删除 key 为 foo 的命令:
    docker exec -it etcd1 etcdctl del foo
    # 删除键值对的命令:
    docker exec -it etcd1 etcdctl del --prev-kv foo
    1
    foo
    bar
    # 清理所有键值对
    docker exec -it etcd1 etcdctl del '' --prefix
    1

    Watch

  3. etcdctl
    应用程序可以使用watch观察一个键或一系列键来监视任何更新。
    打开第一个终端,监听foo的变化,我们输入如下命令:
    1
    docker exec -it etcd1 etcdctl watch foo
    再打开另外一个终端来对 foo 进行操作:
    1
    2
    3
    4
    5
    docker exec -it etcd2 /bin/sh 
    etcdctl put foo 123
    OK
    etcdctl put foo 456
    OK
    第一个终端结果如下:
    1
    2
    3
    4
    5
    6
    PUT
    foo
    123
    PUT
    foo
    456
  4. v3 restful api
    使用curl请求:
    1
    curl -N http://localhost:20000/v3/watch -X POST -d '{"create_request": {"key":"Zm9v"} }' &
    再打开另外一个终端来对foo进行操作:
    1
    2
    curl -L http://localhost:20000/v3/kv/put -X POST -d '{"key": "Zm9v", "value": "MTIz"}'
    curl -L http://localhost:20000/v3/kv/put -X POST -d '{"key": "Zm9v", "value": "NDU2"}'
    第一个终端结果如下:
    1
    2
    {"result":{"header":{"cluster_id":"10220489627942555976","member_id":"12530464223947363063","revision":"5","raft_term":"3"},"events":[{"kv":{"key":"Zm9v","create_revision":"2","mod_revision":"5","version":"4","value":"MTIz"}}]}}
    {"result":{"header":{"cluster_id":"10220489627942555976","member_id":"12530464223947363063","revision":"6","raft_term":"3"},"events":[{"kv":{"key":"Zm9v","create_revision":"2","mod_revision":"6","version":"5","value":"NDU2"}}]}}
    除了以上基本操作, watch也可以像get、del操作那样使用prefix、rev、 hex等参数,这里就不一一列举了。
    ETCD的详细API请参考相关文档

叁. 总结

祝玩得开心!

Done.

CATALOG
  1. 1. 简介
  2. 2. 零. 服务部署
  3. 3. 壹. 测试验证
  4. 4. 贰. 关于数据的 CRUD + Watch
    1. 4.1. CURL
    2. 4.2. Watch
  5. 5. 叁. 总结