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
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
- 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])