ETCD(4):etcdctl的使用

1,073 阅读5分钟

1. etcdctl 的实践应用

etcdctl 是一个命令行客户端,它能提供一些简洁的命令,供用户直接跟etcd服务打交道,而无需基于 HTTP API 方式。可以方便我们在对服务进行测试或者手动修改数据库内容。我们刚开始可以通过 etdctl 来熟悉相关操作。这些操作跟 HTTP API 基本上是对应的。etcdctl 在两个不同的 etcd 版本下的行为方式也完全不同。

export ETCDCTL_API=2
export ETCDCTL_API=3

这里主要以讲解 API 3 为主。

etcdctl 支持的命令大体上分为数据库操作和非数据库操作两类。

2. 常用命令介绍

查看一下 etcd 的版本:

etcd --version

image.png

etcdctl -h

可以看到,etcdctl 支持的命令很多,常用的命令选项:

--debug 输出CURL命令,显示执行命令的时候发起的请求
--no-sync 发出请求之前不同步集群信息
--output, -o 'simple' 输出内容的格式(simple 为原始信息,json 为进行json格式解码,易读性好一些)
--peers, -C 指定集群中的同伴信息,用逗号隔开(默认为: "127.0.0.1:4001")
--cert-file HTTPS下客户端使用的SSL证书文件
--key-file HTTPS下客户端使用的SSL密钥文件
--ca-file 服务端使用HTTPS时,使用CA文件进行验证
--help, -h 显示帮助命令信息
--version, -v 打印版本信息

下面我们将介绍其中常用的数据库命令。

3. 数据库操作

数据库操作围绕对键值和目录的 CRUD 完整生命周期的管理。

etcd在键的组织上采用了层次化的空间结构(类似于文件系统中目录的概念),用户指定的键可以为单独的名字,如:testkey,此时实际上放在根目录/下面,也可以为指定目录结构,如/cluster1/node2/testkey,则将创建相应的目录结构。

3.1 键操作

  • put 指定某个键的值。例如:

    $ etcdctl put /testdir/testkey "Hello world"
    $ etcdctl put /testdir/testkey2 "Hello world2"
    $ etcdctl put /testdir/testkey3 "Hello world3"
    

    成功写入三对键值,/testdir/testkey、/testdir/testkey2 和 /testdir/testkey3。

  • get 获取指定键的值:

    $ etcdctl get /testdir/testkey
    Hello world
    
  • get 十六进制读指定的值:

    $ etcdctl get /testdir/testkey --hex
    \x2f\x74\x65\x73\x74\x64\x69\x72\x2f\x74\x65\x73\x74\x6b\x65\x79 #键
    \x48\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64 #值
    

    加上 --print-value-only 可以读取对应的值。

  • get 范围内的值

     $ etcdctl get /testdir/testkey /testdir/testkey3
    
    /testdir/testkey
    Hello world
    /testdir/testkey2
    Hello world2
    

    可以看到,获取了大于等于 /testdir/testkey,且小于 /testdir/testkey3 的键值对。左闭右开

  • 获取某个前缀的所有键值对,通过 --prefix 可以指定前缀:

    $ etcdctl get --prefix /testdir/testkey
    /testdir/testkey
    Hello world
    /testdir/testkey2
    Hello world2
    /testdir/testkey3
    Hello world3
    

    当前缀获取的结果过多时,还可以通过 --limit=2 限制获取的数量:

    etcdctl get --prefix --limit=2 /testdir/testkey
    
  • 读取键过往版本的值 应用可能想读取键的被替代的值。

    • 例如,应用可能想通过访问键的过往版本来回滚到旧的配置。或者,应用可能想通过多个请求来得到一个覆盖多个键的统一视图,而这些请求可以通过访问键历史记录而来。因为 etcd 集群上键值存储的每个修改都会增加 etcd 集群的全局修订版本,应用可以通过提供旧有的 etcd 修改版本来读取被替代的键。现有如下这些键值对:
    foo = bar         # revision = 2
    foo1 = bar1       # revision = 3
    foo = bar_new     # revision = 4
    foo1 = bar1_new   # revision = 5
    

    以下是访问以前版本 key 的示例:

    $ etcdctl get --prefix foo # 访问最新版本的key
    foo
    bar_new
    foo1
    bar1_new
    
    $ etcdctl get --prefix --rev=4 foo # 访问第4个版本的key
    foo
    bar_new
    foo1
    bar1
    
    $ etcdctl get --prefix --rev=3 foo #  访问第3个版本的key
    foo
    bar
    foo1
    bar1
    
    $ etcdctl get --prefix --rev=2 foo #  访问第2个版本的key
    foo
    bar
    
    $ etcdctl get --prefix --rev=1 foo #  访问第1个版本的key
    
  • 读取大于等于指定键的 byte 值的键。假设 etcd 集群已经有下列键:

    a = 123
    b = 456
    z = 789
    

    读取大于等于键 b 的 byte 值的键:

    $ etcdctl get --from-key b
    b
    456
    z
    789
    
  • 删除键。可以从 etcd 集群中删除一个键或者特定范围的键。 假设 etcd 集群已经有下列键:

    foo = bar
    foo1 = bar1
    foo3 = bar3
    zoo = val
    zoo1 = val1
    zoo2 = val2
    a = 123
    b = 456
    z = 789
    

    删除键 foo 的命令:

    $ etcdctl del foo
    1 # 删除了一个键
    

    删除从 foo to foo9 范围的键的命令:

    $ etcdctl del foo foo9
    2 # 删除了两个键
    

    删除键 zoo 并返回被删除的键值对的命令:

    $ etcdctl del --prev-kv zoo
    1   # 一个键被删除
    zoo # 被删除的键
    val # 被删除的键的值
    

    删除前缀为 zoo 的键的命令:

    $ etcdctl del --prefix zoo
    2 # 删除了两个键
    

    删除大于等于键 b 的 byte 值的键的命令:

    $ etcdctl del --from-key b
    2 # 删除了两个键
    

    etcd可通过读取一个key来获取当前etcd服务端的版本号,不管key是否存在

    etcdctl get /name ‐w=json
    

image.png

  • cluster_id:请求的etcd集群ID。
  • member_id:请求的etcd节点ID。
  • revision:etcd服务端当前全局数据版本号。对任一key的put或delete操作都会使revision自增1。revision=1是etcd的保留版本号,因此用户的key版本号将从2开始。
  • raft_term:etcd当前raft主节点任期号。

3.2 watch 历史改动

  • watch 监测一个键值的变化,一旦键值发生更新,就会输出最新的值并退出。例如:用户更新 testkey 键值为 Hello watch。

    $ etcdctl watch  testkey
    # 在另外一个终端: etcdctl put  testkey Hello watch
    testkey
    Hello watch
    

    监测从 foo 到 foo9 的键:

    $ etcdctl watch foo foo9
    # 在另外一个终端: etcdctl put foo bar
    PUT
    foo
    bar
     
    etcdctl put foo1 bar1
    PUT
    foo1
    bar1
    

    观察多个键 foo 和 zoo 的命令:

    $ etcdctl watch -i
    $ watch foo
    $ watch zoo
    
  • 查看 key 的历史改动,应用可能想观察 etcd 中键的历史改动。例如,应用想接收到某个键的所有修改。如果应用一直连接到 etcd,那么 watch 就足够好了。但是,如果应用或者 etcd 出错,改动可能发生在出错期间,这样应用就没能实时接收到这个更新。为了保证更新被交付,应用必须能够观察到键的历史变动。为了做到这点,应用可以在观察时指定一个历史修订版本,就像读取键的过往版本一样。
    假设我们完成了下列操作序列:

    $ etcdctl put foo bar         # revision = 2
    OK
    $ etcdctl put foo1 bar1       # revision = 3
    OK
    $ etcdctl put foo bar_new     # revision = 4
    OK
    $ etcdctl put foo1 bar1_new   # revision = 5
    OK
    

    观察历史改动:

    # 从修订版本 2 开始观察键 `foo` 的改动
    $ etcdctl watch --rev=3 foo
    PUT
    foo
    bar_new
    
  • 压缩修订版本。如我们提到的,etcd 保存修订版本以便应用可以读取键的过往版本。但是,为了避免积累无限数量的历史数据,压缩过往的修订版本就变得很重要。压缩之后,etcd 删除历史修订版本,释放资源来提供未来使用。所有修订版本在压缩修订版本之前的被替代的数据将不可访问。这是压缩修订版本的命令:

    $ etcdctl compact 5
    compacted revision 5 #在压缩修订版本之前的任何修订版本都不可访问
    $ etcdctl get --rev=4 foo
    {"level":"warn","ts":"2020-05-04T16:37:38.020+0800","caller":"clientv3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"endpoint://client-c0d35565-0584-4c07-bfeb-034773278656/127.0.0.1:2379","attempt":0,"error":"rpc error: code = OutOfRange desc = etcdserver: mvcc: required revision has been compacted"}
    Error: etcdserver: mvcc: required revision has been compacted
    

3.3 租约

  • 可以为etcd设定租约。在时间到期后租约失效。键可以绑定到租约上,租约到期时键随着失效

    # 授予租约,TTL为100秒
    $ etcdctl lease grant 100
    lease 694d71ddacfda227 granted with TTL(100s)
    
    # 附加键 foo 到租约694d71ddacfda227
    $ etcdctl put --lease=694d71ddacfda227 foo10 bar
    OK
    
  • 撤销租约 应用通过租约 id 可以撤销租约。撤销租约将删除所有它附带的 key:

    $ etcdctl lease revoke 694d71ddacfda227
    lease 694d71ddacfda227 revoked
    
  • 刷新租期
    应用程序可以通过刷新其TTL来保持租约活着,因此不会过期。

    $ etcdctl lease keep-alive 694d71ddacfda227
    lease 694d71ddacfda227 keepalived with TTL(100)
    lease 694d71ddacfda227 keepalived with TTL(100)
    ...
    
  • 查询租期 应用程序可能想要了解租赁信息,以便它们可以续订或检查租赁是否仍然存在或已过期。应用程序也可能想知道特定租约所附的 key。

    假设我们完成了以下一系列操作:

    $ etcdctl lease grant 300
    lease 694d71ddacfda22c granted with TTL(300s)
    
    $ etcdctl put --lease=694d71ddacfda22c foo10 bar
    OK
    

    获取有关租赁信息以及哪些 key 使用了租赁信息:

    $ etcdctl lease timetolive 694d71ddacfda22c
    lease 694d71ddacfda22c granted with TTL(300s), remaining(282s)
    
    $ etcdctl lease timetolive --keys 694d71ddacfda22c
    lease 694d71ddacfda22c granted with TTL(300s), remaining(220s), attached keys([foo10])