etcd 對外通過 HTTP API 對外提供服務,這種方式方便測試(通過 curl 或者其他工具就能和 etcd 交互),也很容易集成到各種語言中(每個語言封裝 HTTP API 實現自己的 client 就行)。
下面介紹下 etcd 通過 HTTP API 提供了哪些功能,並使用 httpie
來交互(當然你也可以使用 curl 或者其他工具)。
一、etcd的http api
1.獲取 etcd 服務的版本信息
➜ http http://127.0.0.1:2379/version
HTTP/1.1 200 OK
Content-Length: 44
Content-Type: application/json
Date: Tue, 02 Aug 2016 04:27:32 GMT
{
"etcdcluster": "3.0.0",
"etcdserver": "3.0.4"
}
2.key 的新增
etcd 的數據按照樹形結構組織,類似於 linux 的文件系統,也有目錄和文件的區別,不過一般被稱爲 nodes。數據的 endpoint 都是以 /v2/keys
開頭(v2 表示當前 API 的版本),比如 /v2/keys/names/cizixs
。
要創建一個值,只要使用 PUT
方法在對應的 url endpoint 設置就行。如果對應的 key 已經存在, PUT
也會對 key 進行更新。
➜ http PUT http://127.0.0.1:2379/v2/keys/message value=="hello, etcd"
HTTP/1.1 201 Created
Content-Length: 100
Content-Type: application/json
Date: Tue, 02 Aug 2016 04:48:04 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 4
X-Raft-Index: 28429
X-Raft-Term: 2
{
"action": "set",
"node": {
"createdIndex": 4,
"key": "/message",
"modifiedIndex": 4,
"value": "hello, etcd"
}
}
上面這個命令通過 PUT
方法把 /message
設置爲 hello, etcd
。返回的格式中,各個字段的意義是:
action
:請求出發的動作,這裏因爲是新建一個 key 並設置它的值,所以是set。
node.key
:key 的 HTTP 路徑。node.value
:請求處理之後,key 對應的value值。node.createdIndex
: createdIndex 是一個遞增的值,每次有 key 被創建的時候會增加。node.modifiedIndex
:同上,只不過每次有 key 被修改的時候增加。
除返回的 json 體外,上面的情況還包含了一些特殊的 HTTP 頭部信息,這些信息說明了 etcd cluster 的一些情況。它們的具體含義如下:
X-Etcd-Index
:當前 etcd 集羣的 index。X-Raft-Index
:raft 集羣的 index。X-Raft-Term
:raft 集羣的任期,每次有 leader 選舉的時候,這個值就會增加。
3.key的查看
查看信息比較簡單,使用 GET
方法,url 指向要查看的值就行:
➜ http GET http://127.0.0.1:2379/v2/keys/message
HTTP/1.1 200 OK
Content-Length: 97
Content-Type: application/json
Date: Tue, 02 Aug 2016 05:23:14 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 7
X-Raft-Index: 30801
X-Raft-Term: 2
{
"action": "get",
"node": {
"createdIndex": 7,
"key": "/message",
"modifiedIndex": 7,
"value": "hello, etcd"
}
}
這裏的 action
變成了 get
,其他返回的值和上面的含義一樣,略過不提。
NOTE:這兩個命令並不是連着執行的,中間我有執行其他操作,因此 index
會出現不連續的情況。
4. key的更新
PUT
也可用來更新 key 的值。
➜ http PUT http://127.0.0.1:2379/v2/keys/message value=="I'm changed"
HTTP/1.1 200 OK
Content-Length: 184
Content-Type: application/json
Date: Tue, 02 Aug 2016 05:28:17 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 8
X-Raft-Index: 31407
X-Raft-Term: 2
{
"action": "set",
"node": {
"createdIndex": 8,
"key": "/message",
"modifiedIndex": 8,
"value": "I'm changed"
},
"prevNode": {
"createdIndex": 7,
"key": "/message",
"modifiedIndex": 7,
"value": "hello, etcd"
}
}
和第一次執行 PUT
命令不同的是,返回中多了一個字段 prevNode
,它保存着更新之前該 key 的信息。它的格式和 node
是一樣的,如果之前沒有這個信息,這個字段會被省略。
5.刪除 key
刪除 key 可以通過 DELETE
方法。
➜ http DELETE http://127.0.0.1:2379/v2/keys/message
HTTP/1.1 200 OK
Content-Length: 168
Content-Type: application/json
Date: Tue, 02 Aug 2016 05:31:56 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 9
X-Raft-Index: 31847
X-Raft-Term: 2
{
"action": "delete",
"node": {
"createdIndex": 8,
"key": "/message",
"modifiedIndex": 9
},
"prevNode": {
"createdIndex": 8,
"key": "/message",
"modifiedIndex": 8,
"value": "I'm changed"
}
}
注意,這裏的 action
是 delete
,並且 modifiedIndex
增加了,但是 createdIndex
沒有變化,因爲這是一個修改操作,不是新建操作。
6. 查看ttl
6.1 etcd 中,key 可以有 TTL 屬性,若超過這個時間,就會被自動刪除。
設置一個看看:
➜ http PUT http://127.0.0.1:2379/v2/keys/tempkey value=="Gone with wind" ttl==5
HTTP/1.1 201 Created
Content-Length: 159
Content-Type: application/json
Date: Tue, 02 Aug 2016 05:48:17 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 10
X-Raft-Index: 33810
X-Raft-Term: 2
{
"action": "set",
"node": {
"createdIndex": 10,
"expiration": "2016-08-02T05:48:22.618695843Z",
"key": "/tempkey",
"modifiedIndex": 10,
"ttl": 5,
"value": "Gone with wind"
}
}
除了一般 key 返回的信息之外,上面多了兩個字段:
expiration
:代表 key 過期被刪除的時間ttl
:表示 key 還要多少秒可以存活(這個值是動態的,會根據你請求的時候和過期時間進行計算)
如果我們在 5s 之後再去請求查看該 key,會發現報錯信息:
➜ http http://127.0.0.1:2379/v2/keys/tempkey
HTTP/1.1 404 Not Found
Content-Length: 74
Content-Type: application/json
Date: Tue, 02 Aug 2016 05:48:28 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 11
{
"cause": "/tempkey",
"errorCode": 100,
"index": 11,
"message": "Key not found"
}
http 返回爲 404
,並且返回體中給出了 errorCode
和錯誤信息。
6.2 TTL 也可通過 PUT
方法進行取消,只要設置空值 ttl=
就行,這樣 key 就不會過期被刪除。比如:
➜ http PUT http://127.0.0.1:2379/v2/keys/foo value==bar ttl== prevExist==true
注意:需要設置 value==bar,不然 key 會變成空值。
6.3 如果只是想更新 TTL,可以添加上 refresh==true
參數:
➜ etcd-v3.0.4-darwin-amd64 http -v PUT http://127.0.0.1:2379/v2/keys/tempkey refresh==true
HTTP/1.1 200 OK
Content-Length: 305
Content-Type: application/json
Date: Tue, 02 Aug 2016 06:05:12 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 20
X-Raft-Index: 35849
X-Raft-Term: 2
{
"action": "set",
"node": {
"createdIndex": 20,
"expiration": "2016-08-02T06:13:32.370495212Z",
"key": "/tempkey",
"modifiedIndex": 20,
"ttl": 500,
"value": "hello, there"
},
"prevNode": {
"createdIndex": 19,
"expiration": "2016-08-02T06:10:05.366042396Z",
"key": "/tempkey",
"modifiedIndex": 19,
"ttl": 293,
"value": "hello, there"
}
}
7.監聽變化
etcd 提供了監聽的機制,可以讓客戶端使用 long pulling 方式來監聽某個 key。當key發生變化的時候,可以接收到通知。因爲 etcd 經常被用作服務發現,若集羣中的信息有更新,需要及時被檢測,做出對應的處理。因此,需要有監聽機制,來告訴客戶端特定 key 的變化情況。
監聽動作只需要 GET
方法,添加上 wait=true
參數就行。使用 recursive=true
參數,也能監聽某個目錄。
➜ http http://127.0.0.1:2379/v2/keys/foo wait==true
HTTP/1.1 200 OK
Content-Type: application/json
Date: Tue, 02 Aug 2016 06:09:47 GMT
Transfer-Encoding: chunked
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 22
X-Raft-Index: 36401
X-Raft-Term: 2
這個時候,客戶端會阻塞在這裏。如果有另外的 terminal 修改 key 的值,則監聽的客戶端會接收到消息,並打印出更新的值:
{
"action": "set",
"node": {
"createdIndex": 23,
"key": "/foo",
"modifiedIndex": 23,
"value": "changed"
},
"prevNode": {
"createdIndex": 22,
"key": "/foo",
"modifiedIndex": 22,
"value": "bar"
}
}
除了這種最簡單的監聽之外,還可以提供基於 index 的監聽。如果通過 waitIndex
指定了 index,那麼會返回從 index 開始出現的第一個事件,這包含了兩種情況:
- 給出的 index 小於等於當前 index ,即事件已經發生,那麼監聽會立即返回該事件。
- 給出的 index 大於當前 index,等待 index 之後的事件發生並返回。
目前 etcd 只會保存最近 1000 個事件(整個集羣範圍內),再早之前的事件會被清理。如果監聽被清理的事件,則會報錯。如果出現漏過太多事件(超過 1000)的情況,需要重新獲取當然的 index 值(X-Etcd-Index
),然後從 X-Etcd-Index+1
開始監聽。
因爲在監聽的時候出現事件就會直接返回,所以需要客戶端編寫循環邏輯,保持監聽狀態。在兩次監聽的間隔中出現的事件,很可能被漏過。所以,最好把事件處理邏輯做成異步的,不要阻塞監聽邏輯。
注意:監聽 key 時會出現“長時間沒有返回,導致連接被 close ”的情況,客戶端需要處理這種錯誤,並自動重試。
8.自動創建有序的 keys
在有些情況下,我們需要 key 是有序的,etcd 提供了這個功能。對某個目錄使用 POST
方法,能自動生成有序的 key,這種模式可以用於隊列處理等場景。
➜ http POST http://127.0.0.1:2379/v2/keys/queue value==job1
HTTP/1.1 201 Created
Content-Length: 121
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:08:38 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1030
X-Raft-Index: 44470
X-Raft-Term: 2
{
"action": "create",
"node": {
"createdIndex": 1030,
"key": "/queue/00000000000000001030",
"modifiedIndex": 1030,
"value": "job1"
}
}
創建的 key 會使用 etcd index,只能保證遞增,無法保證是連續的(因爲在兩次創建之間,可能會有其他事件發生)。用相同的命令創建多個值,在獲取值的時候,使用 sorted=true
參數,就會返回已經排序的值:
➜ http http://127.0.0.1:2379/v2/keys/queue sorted==true
HTTP/1.1 200 OK
Content-Length: 385
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:11:32 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1032
X-Raft-Index: 44819
X-Raft-Term: 2
{
"action": "get",
"node": {
"createdIndex": 1030,
"dir": true,
"key": "/queue",
"modifiedIndex": 1030,
"nodes": [
{
"createdIndex": 1030,
"key": "/queue/00000000000000001030",
"modifiedIndex": 1030,
"value": "job1"
},
{
"createdIndex": 1031,
"key": "/queue/00000000000000001031",
"modifiedIndex": 1031,
"value": "job2"
},
{
"createdIndex": 1032,
"key": "/queue/00000000000000001032",
"modifiedIndex": 1032,
"value": "job3"
}
]
}
}
9.設置目錄的 TTL
和 key 類似,目錄(dir)也可以有過期時間。設置的方法也一樣,只不過多了 dir=true
參數來說明這是一個目錄。
➜ http PUT http://127.0.0.1:2379/v2/keys/dir dir==true ttl==5 prevExist==true
HTTP/1.1 200 OK
Content-Length: 226
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:15:42 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1033
X-Raft-Index: 45325
X-Raft-Term: 2
{
"action": "update",
"node": {
"createdIndex": 1029,
"dir": true,
"expiration": "2016-08-02T07:15:47.970434032Z",
"key": "/dir",
"modifiedIndex": 1033,
"ttl": 5
},
"prevNode": {
"createdIndex": 1029,
"dir": true,
"key": "/dir",
"modifiedIndex": 1029
}
}
目錄在過期的時候,會被自動刪除,包括它裏面所有的子目錄和 key。所有監聽這個目錄中內容的客戶端,都會收到對應的事件。
10.比較更新的原子操作
在分佈式環境中,我們需要解決多個客戶端的競爭問題,etcd 提供了原子操作 CompareAndSwap
(CAS),通過這個操作可以很容易實現分佈式鎖。
簡單來說,只有在客戶端提供的條件成立的情況下,這個命令纔會更新對應的值。目前支持的條件包括:
preValue
:檢查 key 之前的值是否和客戶端提供的一致。prevIndex
:檢查 key 之前的modifiedIndex
是否和客戶端提供的一致。prevExist
:檢查 key 是否已經存在。如果存在就執行更新操作,如果不存在,執行 create 操作。
舉個例子,比如目前 /foo
的值爲 bar
,要把它更新成 changed
,可以使用:
➜ http PUT http://127.0.0.1:2379/v2/keys/foo prevValue==bar value==changed
HTTP/1.1 200 OK
Content-Length: 190
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:37:05 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1036
X-Raft-Index: 47893
X-Raft-Term: 2
{
"action": "compareAndSwap",
"node": {
"createdIndex": 1035,
"key": "/foo",
"modifiedIndex": 1036,
"value": "changed"
},
"prevNode": {
"createdIndex": 1035,
"key": "/foo",
"modifiedIndex": 1035,
"value": "bar"
}
}
如果提供的條件不對,會報 412
錯誤:
➜ http PUT http://127.0.0.1:2379/v2/keys/foo prevValue==bar value==new
HTTP/1.1 412 Precondition Failed
Content-Length: 85
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:37:38 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1036
{
"cause": "[bar != changed]",
"errorCode": 101,
"index": 1036,
"message": "Compare failed"
}
注意:匹配條件是 prevIndex=0
的話,也會通過檢查。
這些條件也可以組合起來使用,只有當都滿足的時候,纔會執行對應的操作。
11.比較刪除的原子操作
和條件更新類似,etcd 也支持條件刪除操作:只有在客戶端提供的條件成立的情況下,纔會執行刪除操作。支持 prevValue
和 prevIndex
兩種條件檢查,沒有 prevExist
,因爲刪除不存在的值本身就會報錯。
我們來刪除上面例子中更新的 /foo
,先看一下提供的條件不對的情況:
➜ http DELETE http://127.0.0.1:2379/v2/keys/foo prevValue==bar
HTTP/1.1 412 Precondition Failed
Content-Length: 85
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:49:13 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1043
{
"cause": "[bar != changed]",
"errorCode": 101,
"index": 1043,
"message": "Compare failed"
}
如果提供的條件成立,對應的 key 就會被刪除:
➜ http DELETE http://127.0.0.1:2379/v2/keys/foo prevValue==changed
HTTP/1.1 200 OK
Content-Length: 178
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:51:27 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1044
X-Raft-Index: 49629
X-Raft-Term: 2
{
"action": "compareAndDelete",
"node": {
"createdIndex": 1043,
"key": "/foo",
"modifiedIndex": 1044
},
"prevNode": {
"createdIndex": 1043,
"key": "/foo",
"modifiedIndex": 1043,
"value": "changed"
}
}
12.操作目錄
12.1 創建操作目錄
在創建 key 的時候,如果它所在路徑的目錄不存在,會自動被創建。所以,在多數情況下,我們不需要關心目錄的創建。目錄的操作和 key 的操作基本一致,唯一的區別是:需要加上 dir=true
參數,指明操作的對象是目錄。
比如,如果想要顯示地創建目錄,可以使用 PUT
方法,並設置 dir=true
:
➜ http PUT http://127.0.0.1:2379/v2/keys/anotherdir dir==true
HTTP/1.1 201 Created
Content-Length: 98
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:53:48 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1045
X-Raft-Index: 49914
X-Raft-Term: 2
{
"action": "set",
"node": {
"createdIndex": 1045,
"dir": true,
"key": "/anotherdir",
"modifiedIndex": 1045
}
}
創建目錄的操作不能重複執行,否則會報 HTTP 403
錯誤。
12.2 列出單個節點或目錄下所有節點的信息
如果 GET
方法對應的 url 是目錄的話,etcd 會列出該目錄所有節點的信息(不需要指定 dir=true
)。例如,要列出根目錄下所有的節點:
➜ http http://127.0.0.1:2379/v2/keys/
HTTP/1.1 200 OK
Content-Length: 190
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:55:41 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1045
X-Raft-Index: 50141
X-Raft-Term: 2
{
"action": "get",
"node": {
"dir": true,
"nodes": [
{
"createdIndex": 1045,
"dir": true,
"key": "/anotherdir",
"modifiedIndex": 1045
},
{
"createdIndex": 1030,
"dir": true,
"key": "/queue",
"modifiedIndex": 1030
}
]
}
}
12.3 遞歸列出目錄下所有的值
如果要遞歸列出所有的值,只需添加上 recursive=true
參數:
➜ http http://127.0.0.1:2379/v2/keys/\?recursive\=true
HTTP/1.1 200 OK
Content-Length: 482
Content-Type: application/json
Date: Tue, 02 Aug 2016 07:57:48 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1045
X-Raft-Index: 50394
X-Raft-Term: 2
{
"action": "get",
"node": {
"dir": true,
"nodes": [
{
"createdIndex": 1045,
"dir": true,
"key": "/anotherdir",
"modifiedIndex": 1045
},
{
"createdIndex": 1030,
"dir": true,
"key": "/queue",
"modifiedIndex": 1030,
"nodes": [
{
"createdIndex": 1031,
"key": "/queue/00000000000000001031",
"modifiedIndex": 1031,
"value": "job2"
},
{
"createdIndex": 1032,
"key": "/queue/00000000000000001032",
"modifiedIndex": 1032,
"value": "job3"
},
{
"createdIndex": 1030,
"key": "/queue/00000000000000001030",
"modifiedIndex": 1030,
"value": "job1"
}
]
}
]
}
}
12.4 刪除目錄
和 linux 刪除目錄的設計一樣,要區別空目錄和非空目錄。刪除空目錄很簡單,使用 DELETE
方法,並添加上 dir=true
參數,類似於 rmdir。
而對於非空目錄,需要添加上 recursive=true
,類似於 rm -rf
。
➜ http DELETE http://127.0.0.1:2379/v2/keys/queue dir==true
HTTP/1.1 403 Forbidden
Content-Length: 80
Content-Type: application/json
Date: Tue, 02 Aug 2016 08:06:44 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1045
{
"cause": "/queue",
"errorCode": 108,
"index": 1045,
"message": "Directory not empty"
}
➜ http DELETE http://127.0.0.1:2379/v2/keys/queue dir==true recursive==true
HTTP/1.1 200 OK
Content-Length: 176
Content-Type: application/json
Date: Tue, 02 Aug 2016 08:06:48 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
X-Etcd-Index: 1046
X-Raft-Index: 51478
X-Raft-Term: 2
{
"action": "delete",
"node": {
"createdIndex": 1030,
"dir": true,
"key": "/queue",
"modifiedIndex": 1046
},
"prevNode": {
"createdIndex": 1030,
"dir": true,
"key": "/queue",
"modifiedIndex": 1030
}
}
13.成員管理
etcd 在 /v2/members
下保存着集羣中各個成員的信息。
13.1 列表查看各個成員的信息
➜ http http://127.0.0.1:2379/v2/members
HTTP/1.1 200 OK
Content-Length: 133
Content-Type: application/json
Date: Tue, 02 Aug 2016 08:15:56 GMT
X-Etcd-Cluster-Id: cdf818194e3a8c32
{
"members": [
{
"clientURLs": [
"http://localhost:2379"
],
"id": "8e9e05c52164694d",
"name": "default",
"peerURLs": [
"http://localhost:2380"
]
}
]
}
13.2 可以通過 POST
方法添加成員
curl http://10.0.0.10:2379/v2/members -XPOST \
-H "Content-Type: application/json" -d '{"peerURLs":["http://10.0.0.10:2380"]}'
13.3 可以通過 DELETE
方法刪除成員
curl http://10.0.0.10:2379/v2/members/272e204152 -XDELETE
13.4 通過 PUT 更新成員的 peer url
curl http://10.0.0.10:2379/v2/members/272e204152 -XPUT \
-H "Content-Type: application/json" -d '{"peerURLs":["http://10.0.0.10:2380"]}'
14.查看集羣數據信息
etcd 中還保存了集羣的數據信息,包括節點之間的網絡信息、操作的統計信息。
/v2/stats/leader
會返回集羣中 leader 的信息,以及 followers 的基本信息。/v2/stats/self
會返回當前節點的信息。/v2/state/store
:會返回各種命令的統計信息。
15.隱藏的節點
etcd 中節點也可以是默認隱藏的,類似於 linux 中以“.
”開頭的文件或者文件夾,以 _
開頭的節點也是默認隱藏的,不會在列出目錄的時候顯示。只有知道隱藏節點的完整路徑,才能夠訪問它的信息。
二、etcdctl 命令行工具
除了 HTTP API 外,etcd 還提供了 etcdctl
命令行工具和 etcd 服務交互。這個命令行用 go 語言編寫,也是對 HTTP API 的封裝,日常使用起來也更容易。
etcdctl的安裝很簡單,從官網下載二進制文件,放到系統的 PATH 路徑下,就行了。
# 設置一個 key 的值
➜ ./etcdctl set /message "hello, etcd"
hello, etcd
# 獲取 key 的值
➜ ./etcdctl get /message
hello, etcd
# 獲取 key 的值,包含更詳細的元數據
➜ ./etcdctl -o extended get /message
Key: /message
Created-Index: 1073
Modified-Index: 1073
TTL: 0
Index: 1073
hello, etcd
# 獲取不存在 key 的值,會報錯
➜ ./etcdctl get /notexist
Error: 100: Key not found (/notexist) [1048]
# 設置 key 的 ttl,過期後會被自動刪除
➜ ./etcdctl set /tempkey "gone with wind" --ttl 5
gone with wind
➜ ./etcdctl get /tempkey
gone with wind
➜ ./etcdctl get /tempkey
Error: 100: Key not found (/tempkey) [1050]
# 如果 key 的值是 "hello, etcd",就把它替換爲 "goodbye, etcd"
➜ ./etcdctl set --swap-with-value "hello, world" /message "goodbye, etcd"
Error: 101: Compare failed ([hello, world != hello, etcd]) [1050]
➜ ./etcdctl set --swap-with-value "hello, etcd" /message "goodbye, etcd"
goodbye, etcd
# 僅當 key 不存在的時候創建
➜ ./etcdctl mk /foo bar
bar
➜ ./etcdctl mk /foo bar
Error: 105: Key already exists (/foo) [1052]
# 自動創建排序的 key
➜ ./etcdctl mk --in-order /queue job1
job1
➜ ./etcdctl mk --in-order /queue job2
job2
➜ ./etcdctl ls --sort /queue
/queue/00000000000000001053
/queue/00000000000000001054
# 更新 key 的值或者 ttl,只有當 key 已經存在的時候纔會生效,否則報錯
➜ ./etcdctl update /message "I'am changed"
I'am changed
➜ ./etcdctl get /message
I'am changed
➜ ./etcdctl update /notexist "I'am changed"
Error: 100: Key not found (/notexist) [1055]
➜ ./etcdctl update --ttl 3 /message "I'am changed"
I'am changed
➜ ./etcdctl get /message
Error: 100: Key not found (/message) [1057]
# 刪除某個 key
➜ ./etcdctl mk /foo bar
bar
➜ ./etcdctl rm /foo
PrevNode.Value: bar
➜ ./etcdctl get /foo
Error: 100: Key not found (/foo) [1062]
# 只有當 key 的值匹配的時候,才進行刪除
➜ ./etcdctl mk /foo bar
bar
➜ ./etcdctl rm --with-value wrong /foo
Error: 101: Compare failed ([wrong != bar]) [1063]
➜ ./etcdctl rm --with-value bar /foo
# 創建一個目錄
➜ ./etcdctl mkdir /dir
# 刪除空目錄
➜ ./etcdctl mkdir /dir/subdir/
➜ ./etcdctl rmdir /dir/subdir/
# 刪除非空目錄
➜ ./etcdctl rmdir /dir
Error: 108: Directory not empty (/dir) [1071]
➜ ./etcdctl rm --recursive /dir
# 列出目錄的內容
➜ ./etcdctl ls /
/queue
/anotherdir
/message
# 遞歸列出目錄的內容
➜ ./etcdctl ls --recursive /
/anotherdir
/message
/queue
/queue/00000000000000001053
/queue/00000000000000001054
# 監聽某個 key,當 key 改變的時候會打印出變化
➜ ./etcdctl watch /message
changed
# 監聽某個目錄,當目錄中任何 node 改變的時候,都會打印出來
➜ ./etcdctl watch --recursive /
[set] /message
changed
# 一直監聽,除非 `CTL + C` 導致退出監聽
➜ ./etcdctl watch --forever /message
new value
chaned again
Wola
# 監聽目錄,並在發生變化的時候執行一個命令
➜ ./etcdctl exec-watch --recursive / -- sh -c "echo change detected."
change detected.
change detected.