0%

etcdctl 工具总结

etcdctl 是一个 etcd 命令行工具,通过它可以与 etcd 集群进行交互。这篇文章总结下 etcdctl 的使用方法。

通用说明

  • 当前 etcdctl 默认使用 v3 API 和 etcd 通信。如果想要使用 v2 API,可以设置环境变量:ETCDCTL_API=2
  • 所有的命令都可以通过 -w--write-out 选项设置输出格式。支持的输出格式有 simplejsonProtobufFields
  • 所有命令默认都是 simple 输出。如果一个命令有对应的 RPC,那么它可以接受所有输出格式
  • 如果命令执行失败,返回非 0 退出码,同时会输出错误字符串信息,此时输出格式不生效

Key-value 命令

设置 key

命令语法:

1
PUT [options] <key> <value>
  • 为指定 key 设置 value
  • 对应的 RPC: Put

通用选项:

  • --lease <lease ID>:设置 key 所使用的租约 ID
  • --prev-kv:返回该 key 修改之前的值
  • ignore-value:使用当前值更新 key
  • ignore-lease:使用当前 lease 更新 key

示例:

1
2
3
4
5
$ etcdctl put foo bar
OK
$ etcdctl get foo
foo
bar
1
2
3
4
5
6
7
$ etcdctl put foo bar1 --prev-kv
OK
foo
bar
$ etcdctl get foo
foo
bar1
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
$etcdctl put foo --ignore-value
OK
$ etcdctl get foo
foo
bar1

$ etcdctl get foo -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 12530464223947363063
"Revision" : 4
"RaftTerm" : 2
"Key" : "foo"
"CreateRevision" : 2
"ModRevision" : 4
"Version" : 3
"Value" : "bar1"
"Lease" : 0
"More" : false
"Count" : 1

$ etcdctl put foo --ignore-value
OK

// 可以看到,虽然值没有变,但是其 ModRevision 发生了改变
$ etcdctl get foo -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 12530464223947363063
"Revision" : 5
"RaftTerm" : 2
"Key" : "foo"
"CreateRevision" : 2
"ModRevision" : 5
"Version" : 4
"Value" : "bar1"
"Lease" : 0
"More" : false
"Count" : 1

注意事项:

  • 如果想在 value 中包含换行符,需要在输入时使用 "" 引用输入的内容。
  • 如果输入 value 中包含 -,可以通过如下形式解决,否则 -value 会被当成命令 flag
1
2
./etcdctl put <key> -- <value>
./etcdctl put -- <key> <value>

例如:

1
2
3
4
5
$ etcdctl put foo3 -- -test
OK
$ etcdctl get foo3
foo3
-test

获取 key

命令语法:

1
GET [options] <key> [range_end]
  • 用于获取某个 key 或某个 key 范围 [key, range_end)
  • 对应的 RPC:Range

常用选项:

  • --hex:以十六进制输出 key/value
  • --limit <number>:限制输出结果的个数
  • --prefix:通过前缀匹配获取 key
  • --order:对结果排序,ASCEND 或 DESCEND
  • sort-by:设置排序依据,可以是 CREATE、KEY、MODIFY、VALUE 或 VERSION
  • --rev <revision>:指定 KV 版本
  • --print-value-only:只输出值
  • --consistency:一致性,可以是 Linearizable 或 Serializable
  • from-key:获取大于等于指定 key 的所有 key(通过字节比较排序)
  • keys-only:只输出 key

示例:

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
$ etcdctl get foo
foo
bar1

$ etcdctl get foo foo2
foo
bar1
foo1
bar1

$ etcdctl get foo foo2 --limit 1
foo
bar1

$ etcdctl get foo --prefix
foo
bar1
foo1
bar1
foo2
barnew
foo3
-test4

$ etcdctl get foo foo2 --order DESCEND --sort-by MODIFY
foo1
bar1
foo
bar1

$ etcdctl get foo foo2 --print-value-only
bar1
bar1

$ etcdctl get foo --from-key
foo
bar1
foo1
bar1
foo2
barnew
foo3
-test4

$ etcdctl get foo --from-key --keys-only
foo

foo1

foo2

foo3

注意事项:

  • 可以通过 etcdctl get --from-key '' 获取所有的 key
  • 当 key 或 value 中有不可打印字符或者控制字符,此时输出可能会引入混淆,为了解决该问题,可以使用 --hex 进行输出

删除 key

命令语法:

1
DEL [options] <key> [range_end]
  • 移除指定的 key 或 key 范围
  • 对应的 RPC 方法:DeleteRange
  • 如果删除成功,返回删除的元素个数

常用选项:

  • --prefix:通过前缀匹配指定 key
  • --prev-kv:返回删除的 key-value 对
  • --from-key:删除大于等于指定 key 的所有 key(通过字节比较排序)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ etcdctl del foo
1
$ etcdctl del foo foo1
0
$ etcdctl del foo foo2
1
$ etcdctl del foo2 --prev-kv
1
foo2
barnew
$ etcdctl del foo2 --from-key
1
$ etcdctl del foo2 --prefix
0

事务

命令语法:

1
TXN [options]
  • TXN 从标准输入中读取多个请求,并将它们应用到单个原子的事务操作中。一个事务包含 一系列的条件所有条件都满足时要执行的一系列请求任意条件不满足时要执行的一系列请求
  • 对应的 RPC:Txn

TXN 的语法为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<Txn> ::= <CMP>* "\n" <THEN> "\n" <ELSE> "\n"
<CMP> ::= (<CMPCREATE>|<CMPMOD>|<CMPVAL>|<CMPVER>|<CMPLEASE>) "\n"
<CMPOP> ::= "<" | "=" | ">"
<CMPCREATE> := ("c"|"create")"("<KEY>")" <CMPOP> <REVISION>
<CMPMOD> ::= ("m"|"mod")"("<KEY>")" <CMPOP> <REVISION>
<CMPVAL> ::= ("val"|"value")"("<KEY>")" <CMPOP> <VALUE>
<CMPVER> ::= ("ver"|"version")"("<KEY>")" <CMPOP> <VERSION>
<CMPLEASE> ::= "lease("<KEY>")" <CMPOP> <LEASE>
<THEN> ::= <OP>*
<ELSE> ::= <OP>*
<OP> ::= ((see put, get, del etcdctl command syntax)) "\n"
<KEY> ::= (%q formatted string)
<VALUE> ::= (%q formatted string)
<REVISION> ::= "\""[0-9]+"\""
<VERSION> ::= "\""[0-9]+"\""
<LEASE> ::= "\""[0-9]+\""

如果执行的是事务成功条件下的命令列表,输出 SUCCESS,否则输出 FAILURE。同时会输出命令列表中的每个命令的结果,以空行分隔。

常用选项:

  • --hex:以十六进制输出 key 和 value
  • --interactive:以交互模式执行 input transaction

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ etcdctl txn -i
compares:
mod("key1") > "0"

success requests (get, put, del):
put key1 "overwrote-key1"

failure requests (get, put, del):
put key1 "created-key1"
put key2 "some extra key"

FAILURE

OK

OK
$ etcdctl get key1
key1
created-key1
$ etcdctl get key2
key2
some extra key

注意事项:

  • 由于在 TXN 中通过换行符来分隔事务命令,因此如果 TXN 命令中如果本身需要输入换行符,则必须使用 \n

压缩

命令语法:

1
COMPACTION [options] <revision>
  • compaction 命令用于丢弃给定 revision 之前的所有 etcd 事件历史。由于 etcd 使用多版本并发控制模型,它会以事件历史的形式保存所有的 key 更新记录。当给定 revision 之前的事件历史不再需要时候,此时可以对 key 进行压缩以释放 etcd 后端数据存储空间
  • 对应的 RPC 方法:Compact

常用选项:

  • --physical:等待 compaction 操作物理移除所有旧的 revisions

示例:

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
$ etcdctl put key value1 -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 12530464223947363063
"Revision" : 21
"RaftTerm" : 2

$ etcdctl put key value2 -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 12530464223947363063
"Revision" : 22
"RaftTerm" : 2

$ etcdctl compact 22
compacted revision 22
I have no name!@9008eb121933:/opt/bitnami/etcd$ etcdctl get key
key
value2

$ etcdctl get key --rev 22
key
value2

$ etcdctl get key --rev 21
{"level":"warn","ts":"2022-02-23T11:34:26.239Z","logger":"etcd-client","caller":"v3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc00023e000/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

WATCH

命令语法:

1
WATCH [options] [key or prefix] [range_end] [--] [exec-command arg1 arg2 ...]
  • 通过 Watch 命令可以监控指定 key、前缀、key 范围的事件流。watch 命令会持续运行,直到出现错误或终端用户手动终止
  • 对应的 RPC 方法:Watch
  • 输出的格式为:
1
<event>[\n<old_key>\n<old_value>]\n<key>\n<value>\n<event>\n<next_key>\n<next_value>\n...

常用选项:

  • --hex:以十六进制输出 key 和 value
  • --interactive:开始交互式的 watch
  • --prefix:按前缀进行 watch
  • --prev-kv:输出之前的 key-value 值
  • --rev:从指定的 revision 开始 watch,这可以使得我们获得之间的事件

示例:

1
2
3
4
5
6
7
8
9
$ etcdctl watch foo

$ etcdctl put foo bar
OK

$ etcdctl watch foo
PUT
foo
bar
1
2
3
4
5
6
7
8
$ etcdctl put foo bar2

$ etcdctl watch foo --prev-kv
PUT
foo
bar
foo
bar2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ etcdctl put foo bar3
OK
$ etcdctl put foo3 bar3
OK
$ etcdctl put foo1 bar1
OK

$ etcdctl watch foo foo2
PUT
foo
bar3
PUT
foo1
bar1
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
$ etcdctl put foo bar4 -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 15168875803774599630
"Revision" : 33
"RaftTerm" : 2
$ etcdctl put foo bar5 -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 15168875803774599630
"Revision" : 34
"RaftTerm" : 2
$ etcdctl put foo bar6 -w fields
"ClusterID" : 10316109323310759371
"MemberID" : 15168875803774599630
"Revision" : 35
"RaftTerm" : 2

$ etcdctl watch foo --rev 34
PUT
foo
bar5
PUT
foo
bar6

$ etcdctl watch foo --rev 35
PUT
foo
bar6

如果想在收到事件后执行命令,可以通过 [--] [exec-command arg1 arg2 ...] 的方式指定,例如在收到事件后,执行 echo watch event received

1
2
3
4
5
6
7
8
9
10
$ etcdctl watch foo -- echo watch event received

$ etcdctl put foo bar
OK

$ etcdctl watch foo -- echo watch event received
PUT
foo
bar
watch event received

watch 的响应会通过环境变量 ETCD_WATCH_* 设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ etcdctl put foo bar

$ etcdctl watch foo -- sh -c "env | grep ETCD_WATCH_"
PUT
foo
bar
ETCD_WATCH_REVISION=25
ETCD_WATCH_KEY="foo"
ETCD_WATCH_EVENT_TYPE="PUT"
ETCD_WATCH_VALUE="bar"
DELETE
foo

$ etcdctl del foo
ETCD_WATCH_REVISION=26
ETCD_WATCH_KEY="foo"
ETCD_WATCH_EVENT_TYPE="DELETE"
ETCD_WATCH_VALUE=""

租约

创建租约

命令语法:

1
LEASE GRANT <ttl>
  • 新建一个租约,租约的到期时间为 ttl
  • 对应的 RPC:LeaseGrant
  • 输出创建的租约 ID

示例:

1
2
3
4
5
6
7
8
$ etcdctl lease grant 20
lease 12f77f2076d86f50 granted with TTL(20s)
$ etcdctl put foo bar --lease 12f77f2076d86f50
OK
$ etcdctl get foo
foo
bar
$ etcdctl get foo

释放租约

命令语法:

1
LEASE REVOKE <leaseID>
  • 释放一个指定的租约,并删除该租约关联的所有 keys
  • 对应的 RPC:LeaseRevoke

示例:

1
2
3
4
5
6
7
8
9
10
$ etcdctl lease grant 600
lease 12f77f2076d86f60 granted with TTL(600s)
$ etcdctl put foo bar --lease 12f77f2076d86f60
OK
$ etcdctl get foo
foo
bar
$ etcdctl lease revoke 12f77f2076d86f60
lease 12f77f2076d86f60 revoked
$ etcdctl get foo

获取租约

命令语法:

1
LEASE TIMETOLIVE <leaseID> [options]
  • 获取指定租约的信息
  • 对应的 RPC 方法:LeaseTimeToLive

常用选项:

  • --keys:获取该租约上附加的 keys

示例:

1
2
3
4
5
6
7
8
9
10
11
$ etcdctl lease grant 600
lease 12f77f2076d86f66 granted with TTL(600s)
$ etcdctl put foo bar --lease 12f77f2076d86f66
OK
$ etcdctl lease timetolive 12f77f2076d86f66
lease 12f77f2076d86f66 granted with TTL(600s), remaining(572s)
$ etcdctl lease timetolive 12f77f2076d86f66 --keys
lease 12f77f2076d86f66 granted with TTL(600s), remaining(566s), attached keys([foo])
$ etcdctl put foo1 bar1 --lease 12f77f2076d86f66
$ etcdctl lease timetolive 12f77f2076d86f66 --keys
lease 12f77f2076d86f66 granted with TTL(600s), remaining(462s), attached keys([foo foo1])

获取租约列表

命令语法:

1
LEASE LIST
  • 列出所有的 lease
  • 对应的 RPC 方法:LeaseLeases

示例:

1
2
3
$ etcdctl lease list
found 1 leases
12f77f2076d86f66

续约

命令语法:

1
LEASE KEEP-ALIVE <leaseID>
  • LEASE KEEP-ALIVE 周期性地对指定租约进行续约,因此该 lease 不会过期

示例:

1
2
3
4
5
6
7
8
$ etcdctl lease timetolive 12f77f2076d86f66
lease 12f77f2076d86f66 granted with TTL(600s), remaining(234s)

$ etcdctl lease keep-alive 12f77f2076d86f66
lease 12f77f2076d86f66 keepalived with TTL(600)

$ etcdctl lease timetolive 12f77f2076d86f66
lease 12f77f2076d86f66 granted with TTL(600s), remaining(556s)

集群维护命令

成员管理

成员管理命令用于管理 etcd 集群中的成员关系。

添加成员

命令语法:

1
MEMBER ADD <memberName> [options]
  • 在 etcd 集群中新添加一个成员
  • 输出新成员的成员 ID 以及其所在的 cluster ID
  • 对应的 RPC 方法:MemberAdd

常用选项:

  • peer-urls:新成员所关联的 peer-urls,如果包含多个 URL,需要用逗号分隔

示例:

1
2
3
4
5
6
7
$ etcdctl member add newMember --peer-urls=https://etcd4:2380
Member 2833744901904773 added to cluster 8f2a2ec5c0087dcb

ETCD_NAME="newMember"
ETCD_INITIAL_CLUSTER="newMember=https://etcd4:2380,etcd1=http://etcd1:2380,etcd3=http://etcd3:2380,etcd2=http://etcd2:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="https://etcd4:2380"
ETCD_INITIAL_CLUSTER_STATE="existing"

更新成员

命令语法:

1
MEMBER UPDATE <memberID> [options]
  • 对 etcd 集群中的 member 进行更新,只能更新 peer URLs
  • 输出更新的成员 ID 以及其所在的 cluster ID
  • 对应的 RPC 方法:MemberUpdate

常用选项:

  • --peer-urls:成员所关联的 peer-urls,如果包含多个 URL,需要用逗号分隔

示例:

1
2
$ etcdctl member update 2833744901904773 --peer-urls=https://etcd4:2380
Member 2833744901904773 updated in cluster 8f2a2ec5c0087dcb

移除成员

命令语法:

1
MEMBER REMOVE <memberID>
  • 从 etcd 集群中移除成员
  • 输出删除的成员 ID 以及其所在的 cluster ID。
  • 对应的 RPC 方法:MEMBER REMOVE

示例:

1
2
$ etcdctl member remove 2833744901904773
Member 2833744901904773 removed from cluster 8f2a2ec5c0087dcb

列出成员

命令语法:

1
MEMBER LIST
  • 显示 etcd 集群中的成员列表

示例:

1
2
3
4
$ etcdctl member list
ade526d28b1f92f7, started, etcd1, http://etcd1:2380, http://etcd1:2379, false
bd388e7810915853, started, etcd3, http://etcd3:2380, http://etcd3:2379, false
d282ac2ce600c1ce, started, etcd2, http://etcd2:2380, http://etcd2:2379, false

ENDPOINT 命令

ENDPOINT 命令用于查询独立的 endpoints。

节点健康信息

命令语法:

1
ENDPOINT HEALTH
  • 用于检查 cluster 集群中 endpoint 列表的健康情况。如果某个 endpoint 无法与集群的其他节点达成一致,就认为该节点是不健康的

常用选项:

  • --cluster:使用 etcd 集群中的所有成员

示例:

1
2
3
# 检查默认节点的健康状况
$ etcdctl endpoint health
127.0.0.1:2379 is healthy: successfully committed proposal: took = 8.8908ms
1
2
3
4
5
# 检查集群所有节点的健康状况
$ etcdctl endpoint --cluster health
http://etcd2:2379 is healthy: successfully committed proposal: took = 9.1295ms
http://etcd3:2379 is healthy: successfully committed proposal: took = 8.031ms
http://etcd1:2379 is healthy: successfully committed proposal: took = 25.7359ms

节点状态

命令语法:

1
ENDPOINT STATUS
  • ENDPOINT STATUS 用来查询给定 endpoint 列表中每个 endpoint 的状态。

示例:

1
2
3
4
5
6
7
$ etcdctl endpoint status
127.0.0.1:2379, ade526d28b1f92f7, 3.5.2, 25 kB, false, false, 2, 85, 85,

$ etcdctl endpoint status --cluster
http://etcd1:2379, ade526d28b1f92f7, 3.5.2, 25 kB, false, false, 2, 85, 85,
http://etcd3:2379, bd388e7810915853, 3.5.2, 25 kB, true, false, 2, 85, 85,
http://etcd2:2379, d282ac2ce600c1ce, 3.5.2, 25 kB, false, false, 2, 85, 85,

节点 HASHKV

命令语法:

1
ENDPOINT HASHKV
  • ENDPOINT HASHKV 用于获取某个 endpoint KV 存储的 hash 值

示例:

1
2
3
4
5
6
7
$ etcdctl endpoint hashkv
127.0.0.1:2379, 2755762864

$ etcdctl endpoint hashkv --cluster
http://etcd1:2379, 2755762864
http://etcd3:2379, 2755762864
http://etcd2:2379, 2755762864

ALARM 命令

提供告警相关的命令。

解除警告

命令语法:

1
ALARM DISARM
  • 解除所有的告警
  • 对应的 RPC 方法: Alarm

示例:

1
$ etcdctl alarm disarm

列出警告

1
ALARM LIST
  • 列出所有的告警
  • 对应的 RPC 方法为 Alarm

示例:

1
$ etcdctl alarm list

碎片整理

DEFRAG 命令可以在 etcd 运行时为一系列 endpoint 整理后端数据库文件的碎片。当 etcd member 删除或压缩 keys 时,这些 keys 占用的空间仍然会被占用。通过对数据库进行碎片整理,etcd 成员可以把这些空间归还给文件系统。

需要注意,在某个成员上进行在线的碎片整理会阻塞系统的读写。碎片整理操作默认不会在集群中传播,它只会应用于 local node。可以通过 --endpoints 指定集群成员,或者使用 --cluster 标志来指定所有集群成员。

如果想使用离线碎片整理(–data-dir flag),可以使用 etcutl defrag

示例:

1
2
3
4
etcdctl --endpoints=localhost:2379,badendpoint:2379 defrag
Finished defragmenting etcd member[localhost:2379]
{"level":"warn","ts":"2022-02-24T12:05:08.985Z","logger":"etcd-client","caller":"v3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc00020e000/localhost:2379","attempt":0,"error":"rpc error: code = DeadlineExceeded desc = latest balancer error: last connection error: connection error: desc = \"transport: Error while dialing dial tcp: lookup badendpoint on 127.0.0.11:53: no such host\""}
Failed to defragment etcd member[badendpoint:2379] (context deadline exceeded)
1
2
3
4
$ etcdctl defrag --cluster
Finished defragmenting etcd member[http://etcd1:2379]
Finished defragmenting etcd member[http://etcd3:2379]
Finished defragmenting etcd member[http://etcd2:2379]

如果想直接压缩某个数据目录,可以使用 etcdutl 并指定 --data-dir(该标志马上将被删除)。

快照命令

SNAPSHOT 命令可以用于实现快照。

保存快照

命令语法:

1
SNAPSHOT SAVE <filename>
  • 将 etcd 后端数据库实时的数据写入一个文件

示例:

1
2
3
4
5
6
7
8
etcdctl snapshot save test.db
{"level":"info","ts":1645705033.3974695,"caller":"snapshot/v3_snapshot.go:68","msg":"created temporary db file","path":"test.db.part"}
{"level":"info","ts":1645705033.4031475,"logger":"client","caller":"v3/maintenance.go:211","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":1645705033.403688,"caller":"snapshot/v3_snapshot.go:76","msg":"fetching snapshot","endpoint":"127.0.0.1:2379"}
{"level":"info","ts":1645705033.4247742,"logger":"client","caller":"v3/maintenance.go:219","msg":"completed snapshot read; closing"}
{"level":"info","ts":1645705033.428916,"caller":"snapshot/v3_snapshot.go:91","msg":"fetched snapshot","endpoint":"127.0.0.1:2379","size":"25 kB","took":"now"}
{"level":"info","ts":1645705033.4335535,"caller":"snapshot/v3_snapshot.go:100","msg":"saved","path":"test.db"}
Snapshot saved at test.db

恢复快照

命令语法:

1
SNAPSHOT RESTORE [options] <filename>
  • 它根据后端数据库快照以及新的集群配置,为 etcd 集群成员创建一个 etcd 数据目录。为新集群中的每个 member 恢复 snapshot,这样新的 etcd 集群就预先加载了快照数据
  • 该命令即将被遗弃,应该使用 etcdutl snapshot restore

该命令支持的选项基本类似于 etcd 集群命令:

  • --data-dir <dir>:数据目录的路径,如果没有指定的话默认使用 <name>.etcd
  • --wal-dir <dir>:WAL 目录路径,如果没有指定的话则使用数据目录
  • --initial-cluster <configuration>:初始集群配置
  • initial-cluster-token:初始 token
  • initial-advertise-peer-urls:初始通告的成员 peer URLS
  • name:集群成员名称
  • skip-hash-check:忽略快照的 hash value

示例:

1
2
3
4
5
6
7
8
9
$ etcdctl snapshot restore test.db --initial-cluster-token etcd-cluster-1 --initial-advertise-peer-urls http://127.0.0.1:12380  --name sshot1 --initial-cluster 'sshot1=http://127.0.0.1:12380,sshot2=http://127.0.0.1:22380,sshot3=http://127.0.0.1:32380'
Deprecated: Use `etcdutl snapshot restore` instead.

2022-02-24T13:03:33Z info snapshot/v3_snapshot.go:251 restoring snapshot {"path": "test.db", "wal-dir": "sshot1.etcd/member/wal", "data-dir": "sshot1.etcd", "snap-dir": "sshot1.etcd/member/snap", "stack": "go.etcd.io/etcd/etcdutl/v3/snapshot.(*v3Manager).Restore\n\t/tmp/etcd-release-3.5.2/etcd/release/etcd/etcdutl/snapshot/v3_snapshot.go:257\ngo.etcd.io/etcd/etcdutl/v3/etcdutl.SnapshotRestoreCommandFunc\n\t/tmp/etcd-release-3.5.2/etcd/release/etcd/etcdutl/etcdutl/snapshot_command.go:147\ngo.etcd.io/etcd/etcdctl/v3/ctlv3/command.snapshotRestoreCommandFunc\n\t/tmp/etcd-release-3.5.2/etcd/release/etcd/etcdctl/ctlv3/command/snapshot_command.go:128\ngithub.com/spf13/cobra.(*Command).execute\n\t/usr/local/google/home/siarkowicz/.gvm/pkgsets/go1.16.3/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:856\ngithub.com/spf13/cobra.(*Command).ExecuteC\n\t/usr/local/google/home/siarkowicz/.gvm/pkgsets/go1.16.3/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:960\ngithub.com/spf13/cobra.(*Command).Execute\n\t/usr/local/google/home/siarkowicz/.gvm/pkgsets/go1.16.3/global/pkg/mod/github.com/spf13/cobra@v1.1.3/command.go:897\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.Start\n\t/tmp/etcd-release-3.5.2/etcd/release/etcd/etcdctl/ctlv3/ctl.go:107\ngo.etcd.io/etcd/etcdctl/v3/ctlv3.MustStart\n\t/tmp/etcd-release-3.5.2/etcd/release/etcd/etcdctl/ctlv3/ctl.go:111\nmain.main\n\t/tmp/etcd-release-3.5.2/etcd/release/etcd/etcdctl/main.go:59\nruntime.main\n\t/usr/local/google/home/siarkowicz/.gvm/gos/go1.16.3/src/runtime/proc.go:225"}
2022-02-24T13:03:33Z info membership/store.go:141 Trimming membership information from the backend...
2022-02-24T13:03:33Z info membership/cluster.go:421 added member {"cluster-id": "ef37ad9dc622a7c4", "local-member-id": "0", "added-peer-id": "8211f1d0f64f3269", "added-peer-peer-urls": ["http://127.0.0.1:12380"]}
2022-02-24T13:03:33Z info membership/cluster.go:421 added member {"cluster-id": "ef37ad9dc622a7c4", "local-member-id": "0", "added-peer-id": "91bc3c398fb3c146", "added-peer-peer-urls": ["http://127.0.0.1:22380"]}
2022-02-24T13:03:33Z info membership/cluster.go:421 added member {"cluster-id": "ef37ad9dc622a7c4", "local-member-id": "0", "added-peer-id": "fd422379fda50e48", "added-peer-peer-urls": ["http://127.0.0.1:32380"]}
2022-02-24T13:03:33Z info snapshot/v3_snapshot.go:272 restored snapshot {"path": "test.db", "wal-dir": "sshot1.etcd/member/wal", "data-dir": "sshot1.etcd", "snap-dir": "sshot1.etcd/member/snap"}
1
etcd --name sshot1 --listen-client-urls http://127.0.0.1:2379 --advertise-client-urls http://127.0.0.1:2379 --listen-peer-urls http://127.0.0.1:12380 &

查快快照

命令语法:

1
SNAPSHOT STATUS <filename>
  • 用于查看后端数据库快照文件的详细信息

示例:

1
2
3
4
$ etcdctl snapshot status test.db
Deprecated: Use `etcdutl snapshot status` instead.

dc4be536, 48, 43, 25 kB
1
2
3
4
5
6
7
8
etcdctl snapshot status test.db -w table
Deprecated: Use `etcdutl snapshot status` instead.

+----------+----------+------------+------------+
| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |
+----------+----------+------------+------------+
| dc4be536 | 48 | 43 | 25 kB |
+----------+----------+------------+------------+

MOVE-LEADER

命令语法:

1
MOVE-LEADER
  • 用于切换 etcd 集群中的 leader

示例:

1
2
3
4
5
6
7
8
9
10
11
12
$ etcdctl endpoint status --cluster
http://etcd1:2379, ade526d28b1f92f7, 3.5.2, 25 kB, false, false, 2, 89, 89,
http://etcd3:2379, bd388e7810915853, 3.5.2, 25 kB, true, false, 2, 89, 89,
http://etcd2:2379, d282ac2ce600c1ce, 3.5.2, 25 kB, false, false, 2, 89, 89,

$ etcdctl endpoint status --cluster | grep -m 1 "false" | awk -F', ' '{print $2}'
ade526d28b1f92f7

$ etcdctl move-leader ade526d28b1f92f7
Error: no leader endpoint given at [127.0.0.1:2379]

$ etcdctl --endpoints bd388e7810915853 move-leader ade526d28b1f92f7

降级命令

降级在 v3.6 中是实验性质的特性,并不推荐在生产环境中使用。降级命令用于对集群进行降级。通常来说,由于集群版本机制的问题,etcd 成员是不能降级的。

在初始启动后,集群成员对集群版本达成一致。每隔 5 s,leader 会检查所有成员的版本并选择最小的版本。如果新加入的成员,其版本低于当前的集群版本,该成员无法加入集群,这样可以防止集群被降级。而降级命令则允许集群管理员强制对集群进行降级。

降级应该分阶段执行:

  • 执行 etcdctl downgrade validate <TARGET_VERSION> 验证当前集群是否准备好进行降级
  • etcdctl downgrade enable <TARGET_VERSION> 开始集群降级
  • 对于每个成员
    • 通过检查其 log 中是否包含 The server is ready to downgrade 来确认成员准备好执行降级
    • 替换成员的二进制版本
    • 确认每个成员都正确启动并加入集群
  • 通过检查 leader log 中是否包含 The server is ready to downgrade 来确认降级是否成功

降级校验

命令语法:

1
DOWNGRADE VALIDATE <TARGET_VERSION>
  • 在降级命令执行前检查是否能够进行降级

启动降级

命令语法:

1
DOWNGRADE ENABLE <TARGET_VERSION>
  • 开始对集群进行降级

取消降级

命令语法:

1
DOWNGRADE CANCEL <TARGET_VERSION>
  • 取消对集群的降级

并发命令

LOCK 命令

命令语法:

1
LOCK [options] <lockname> [command arg1 arg2 ...]
  • 获取一个分布式锁,该锁的名称由 lockname 指定。一旦 lock 获取到后,该锁一直会被持有,直到 etcdctl 命令终止
  • 如果 lock 获取到,同时没有指定要执行的命令,那么会输出则会输出该 lock 的 KEY
  • 如果 lock 获取到,同时指定了要执行的命令,那么换将变量 ETCD_LOCK_KEYETCD_LOCK_KEY 会输出成 lock 的 key 和 revision

常用选项:

  • lock 会话的超时时间

示例:

1
2
3
4
5
$ etcdctl lock mylock
mylock/12f77f2076d86fa0

$ etcdctl lock mylock etcdctl put foo bar
OK

注意事项:

  • 只有当 LOCK 命令是通过信号终止,并释放 lock 之后,LOCK 命令的退出码才是 0
  • 如果 LOCK 命令是异常终止,或者无法让集群释放锁时,该 lock 会一直被占有,直到租约过期(60s)

ELECT 命令

命令语法:

1
ELECT [options] <election-name> [proposal]
  • ELECT 命令用于参加一个命名选举。通过在 ELECT 命令中提供一个 prososal 值,来表明本节点参与本选举
  • 如果只是想观察选举,不用提供 prososal 值,但是需要使用 listen 选项
  • 无论何时 leader 被选举后,它的 prososal 值都会被打印出来
  • 对于候选人,如果该节点赢得了选举,会输出对应的 key 信息。如果是观察选举,ELECT 命令会持续输出选举的结果

示例:

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
## etcd1
$ etcdctl elect myelection etcd1
myelection/12f77f2076d86fb4
etcd1

## etcd2
$ etcdctl elect myelection etcd2


# observe
$ etcdctl elect myelection -l
myelection/12f77f2076d86fb4
etcd1

## stop etcd1

$ etcdctl elect myelection etcd2
myelection/41ce7f2076d86923
etcd2

$ etcdctl elect myelection -l
myelection/12f77f2076d86fb4
etcd1
myelection/41ce7f2076d86923
etcd2

注意事项:

  • 只有当 ELECT 命令是通过信号终止,并释放其候选人/领导者身份的时候,ELECT 命令的退出码才是 0
  • 如果候选人是异常终止,那么该选举过程会一直持续,直到默认租约过期(60s)

认证命令

开启/关闭认证

命令语法:

1
AUTH <enable or disable>
  • 用于开启或关闭 etcd 集群的认证机制。当开启 etcd 的认证机制的时候,etcd 会对所有请求进行认证检查
  • 对应的 RPC:AuthEnable/AuthDisable

添加角色

命令语法:

1
ROLE ADD <role name>
  • 创建一个角色
  • 对应的 RPC 方法:RoleAdd

示例:

1
2
$ etcdctl role add test
Role test created

获取角色

命令语法:

1
ROLE GET <role name>
  • 获取详细的角色信息
  • 对应的 RPC 方法 RoleGet

示例:

1
2
3
4
$ etcdctl role get test
Role test
KV Read:
KV Write:

删除角色

命令语法:

1
ROLE DELETE <role name>
  • 删除指定角色
  • 对应的 RPC 方法: RoleDelete

示例:

1
2
$ etcdctl role delete test
Role test deleted

列出角色

命令语法:

1
ROLE LIST <role name>
  • 列出 etcd 中所有的角色
  • 对应的 RPC 方法:RoleList

示例:

1
2
$ etcdctl role list
test

角色授权

命令语法:

1
ROLE GRANT-PERMISSION [options] <role name> <permission type> <key> [endkey]
  • 针对某个 key 或 key 范围,为 role 设置权限
  • 对应的 RPC 方法为 RoleGrantPermission

常用选项:

  • --from-key:为大于等于指定 key 的所有 key(通过字节比较排序)进行授权
  • --preifx:使用前缀匹配

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ etcdctl role grant-permission test readwrite test_key
Role test updated

$ etcdctl role get test
Role test
KV Read:
test_key
KV Write:
test_key

$ etcdctl role grant-permission test read foo/ --prefix
Role test updated
$ etcdctl role get test
Role test
KV Read:
[foo/, foo0) (prefix foo/)
test_key
KV Write:
test_key

取消授权

命令语法:

1
ROLE REVOKE-PERMISSION <role name> <permission type> <key> [endkey]
  • 针对某个 key 或者 key 范围,为 role 撤销权限
  • 对应的 RPC 方法为 RoleRevokePermission

常用选项:

  • --from-key:为大于等于指定 key 的所有 key(通过字节比较排序)取消授权
  • --preifx:使用前缀匹配

示例:

1
2
3
4
5
6
7
8
9
10
$ etcdctl role revoke-permission test test_key
Permission of key test_key is revoked from role test

$ etcdctl role revoke-permission test --prefix foo/
Permission of range [foo/, foo0) is revoked from role test

$ etcdctl role get test
Role test
KV Read:
KV Write:

添加用户

命令语法:

1
USER ADD <user name or user:password> [options]
  • 添加一个用户
  • 对应的 RPC 方法为:UserAdd

常用选项:

  • --interactive:交互模式,从标准输入中读取密码

示例:

1
2
3
4
etcdctl user add test_user
Password of test_user:
Type password of test_user again for confirmation:
User test_user created

获取用户

命令语法:

1
USER GET <user name> [options]
  • 获取指定用户的信息
  • 对应的RPC 方法 UserGet

常用选项:

  • --detail:显示用户所对应的角色及权限

示例:

1
2
etcdctl user get test_user --detail
User: test_user

删除用户

命令语法:

1
USER DELETE <user name>
  • 删除指定的用户
  • 对应的 RPC 方法为 UserDelete

示例:

1
2
$ etcdctl user delete test_user
User test_user deleted

列出用户

命令语法:

1
USER LIST

示例:

1
2
$ etcdctl user list
test_user
  • 列出所有的用户信息

设置密码

命令语法:

1
USER PASSWD <user name> [options]
  • 修改用户的密码
  • 对应的 RPC 方法:UserChangePassword

常用选项:

  • --interactive:交互模式,从标准输入中读取密码

示例:

1
2
3
4
$ etcdctl user passwd test_user
Password of test_user:
Type password of test_user again for confirmation:
Password updated

设置用户角色

命令语法:

1
USER GRANT-ROLE <user name> <role name>
  • 为 user 指定角色
  • 对应的 RPC 方法:UserGrantRole

示例:

1
2
$ etcdctl user grant-role test_user test
Role test is granted to user test_user

取消用户角色

命令语法:

1
USER REVOKE-ROLE <user name> <role name>
  • 撤销用户的角色
  • 对应的 RPC 方法:UserRevokeRole

示例:

1
2
$ etcdctl user revoke-role test_user test
Role test is revoked from user test_user

工具命令

make-mirror

命令语法:

1
MAKE-MIRROR [options] <destination>
  • 将 etcd 集群中的某些 key 映射到另一个 etcd 集群中

常用选项

  • --dest-cacert <cacert>:目的集群的 TLS cacert 文件
  • --dest-cacert <cert>:目的集群的 TLS cert 文件
  • --dest-key <key>:目的集群的 TLS key 文件
  • --prefix:按前缀匹配
  • dest-prefix:指定在目标集群中的前缀
  • no-dest-prefix:在目标集群的 root 下进行 mirror
  • dest-insecure-transport:关闭传输层安全

版本

命令语法:

1
VERSION
  • 输出 etcdctl 的版本

示例:

1
2
3
$ etcdctl version
etcdctl version: 3.5.2
API version: 3.5

CHECK

用于检查 etcd 集群中的各个信息。

性能检查

命令语法:

1
CHECK PERF [options]
  • 用于检查 etcd 集群的性能信息。
  • 对应的 RPC 方法:CheckPerf

常用选项:

  • --load:性能检查的负载模型,支持有:s(small), m(medium)、l(large)、xl(xlarge)
  • --prefix:性能测试使用的 key 前缀
  • --auto-compact:性能测试后,自动进行 compact
  • auto-defrag:性能测试后自动进行 defragment

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ etcdctl check perf --load="s"
60 / 60 Booooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo! 100.00% 1m0s
PASS: Throughput is 149 writes/s
PASS: Slowest request took 0.261242s
PASS: Stddev is 0.013076s
PASS

$ etcdctl check perf --load="l"
FAIL: too many errors
FAIL: ERROR(etcdserver: request timed out) -> 287
FAIL: Throughput too low: 297 writes/s
Slowest request took too long: 8.325122s
Stddev too high: 1.062989s
FAIL

数据规模检查

命令语法:

1
CHECK DATASCALE [options]
  • 检查在一个指定的 endpoint server 上,不同负载情况下保存数据所需要使用的内存
  • 对应的 RPC 方法 CheckDatascale

常用选项:

  • --load:所使用的负载模型,支持有:s(small), m(medium)、l(large)、xl(xlarge)
  • --prefix:所使用的 key 前缀
  • --auto-compact:性能测试后,自动进行 compact
  • auto-defrag:性能测试后自动进行 defragment

示例:

1
2
3
4
$ etcdctl check datascale --load="s"
Start data scale check for work load [10000 key-value pairs, 1024 bytes per key-value, 50 concurrent clients].
10000 / 10000 Boooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo! 100.00% 14s
PASS: Approximate system memory used : 91.16 MB.

Reference