摘要:# 設置一個key值 [root@etcd-0-8 ~]# etcdctl set /msg "hello k8s" hello k8s # 獲取key的值 [root@etcd-0-8 ~]# etcdctl get /msg hello k8s # 獲取key值的詳細信息 [root@etcd-0-8 ~]# etcdctl -o extended get /msg Key: /msg Created-Index: 12 Modified-Index: 12 TTL: 0 Index: 12 hello k8s # 獲取不存在的key回報錯 [root@etcd-0-8 ~]# etcdctl get /xxzx Error: 100: Key not found (/xxzx) [12] # 設置key的ttl,過期後會被自動刪除 [root@etcd-0-8 ~]# etcdctl set /testkey "tmp key test" --ttl 5 tmp key test [root@etcd-0-8 ~]# etcdctl get /testkey Error: 100: Key not found (/testkey) [14] # key 替換操作 [root@etcd-0-8 ~]# etcdctl get /msg hello k8s # [root@etcd-0-8 ~]# etcdctl set --swap-with-value "hello k8s" /msg "goodbye" goodbye [root@etcd-0-8 ~]# etcdctl get /msg goodbye # mk 僅當key不存在時創建(set對同一個key會覆蓋) [root@etcd-0-8 ~]# etcdctl get /msg goodbye [root@etcd-0-8 ~]# etcdctl mk /msg "mktest" Error: 105: Key already exists (/msg) [18] [root@etcd-0-8 ~]# etcdctl mk /msg1 "mktest" mktest # 創建自排序的key [root@etcd-0-8 ~]# etcdctl mk --in-order /queue s1 s1 [root@etcd-0-8 ~]# etcdctl mk --in-order /queue s2 s2 [root@etcd-0-8 ~]# etcdctl ls --sort /queue /queue/00000000000000000021 /queue/00000000000000000022 [root@etcd-0-8 ~]# etcdctl get /queue/00000000000000000021 s1 # 更新key值 [root@etcd-0-8 ~]# etcdctl update /msg1 "update test" update test [root@etcd-0-8 ~]# etcdctl get /msg1 update test # 更新key的ttl及值 [root@etcd-0-8 ~]# etcdctl update --ttl 5 /msg "aaa" aaa # 創建目錄 [root@etcd-0-8 ~]# etcdctl mkdir /testdir 刪除空目錄 [root@etcd-0-8 ~]# etcdctl mkdir /test1 [root@etcd-0-8 ~]# etcdctl rmdir /test1 刪除非空目錄 [root@etcd-0-8 ~]# etcdctl get /testdir /testdir: is a directory [root@etcd-0-8 ~]# etcdctl rm --recursive /testdir # 列出目錄內容 [root@etcd-0-8 ~]# etcdctl ls / /tmp /msg1 /queue [root@etcd-0-8 ~]# etcdctl ls /tmp /tmp/a /tmp/b # 遞歸列出目錄的內容 [root@etcd-0-8 ~]# etcdctl ls --recursive / /msg1 /queue /queue/00000000000000000021 /queue/00000000000000000022 /tmp /tmp/b /tmp/a # 監聽key,當key發生改變的時候打印出變化 [root@etcd-0-8 ~]# etcdctl watch /msg1 xxx [root@VM_0_17_centos ~]# etcdctl update /msg1 "xxx" xxx # 監聽某個目錄,當目錄中任何 node 改變的時候,都會打印出來 [root@etcd-0-8 ~]# etcdctl watch --recursive / [update] /msg1 xxx [root@VM_0_17_centos ~]# etcdctl update /msg1 "xxx" xxx # 一直監聽,除非 `CTL + C` 導致退出監聽 [root@etcd-0-8 ~]# etcdctl watch --forever / # 監聽目錄,當發生變化時執行一條命令 [root@etcd-0-8 ~]# etcdctl exec-watch --recursive / -- sh -c "echo change" change backup [root@etcd-0-14 ~]# etcdctl backup --data-dir /data/app/etcd --backup-dir /root/etcd_backup 2019-12-04 10:25:16.113237 I | ignoring EntryConfChange raft entry 2019-12-04 10:25:16.113268 I | ignoring EntryConfChange raft entry 2019-12-04 10:25:16.113272 I | ignoring EntryConfChange raft entry 2019-12-04 10:25:16.113293 I | ignoring member attribute update on /0/members/2d2e457c6a1a76cb/attributes 2019-12-04 10:25:16.113299 I | ignoring member attribute update on /0/members/d2d2e9fc758e6790/attributes 2019-12-04 10:25:16.113305 I | ignoring member attribute update on /0/members/56e0b6dad4c53d42/attributes 2019-12-04 10:25:16.113310 I | ignoring member attribute update on /0/members/56e0b6dad4c53d42/attributes 2019-12-04 10:25:16.113314 I | ignoring member attribute update on /0/members/2d2e457c6a1a76cb/attributes 2019-12-04 10:25:16.113319 I | ignoring member attribute update on /0/members/d2d2e9fc758e6790/attributes 2019-12-04 10:25:16.113384 I | ignoring member attribute update on /0/members/56e0b6dad4c53d42/attributes # 使用v3版本 [root@etcd-0-14 ~]# export ETCDCTL_API=3 [root@etcd-0-14 ~]# etcdctl --endpoints="http://172.16.0.8:2379,http://172.16.0.14:2379,http://172.16.0.17:2379" snapshot save mysnapshot.db Snapshot saved at mysnapshot.db [root@etcd-0-14 ~]# etcdctl snapshot status mysnapshot.db -w json {"hash":928285884,"revision":0,"totalKey":5,"totalSize":20480}。[root@etcd-0-8 app]# cat /etc/etcd/etcd.conf [Member] ETCD_CORS="" ETCD_DATA_DIR="/data/app/etcd/" # etcd數據存儲目錄,建議存儲在數據盤 ETCD_WAL_DIR="" ETCD_LISTEN_PEER_URLS="http://172.16.0.8:2380" # 與同伴的通訊地址,和其他節點同伴的通訊地址 ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.8:2379" # 對外提供服務的地址 ETCD_MAX_SNAPSHOTS="5" #ETCD_MAX_WALS="5" ETCD_NAME="etcd-0-8" # etcd節點名稱,集羣內需要唯一 #ETCD_SNAPSHOT_COUNT="100000" #ETCD_HEARTBEAT_INTERVAL="100" #ETCD_ELECTION_TIMEOUT="1000" #ETCD_QUOTA_BACKEND_BYTES="0" ETCD_MAX_REQUEST_BYTES="1572864" ETCD_GRPC_KEEPALIVE_MIN_TIME="5s" ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s" ETCD_GRPC_KEEPALIVE_TIMEOUT="20s" [Clustering] ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.0.8:2380" # 該節點同伴監聽地址,這個值會告訴集羣中其他節點 ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.8:2379" # 對外公告的該節點客戶端監聽地址,這個值會告訴集羣中其他節點 ETCD_DISCOVERY="" ETCD_DISCOVERY_FALLBACK="proxy" ETCD_DISCOVERY_PROXY="" ETCD_DISCOVERY_SRV="" ETCD_INITIAL_CLUSTER="etcd-0-8=http://172.16.0.8:2380,etcd-0-17=http://172.16.0.17:2380,etcd-0-14=http://172.16.0.14:2380" # 集羣中所有節點的信 ETCD_INITIAL_CLUSTER_TOKEN="etcd-token" # 創建集羣的 token,這個值每個集羣保持唯一。

背景:近期k8s應用中etcd的功能存在一些困惑,對其進行來單獨的學習,能更深入理解k8s中的的一些特性。

1.1 etcd簡介

etcd是CoreOS團隊於2013年6月發起的開源項目,它的目標是構建一個高可用的分佈式鍵值(key-value)數據庫。etcd內部採用 raft 協議作爲一致性算法,etcd基於Go語言實現。

1.2 發展歷史

1.3 etcd的特點

  • 簡單:安裝配置簡單,而且提供了HTTP API進行交互,使用也很簡單
  • 安全:支持SSL證書驗證
  • 快速:根據官方提供的benchmark數據,單實例支持每秒2k+讀操作
  • 可靠:採用raft算法,實現分佈式系統數據的可用性和一致性

1.4 概念術語

  • Raft:etcd所採用的保證分佈式系統強一致性的算法。

  • Node:一個Raft狀態機實例。

  • Member: 一個etcd實例。它管理着一個Node,並且可以爲客戶端請求提供服務。

  • Cluster:由多個Member構成可以協同工作的etcd集羣。

  • Peer:對同一個etcd集羣中另外一個Member的稱呼。

  • Client: 向etcd集羣發送HTTP請求的客戶端。

  • WAL:預寫式日誌,etcd用於持久化存儲的日誌格式。

  • snapshot:etcd防止WAL文件過多而設置的快照,存儲etcd數據狀態。

  • Proxy:etcd的一種模式,爲etcd集羣提供反向代理服務。

  • Leader:Raft算法中通過競選而產生的處理所有數據提交的節點。

  • Follower:競選失敗的節點作爲Raft中的從屬節點,爲算法提供強一致性保證。

  • Candidate:當Follower超過一定時間接收不到Leader的心跳時轉變爲Candidate開始競選。

  • Term:某個節點成爲Leader到下一次競選時間,稱爲一個Term。

  • Index:數據項編號。Raft中通過Term和Index來定位數據。

1.5 數據讀寫順序

爲了保證數據的強一致性,etcd集羣中所有的數據流向都是一個方向,從 Leader (主節點)流向 Follower,也就是所有 Follower 的數據必須與 Leader 保持一致,如果不一致會被覆蓋。

用戶對於etcd集羣所有節點進行讀寫

  • 讀取:由於集羣所有節點數據是強一致性的,讀取可以從集羣中隨便哪個節點進行讀取數據
  • 寫入:etcd集羣有leader,如果寫入往leader寫入,可以直接寫入,然後然後Leader節點會把寫入分發給所有Follower,如果往follower寫入,然後Leader節點會把寫入分發給所有Follower

1.6 leader選舉

假設三個節點的集羣,三個節點上均運行Timer(每個Timer持續時間是隨機的),Raft算法使用隨機Timer來初始化Leader選舉流程,第一個節點率先完成了Timer,隨後它就會向其他兩個節點發送成爲Leader的請求,其他節點接收到請求後會以投票回應然後第一個節點被選舉爲Leader。

成爲Leader後,該節點會以固定時間間隔向其他節點發送通知,確保自己仍是Leader。有些情況下當Follower們收不到Leader的通知後,比如說Leader節點宕機或者失去了連接,其他節點會重複之前選舉過程選舉出新的Leader。

1.7 判斷數據是否寫入

etcd認爲寫入請求被Leader節點處理並分發給了多數節點後,就是一個成功的寫入。那麼多少節點如何判定呢,假設總結點數是N,那麼多數節點 Quorum=N/2+1 。關於如何確定etcd集羣應該有多少個節點的問題,上圖的左側的圖表給出了集羣中節點總數(Instances)對應的Quorum數量,用Instances減去Quorom就是集羣中容錯節點(允許出故障的節點)的數量。

所以在集羣中推薦的最少節點數量是3個,因爲1和2個節點的容錯節點數都是0,一旦有一個節點宕掉整個集羣就不能正常工作了。

二 etcd架構及解析

2.1 架構圖

2.2 架構解析

從 etcd 的架構圖中我們可以看到,etcd 主要分爲四個部分。

  • HTTP Server:用於處理用戶發送的 API 請求以及其它 etcd 節點的同步與心跳信息請求。
  • Store:用於處理 etcd 支持的各類功能的事務,包括數據索引、節點狀態變更、監控與反饋、事件處理與執行等等,是 etcd 對用戶提供的大多數 API 功能的具體實現。
  • Raft:Raft 強一致性算法的具體實現,是 etcd 的核心。
  • WAL:Write Ahead Log(預寫式日誌),是 etcd 的數據存儲方式。除了在內存中存有所有數據的狀態以及節點的索引以外,etcd 就通過 WAL 進行持久化存儲。WAL 中,所有的數據提交前都會事先記錄日誌。
    • Snapshot 是爲了防止數據過多而進行的狀態快照;
    • Entry 表示存儲的具體日誌內容。

通常,一個用戶的請求發送過來,會經由 HTTP Server 轉發給 Store 進行具體的事務處理,如果涉及到節點的修改,則交給 Raft 模塊進行狀態的變更、日誌的記錄,然後再同步給別的 etcd 節點以確認數據提交,最後進行數據的提交,再次同步。

三 應用場景

3.1 服務註冊與發現

etcd可以用於服務的註冊與發現

中間價已經後端服務在etcd中註冊,前端和中間價可以很輕鬆的從etcd中發現相關服務器然後服務器之間根據調用關係相關綁定調用

後端多個無狀態相同副本的app可以同事註冊到etcd中,前端可以通過haproxy從etcd中獲取到後端的ip和端口組,然後進行請求轉發,可以用來故障轉移屏蔽後端端口已經後端多組app實例。

3.2 消息發佈與訂閱

etcd可以充當消息中間件,生產者可以往etcd中註冊topic併發送消息,消費者從etcd中訂閱topic,來獲取生產者發送至etcd中的消息。

3.3 負載均衡

後端多組相同的服務提供者可以經自己服務註冊到etcd中,etcd並且會與註冊的服務進行監控檢查,服務請求這首先從etcd中獲取到可用的服務提供者真正的ip:port,然後對此多組服務發送請求,etcd在其中充當了負載均衡的功能

3.4 分部署通知與協調

  • 當etcd watch服務發現丟失,會通知服務檢查
  • 控制器向etcd發送啓動服務,etcd通知服務進行相應操作
  • 當服務完成work會講狀態更新至etcd,etcd對應會通知用戶

3.5 分佈式鎖

當有多個競爭者node節點,etcd作爲總控,在分佈式集羣中與一個節點成功分配lock

3.6 分佈式隊列

有對個node,etcd根據每個node來創建對應node的隊列,根據不同的隊列可以在etcd中找到對應的competitor

3.7 集羣與監控與Leader選舉

etcd可以根據raft算法在多個node節點來選舉出leader

四 安裝部署

4.1 單機部署

可以使用二進制或源碼下載安裝,但是危害需要自己寫配置文件,如何要啓動需要自己寫服務啓動文件,推薦使用yum安裝方式

hostnamectl set-hostname etcd-1
wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
 yum 倉庫中的etcd版本爲3.3.11,如果需要最新版本的etcd可以進行二進制安裝
yum -y install etcd
systemctl enable etcd

可以查看yum安裝的etcd的有效配置文件,根據自己的需求來修改數據存儲目錄,已經監聽端口url/etcd的名稱等

  • etcd 默認將數據存放到當前路徑的 default.etcd/ 目錄下
  • http://localhost:2380 和集羣中其他節點通信
  • http://localhost:2379 提供 HTTP API 服務,供客戶端交互
  • 該節點的名稱默認爲 default
    • heartbeat 爲 100ms,後面會說明這個配置的作用
  • election 爲 1000ms,後面會說明這個配置的作用
  • snapshot count 爲 10000,後面會說明這個配置的作用
  • 集羣和每個節點都會生成一個 uuid
  • 啓動的時候,會運行 raft,選舉出 leader
[root@VM_0_8_centos tmp]# grep -Ev "^#|^$" /etc/etcd/etcd.conf

ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379"
ETCD_NAME="default"
ETCD_ADVERTISE_CLIENT_URLS="http://localhost:2379"
[root@VM_0_8_centos tmp]# systemctl status etcd

4.2 集羣部署

集羣部署最好部署奇數位,此能達到最好的集羣容錯

4.2.1 主機信息

主機名稱 系統 IP地址 部署組件
etcd-0-8 CentOS 7.3 172.16.0.8 etcd
etcd-0-17 CentOS 7.3 172.16.0.17 etcd
etcd-0-14 CentOS 7.3 172.16.0.14 etcd

4.2.2 host配置

在此示例用三個節點來部署etcd集羣,各節點修改hosts

cat >> /etc/hosts << EOF
172.16.0.8 etcd-0-8
172.16.0.14 etcd-0-14
172.16.0.17 etcd-0-17
EOF

4.2.3 etcd安裝

三個節點均安裝etcd

wget http://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
rpm -ivh epel-release-latest-7.noarch.rpm
yum -y install etcd
systemctl enable etcd
mkdir -p /data/app/etcd/
chown etcd:etcd /data/app/etcd/

4.2.4 etcd配置

[root@etcd-0-8 app]# cat /etc/etcd/etcd.conf
[Member]
ETCD_CORS=""
ETCD_DATA_DIR="/data/app/etcd/"																						# etcd數據存儲目錄,建議存儲在數據盤
ETCD_WAL_DIR=""
ETCD_LISTEN_PEER_URLS="http://172.16.0.8:2380"														# 與同伴的通訊地址,和其他節點同伴的通訊地址	
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.8:2379"		# 對外提供服務的地址
ETCD_MAX_SNAPSHOTS="5"																										
#ETCD_MAX_WALS="5"																												
ETCD_NAME="etcd-0-8"																											# etcd節點名稱,集羣內需要唯一
#ETCD_SNAPSHOT_COUNT="100000"													      
#ETCD_HEARTBEAT_INTERVAL="100"															
#ETCD_ELECTION_TIMEOUT="1000"			                          
#ETCD_QUOTA_BACKEND_BYTES="0"
ETCD_MAX_REQUEST_BYTES="1572864"
ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"

[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.0.8:2380"									   # 該節點同伴監聽地址,這個值會告訴集羣中其他節點
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.8:2379"    # 對外公告的該節點客戶端監聽地址,這個值會告訴集羣中其他節點
ETCD_DISCOVERY=""
ETCD_DISCOVERY_FALLBACK="proxy"
ETCD_DISCOVERY_PROXY=""
ETCD_DISCOVERY_SRV=""
ETCD_INITIAL_CLUSTER="etcd-0-8=http://172.16.0.8:2380,etcd-0-17=http://172.16.0.17:2380,etcd-0-14=http://172.16.0.14:2380"													# 集羣中所有節點的信	
ETCD_INITIAL_CLUSTER_TOKEN="etcd-token"							 # 創建集羣的 token,這個值每個集羣保持唯一。這樣的話,如果你要重新創建集羣,即使配置和之前一樣,也會再次生成新的集羣和節點 uuid;否則會導致多個集羣之間的衝突,造成未知的錯誤
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_STRICT_RECONFIG_CHECK="true"									 
#ETCD_ENABLE_V2="true"

[Proxy]
ETCD_PROXY="off"
ETCD_PROXY_FAILURE_WAIT="5000"
ETCD_PROXY_REFRESH_INTERVAL="30000"
ETCD_PROXY_DIAL_TIMEOUT="1000"
ETCD_PROXY_WRITE_TIMEOUT="5000"
ETCD_PROXY_READ_TIMEOUT="0"

[Security]
ETCD_CERT_FILE=""
ETCD_KEY_FILE=""
ETCD_CLIENT_CERT_AUTH="false"
ETCD_TRUSTED_CA_FILE=""
ETCD_AUTO_TLS="false"
ETCD_PEER_CERT_FILE=""
ETCD_PEER_KEY_FILE=""
ETCD_PEER_CLIENT_CERT_AUTH="false"
ETCD_PEER_TRUSTED_CA_FILE=""
ETCD_PEER_AUTO_TLS="false"

[Logging]
ETCD_DEBUG="false"
ETCD_LOG_PACKAGE_LEVELS=""
ETCD_LOG_OUTPUT="default"

[Unsafe]
ETCD_FORCE_NEW_CLUSTER="false"

[Version]
ETCD_VERSION="false"
ETCD_AUTO_COMPACTION_RETENTION="0"

[Profiling]
ETCD_ENABLE_PPROF="false"
ETCD_METRICS="basic"

[Auth]
ETCD_AUTH_TOKEN="simple"

etcd-0-8配置:

[root@etcd-server ~]# hostnamectl set-hostname etcd-0-8
[root@etcd-0-8 ~]# egrep "^#|^$" /etc/etcd/etcd.conf -v
ETCD_DATA_DIR="/data/app/etcd/"
ETCD_LISTEN_PEER_URLS="http://172.16.0.8:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.8:2379"
ETCD_NAME="etcd-0-8"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.0.8:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.8:2379"
ETCD_INITIAL_CLUSTER="etcd-0-8=http://172.16.0.8:2380,etcd-0-17=http://172.16.0.17:2380,etcd-0-14=http://172.16.0.14:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-token"
ETCD_INITIAL_CLUSTER_STATE="new"

etcd-0-14配置:

[root@etcd-server ~]# hostnamectl set-hostname etcd-0-14
[root@etcd-server ~]# mkdir -p /data/app/etcd/
[[email protected] ~]# egrep "^#|^$" /etc/etcd/etcd.conf -v
ETCD_DATA_DIR="/data/app/etcd/"
ETCD_LISTEN_PEER_URLS="http://172.16.0.14:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.14:2379"
ETCD_NAME="etcd-0-14"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.0.14:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.14:2379"
ETCD_INITIAL_CLUSTER="etcd-0-8=http://172.16.0.8:2380,etcd-0-17=http://172.16.0.17:2380,etcd-0-14=http://172.16.0.14:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-token"
ETCD_INITIAL_CLUSTER_STATE="new"
[root@etcd-server ~]# hostnamectl set-hostname etcd-0-17
[root@etcd-server ~]# mkdir -p /data/app/etcd/
[root@etcd-0-17 ~]# egrep "^#|^$" /etc/etcd/etcd.conf -v
ETCD_DATA_DIR="/data/app/etcd/"
ETCD_LISTEN_PEER_URLS="http://172.16.0.17:2380"
ETCD_LISTEN_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.17:2379"
ETCD_NAME="etcd-0-17"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://172.16.0.17:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://127.0.0.1:2379,http://172.16.0.17:2379"
ETCD_INITIAL_CLUSTER="etcd-0-8=http://172.16.0.8:2380,etcd-0-17=http://172.16.0.17:2380,etcd-0-14=http://172.16.0.14:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-token"
ETCD_INITIAL_CLUSTER_STATE="new"
systemctl start etcd

4.2.5 查看集羣狀態

[root@etcd-0-8 default.etcd]# systemctl status etcd
● etcd.service - Etcd Server
   Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; vendor preset: disabled)
   Active: active (running) since 二 2019-12-03 15:55:28 CST; 8s ago
 Main PID: 24510 (etcd)
   CGroup: /system.slice/etcd.service
           └─24510 /usr/bin/etcd --name=etcd-0-8 --data-dir=/data/app/etcd/ --listen-client-urls=http://172.16.0.8:2379

12月 03 15:55:28 etcd-0-8 etcd[24510]: set the initial cluster version to 3.0
12月 03 15:55:28 etcd-0-8 etcd[24510]: enabled capabilities for version 3.0
12月 03 15:55:30 etcd-0-8 etcd[24510]: peer 56e0b6dad4c53d42 became active
12月 03 15:55:30 etcd-0-8 etcd[24510]: established a TCP streaming connection with peer 56e0b6dad4c53d42 (stream Message reader)
12月 03 15:55:30 etcd-0-8 etcd[24510]: established a TCP streaming connection with peer 56e0b6dad4c53d42 (stream Message writer)
12月 03 15:55:30 etcd-0-8 etcd[24510]: established a TCP streaming connection with peer 56e0b6dad4c53d42 (stream MsgApp v2 reader)
12月 03 15:55:30 etcd-0-8 etcd[24510]: established a TCP streaming connection with peer 56e0b6dad4c53d42 (stream MsgApp v2 writer)
12月 03 15:55:32 etcd-0-8 etcd[24510]: updating the cluster version from 3.0 to 3.3
12月 03 15:55:32 etcd-0-8 etcd[24510]: updated the cluster version from 3.0 to 3.3
12月 03 15:55:32 etcd-0-8 etcd[24510]: enabled capabilities for version 3.3
  • 查看端口監聽(如果未在本地監聽環回地址,那麼在本地使用etcdctl不能正常連入進去)
[root@etcd-0-8 default.etcd]# netstat -lntup |grep etcd
tcp        0      0 172.16.0.8:2379         0.0.0.0:*               LISTEN      25167/etcd
tcp        0      0 127.0.0.1:2379          0.0.0.0:*               LISTEN      25167/etcd
tcp        0      0 172.16.0.8:2380         0.0.0.0:*               LISTEN      25167/etcd
[root@etcd-0-8 default.etcd]# etcdctl member list
2d2e457c6a1a76cb: name=etcd-0-8 peerURLs=http://172.16.0.8:2380 clientURLs=http://127.0.0.1:2379,http://172.16.0.8:2379 isLeader=false
56e0b6dad4c53d42: name=etcd-0-14 peerURLs=http://172.16.0.14:2380 clientURLs=http://127.0.0.1:2379,http://172.16.0.14:2379 isLeader=true
d2d2e9fc758e6790: name=etcd-0-17 peerURLs=http://172.16.0.17:2380 clientURLs=http://127.0.0.1:2379,http://172.16.0.17:2379 isLeader=false

[root@etcd-0-8 ~]# etcdctl cluster-health
member 2d2e457c6a1a76cb is healthy: got healthy result from http://127.0.0.1:2379
member 56e0b6dad4c53d42 is healthy: got healthy result from http://127.0.0.1:2379
member d2d2e9fc758e6790 is healthy: got healthy result from http://127.0.0.1:2379
cluster is healthy

五 簡單使用

5.1 增加

指定某個鍵的值。例如:

$ etcdctl set /testdir/testkey "Hello world"
Hello world

支持的選項包括:

--ttl '0' 該鍵值的超時時間(單位爲秒),不配置(默認爲0)則永不超時
--swap-with-value value 若該鍵現在的值是value,則進行設置操作
--swap-with-index '0'   若該鍵現在的索引值是指定索引,則進行設置操作

如果給定的鍵不存在,則創建一個新的鍵值。例如:

$ etcdctl mk /testdir/testkey "Hello world"
Hello world

當鍵存在的時候,執行該命令會報錯,例如:

$ etcdctl mk /testdir/testkey "Hello world"
Error:  105: Key already exists (/testdir/testkey) [8]

支持的選項爲:

--ttl '0'  超時時間(單位爲秒),不配置(默認爲 0)。則永不超時

如果給定的鍵目錄不存在,則創建一個新的鍵目錄。例如:

$ etcdctl mkdir testdir2

當鍵目錄存在的時候,執行該命令會報錯,例如:

$ etcdctl mkdir testdir2
Error:  105: Key already exists (/testdir2) [9]

支持的選項爲:

--ttl '0' 超時時間(單位爲秒),不配置(默認爲0)則永不超時。

創建一個鍵目錄。如果目錄不存在就創建,如果目錄存在更新目錄TTL。

$ etcdctl setdir testdir3

支持的選項爲:

--ttl '0' 超時時間(單位爲秒),不配置(默認爲0)則永不超時。

5.2 刪除

刪除某個鍵值。例如:

$ etcdctl rm /testdir/testkey
PrevNode.Value: Hello

當鍵不存在時,則會報錯。例如:

$ etcdctl rm /testdir/testkey
Error:  100: Key not found (/testdir/testkey) [7]

支持的選項爲:

--dir 如果鍵是個空目錄或者鍵值對則刪除
--recursive 刪除目錄和所有子鍵
--with-value  檢查現有的值是否匹配
--with-index '0'檢查現有的index是否匹配

刪除一個空目錄,或者鍵值對。

$ etcdctl setdir dir1
$ etcdctl rmdir dir1

若目錄不空,會報錯:

$ etcdctl set /dir/testkey hi
hi
$ etcdctl rmdir /dir
Error:  108: Directory not empty (/dir) [17]

5.3 更新

當鍵存在時,更新值內容。例如:

$ etcdctl update /testdir/testkey "Hello"
Hello

當鍵不存在時,則會報錯。例如:

$ etcdctl update /testdir/testkey2 "Hello"
Error:  100: Key not found (/testdir/testkey2) [6]

支持的選項爲:

--ttl '0' 超時時間(單位爲秒),不配置(默認爲 0)則永不超時。

更新一個已經存在的目錄。

$ etcdctl updatedir testdir2

支持的選項爲:

--ttl '0' 超時時間(單位爲秒),不配置(默認爲0)則永不超時。

5.4 查詢

獲取指定鍵的值。例如:

$ etcdctl get /testdir/testkey
Hello world

當鍵不存在時,則會報錯。例如:

$ etcdctl get /testdir/testkey2
Error:  100: Key not found (/testdir/testkey2) [5]

支持的選項爲:

--sort 對結果進行排序
--consistent 將請求發給主節點,保證獲取內容的一致性。

列出目錄(默認爲根目錄)下的鍵或者子目錄,默認不顯示子目錄中內容。

例如:

$ etcdctl ls
/testdir
/testdir2
/dir

$ etcdctl ls dir
/dir/testkey

支持的選項包括:

--sort 將輸出結果排序
--recursive 如果目錄下有子目錄,則遞歸輸出其中的內容
-p 對於輸出爲目錄,在最後添加/進行區分

5.5 watch

監測一個鍵值的變化,一旦鍵值發生更新,就會輸出最新的值並退出。

例如:用戶更新testkey鍵值爲Hello watch。

$ etcdctl get /testdir/testkey
Hello world
$ etcdctl set /testdir/testkey "Hello watch"
Hello watch
$ etcdctl watch testdir/testkey
Hello watch

支持的選項包括:

--forever  一直監測直到用戶按CTRL+C退出
--after-index '0' 在指定index之前一直監測
--recursive 返回所有的鍵值和子鍵值

監測一個鍵值的變化,一旦鍵值發生更新,就執行給定命令。

例如:用戶更新testkey鍵值。

$ etcdctl exec-watch testdir/testkey -- sh -c 'ls'
config	Documentation  etcd  etcdctl  README-etcdctl.md  README.md  READMEv2-etcdctl.md

支持的選項包括:

--after-index '0' 在指定 index 之前一直監測
--recursive 返回所有的鍵值和子鍵值

5.6 備份

備份etcd的數據。

$ etcdctl backup --data-dir /var/lib/etcd  --backup-dir /home/etcd_backup

支持的選項包括:

--data-dir  etcd的數據目錄
--backup-dir 備份到指定路徑

5.7 member

通過 listaddremove 命令列出、添加、刪除etcd實例到etcd集羣中。

查看集羣中存在的節點

$ etcdctl member list
8e9e05c52164694d: name=dev-master-01 peerURLs=http://localhost:2380 clientURLs=http://localhost:2379 isLeader=true

刪除集羣中存在的節點

$ etcdctl member remove 8e9e05c52164694d
Removed member 8e9e05c52164694d from cluster

向集羣中新加節點

$ etcdctl member add etcd3 http://192.168.1.100:2380
Added member named etcd3 with ID 8e9e05c52164694d to cluster

示例:

# 設置一個key值
[root@etcd-0-8 ~]# etcdctl set /msg "hello k8s"

hello k8s
 
# 獲取key的值
[root@etcd-0-8 ~]# etcdctl get /msg
hello k8s

# 獲取key值的詳細信息
[root@etcd-0-8 ~]# etcdctl -o extended get /msg

Key: /msg
Created-Index: 12
Modified-Index: 12
TTL: 0
Index: 12
hello k8s

# 獲取不存在的key回報錯
[root@etcd-0-8 ~]# etcdctl get /xxzx

Error:  100: Key not found (/xxzx) [12]

# 設置key的ttl,過期後會被自動刪除
[root@etcd-0-8 ~]# etcdctl set /testkey "tmp key test" --ttl 5

tmp key test

[root@etcd-0-8 ~]# etcdctl get /testkey

Error:  100: Key not found (/testkey) [14]
 
# key 替換操作
[root@etcd-0-8 ~]# etcdctl get /msg
hello k8s

# [root@etcd-0-8 ~]# etcdctl set --swap-with-value "hello k8s" /msg "goodbye"

goodbye

[root@etcd-0-8 ~]# etcdctl get /msg
goodbye

# mk 僅當key不存在時創建(set對同一個key會覆蓋)
[root@etcd-0-8 ~]# etcdctl get /msg
goodbye

[root@etcd-0-8 ~]# etcdctl mk /msg "mktest"
Error:  105: Key already exists (/msg) [18]

[root@etcd-0-8 ~]# etcdctl mk /msg1 "mktest"
mktest

# 創建自排序的key
[root@etcd-0-8 ~]# etcdctl mk --in-order /queue s1
s1

[root@etcd-0-8 ~]# etcdctl mk --in-order /queue s2
s2

[root@etcd-0-8 ~]# etcdctl ls --sort /queue
/queue/00000000000000000021
/queue/00000000000000000022

[root@etcd-0-8 ~]# etcdctl get /queue/00000000000000000021
s1

# 更新key值
[root@etcd-0-8 ~]# etcdctl update /msg1 "update test"
update test

[root@etcd-0-8 ~]# etcdctl get /msg1
update test

# 更新key的ttl及值
[root@etcd-0-8 ~]# etcdctl update --ttl 5 /msg "aaa"
aaa

# 創建目錄
[root@etcd-0-8 ~]# etcdctl mkdir /testdir
 刪除空目錄

[root@etcd-0-8 ~]# etcdctl mkdir /test1
[root@etcd-0-8 ~]# etcdctl rmdir /test1
 刪除非空目錄

[root@etcd-0-8 ~]# etcdctl get /testdir
/testdir: is a directory

[root@etcd-0-8 ~]# etcdctl rm --recursive /testdir

# 列出目錄內容
[root@etcd-0-8 ~]# etcdctl ls /
/tmp
/msg1
/queue

[root@etcd-0-8 ~]# etcdctl ls /tmp
/tmp/a
/tmp/b

# 遞歸列出目錄的內容
[root@etcd-0-8 ~]# etcdctl ls --recursive /
/msg1
/queue
/queue/00000000000000000021
/queue/00000000000000000022
/tmp
/tmp/b
/tmp/a

# 監聽key,當key發生改變的時候打印出變化
[root@etcd-0-8 ~]# etcdctl watch /msg1
xxx

[root@VM_0_17_centos ~]# etcdctl update /msg1 "xxx"
xxx

# 監聽某個目錄,當目錄中任何 node 改變的時候,都會打印出來
[root@etcd-0-8 ~]# etcdctl watch --recursive /
[update] /msg1
xxx

[root@VM_0_17_centos ~]# etcdctl update /msg1 "xxx"
xxx

# 一直監聽,除非 `CTL + C` 導致退出監聽
[root@etcd-0-8 ~]# etcdctl watch --forever /
 
# 監聽目錄,當發生變化時執行一條命令
[root@etcd-0-8 ~]# etcdctl exec-watch --recursive / -- sh -c "echo change"
change
 backup

[root@etcd-0-14 ~]# etcdctl backup --data-dir /data/app/etcd --backup-dir /root/etcd_backup
2019-12-04 10:25:16.113237 I | ignoring EntryConfChange raft entry
2019-12-04 10:25:16.113268 I | ignoring EntryConfChange raft entry
2019-12-04 10:25:16.113272 I | ignoring EntryConfChange raft entry
2019-12-04 10:25:16.113293 I | ignoring member attribute update on /0/members/2d2e457c6a1a76cb/attributes
2019-12-04 10:25:16.113299 I | ignoring member attribute update on /0/members/d2d2e9fc758e6790/attributes
2019-12-04 10:25:16.113305 I | ignoring member attribute update on /0/members/56e0b6dad4c53d42/attributes
2019-12-04 10:25:16.113310 I | ignoring member attribute update on /0/members/56e0b6dad4c53d42/attributes
2019-12-04 10:25:16.113314 I | ignoring member attribute update on /0/members/2d2e457c6a1a76cb/attributes
2019-12-04 10:25:16.113319 I | ignoring member attribute update on /0/members/d2d2e9fc758e6790/attributes
2019-12-04 10:25:16.113384 I | ignoring member attribute update on /0/members/56e0b6dad4c53d42/attributes
 
# 使用v3版本
[root@etcd-0-14 ~]# export ETCDCTL_API=3
[root@etcd-0-14 ~]# etcdctl --endpoints="http://172.16.0.8:2379,http://172.16.0.14:2379,http://172.16.0.17:2379" snapshot save mysnapshot.db
Snapshot saved at mysnapshot.db
[root@etcd-0-14 ~]# etcdctl snapshot status mysnapshot.db -w json
{"hash":928285884,"revision":0,"totalKey":5,"totalSize":20480}

六 總結

  • etcd 默認只保存 1000 個歷史事件,所以不適合有大量更新操作的場景,這樣會導致數據的丟失。 etcd 典型的應用場景是配置管理和服務發現,這些場景都是讀多寫少的。

  • 相比於 zookeeper,etcd 使用起來要簡單很多。不過要實現真正的服務發現功能,etcd 還需要和其他工具(比如 registrator、confd 等)一起使用來實現服務的自動註冊和更新。

  • 目前 etcd 還沒有圖形化的工具。

相關文章