1. 程式人生 > >如何在滴滴雲 DC2 上搭建 ETCD 叢集

如何在滴滴雲 DC2 上搭建 ETCD 叢集

簡介

ETCD 是一個開源的分散式 Key-Value 儲存,它採用 Raft 演算法來保證資料的強一致性,故常常用來存取分散式系統中對一致性要求比較苛刻的配置資訊,被廣泛應用。它具有如下特點:

  • 簡單:為使用者提供了簡單而友好的 API 介面(gRPC)
  • 安全:客戶端認證授權自動支援 TLS
  • 快速:基準測試效能可達每秒 10000 寫操作
  • 可靠:採用 Raft 演算法實現的分散式一致

ETCD 被很多公司在生產環境中廣泛使用。ETCD 也是Kubernetes、Locksmith、Vulcand、Doorman 等著名開源專案的核心元件。

ETCD 支援兩種組建叢集的方式,第一種方式是靜態配置,第二種是服務發現。

靜態配置一個 ETCD 叢集需要提前知道叢集的成員節點 IP 地址或主機名。在有些場景下,叢集成員節點的 IP 地址無法提前知道,那麼也可以通過服務發現的方式來啟動叢集。

一旦一個 ETCD 叢集啟動並執行起來後,新增和移除叢集成員節點就需要通過執行時重新配置(Runtime Reconfiguration)的方式來完成。

在本文中,我們介紹基於靜態配置組建 ETCD 叢集的機制,靜態配置叢集也是生產環境中使用 ETCD 的常用方式。

基本環境要求

我們使用三個滴滴雲 DC2 伺服器(奇數個 quorum,5個或7個伺服器更好)來搭建一個最小化的 ETCD 叢集,伺服器的主機名與 IP 地址資訊如下:

  1. etcd-1: 10.255.1.211
  2. etcd-2: 10.255.1.40
  3. etcd-3: 10.255.1.181

登陸 DC2,檢視三個伺服器的 IP 與 Hostname 詳細資訊如下:

第一個伺服器的 IP 與主機名資訊

[[email protected] ~]$ ip a | grep 'inet\b' | grep -v '127.0.0.1'
    inet 10.255.1.211/24 brd 10.255.1.255 scope global eth0
[[email protected] ~]$ hostname
etcd-1

第二個伺服器的 IP 與主機名資訊

[[email protected] ~]$ ip a | grep 'inet\b' | grep -v '127.0.0.1'
    inet 10.255.1.40/24 brd 10.255.1.255 scope global eth0
[[email protected] ~]$ hostname
etcd-2

第三個伺服器 IP 與主機名資訊

[[email protected] ~]$ ip a | grep 'inet\b' | grep -v '127.0.0.1'
    inet 10.255.1.181/24 brd 10.255.1.255 scope global eth0
[[email protected] ~]$ hostname
etcd-3

另外,要求上面所有伺服器上的防火牆配置開放 2380 與 2379 埠的訪問,前者用於監聽 ETCD 客戶端請求,後者用於 ETCD 叢集其他節點的通訊。

配置 ETCD 叢集

步驟1 :CD 到 home 目錄:

[[email protected] ~]$ cd ~
[[email protected] ~]$ pwd
/home/dc2-user

步驟2 :從GitHub下載最近的 ETCD 發行版,並且解壓。在寫作本文時,最新的發行版為 3.3.10。

[[email protected] ~]$ sudo wget "https://github.com/etcd-io/etcd/releases/download/v3.3.10/etcd-v3.3.10-linux-amd64.tar.gz"
[[email protected] ~]$ ls
etcd-v3.3.10-linux-amd64.tar.gz
[[email protected] ~]$ tar -zxvf etcd-v3.3.10-linux-amd64.tar.gz 

步驟3 :將解壓得到的 ETCD 程式新增到系統可執行檔案目錄。

[[email protected] ~]$ sudo mv etcd-v3.3.10-linux-amd64/etcd* /usr/local/bin/

這裡步驟 1 至步驟 3 需要在所有伺服器上執行。

在靜態配置的情況下,因為我們已經知道叢集成員節點的 IP 地址和叢集規模,我們可以使用一個啟動配置來組建叢集,啟動配置需設定 initial-cluster 標誌。

每臺機器需要配置如下環境變數:

ETCD_INITIAL_CLUSTER="etcd-1=http://10.255.1.211:2380,etcd-2=http://10.255.1.40:2380,etcd-3=http://10.255.1.181:2380"
ETCD_INITIAL_CLUSTER_STATE=new

或者配置如下的 ETCD 引數:

--initial-cluster etcd-1=http://10.255.1.211:2380,etcd-2=http://10.255.1.40:2380,etcd-3=http://10.255.1.181:2380 \
--initial-cluster-state new

注意這裡 initial-cluster 指定的 URL 必須與 initial-advertise-peer-urls 指定的保持一致。

另外,在配置叢集時還有個引數特別有用必須切記不要忘了設定,即 initial-cluster-token。將每個 initial-cluster-token 設定為唯一的值,可以防止人為失誤的錯誤配置而導致一個節點加入兩個叢集的問題。

ETCD 監聽 listen-client-urls 指定的地址來接受客戶端請求,但是隻有在 advertise-client-urls 中指定的地址才會能被叢集其他成員、叢集代理或客戶端訪問到。一個常見的錯誤是將 advertise-client-urls 配置為 localhost 或不配置而是用預設值,這會導致叢集不能被其他機器的客戶端訪問到。

步驟4 :在每個伺服器上,依次使用如下命令來啟動 ETCD,使用上面我們提到的引數。

在 etcd-1 伺服器上的啟動命令如下:

[[email protected] ~]$ etcd --name etcd-1 --initial-advertise-peer-urls http://10.255.1.211:2380 \
>   --listen-peer-urls http://10.255.1.211:2380 \
>   --listen-client-urls http://10.255.1.211:2379,http://127.0.0.1:2379 \
>   --advertise-client-urls http://10.255.1.211:2379 \
>   --initial-cluster-token etcd-cluster-on-didicloud \
>   --initial-cluster etcd-1=http://10.255.1.211:2380,etcd-2=http://10.255.1.40:2380,etcd-3=http://10.255.1.181:2380 \
>   --initial-cluster-state

在 etcd-2 伺服器上的啟動命令如下:

[[email protected] ~]$ etcd --name etcd-2 --initial-advertise-peer-urls http://10.255.1.40:2380 \
>   --listen-peer-urls http://10.255.1.40:2380 \
>   --listen-client-urls http://10.255.1.40:2379,http://127.0.0.1:2379 \
>   --advertise-client-urls http://10.255.1.40:2379 \
>   --initial-cluster-token etcd-cluster-on-didicloud \
>   --initial-cluster etcd-1=http://10.255.1.211:2380,etcd-2=http://10.255.1.40:2380,etcd-3=http://10.255.1.181:2380 \
>   --initial-cluster-state new

在 etcd-3 伺服器上的啟動命令如下:

[[email protected] ~]$ etcd --name etcd-3 --initial-advertise-peer-urls http://10.255.1.181:2380 \
>   --listen-peer-urls http://10.255.1.181:2380 \
>   --listen-client-urls http://10.255.1.181:2379,http://127.0.0.1:2379 \
>   --advertise-client-urls http://10.255.1.181:2379 \
>   --initial-cluster-token etcd-cluster-on-didicloud \
>   --initial-cluster etcd-1=http://10.255.1.211:2380,etcd-2=http://10.255.1.40:2380,etcd-3=http://10.255.1.181:2380 \
>   --initial-cluster-state new 

命令列引數 -initial-cluster 只在叢集初次啟動時生效。再次啟動時可以不傳這個引數。如果需要在執行時修改配置,請參考 ETCD 的執行時改配置幫助文件。

驗證叢集狀態

ETCD 安裝包內帶有一個 etcdctl 命令列工具,可以用來獲取叢集狀態資訊。可以在任意叢集節點上執行如下的命令檢查叢集狀態。
檢查叢集是否健康:

[[email protected] ~]$ etcdctl cluster-health
member dc6b4b48ae00bf8 is healthy: got healthy result from http://10.255.1.40:2379
member d6020117e8a2dc38 is healthy: got healthy result from http://10.255.1.181:2379
member e95ffbf99d4aae9c is healthy: got healthy result from http://10.255.1.211:2379
cluster is healthy

使用如下命令檢查叢集成員節點:

[[email protected] ~]$ etcdctl member list
dc6b4b48ae00bf8: name=etcd-2 peerURLs=http://10.255.1.40:2380 
clientURLs=http://10.255.1.40:2379 isLeader=false
d6020117e8a2dc38: name=etcd-3 peerURLs=http://10.255.1.181:2380 
clientURLs=http://10.255.1.181:2379 isLeader=false
e95ffbf99d4aae9c: name=etcd-1 peerURLs=http://10.255.1.211:2380 
clientURLs=http://10.255.1.211:2379 isLeader=true
[[email protected] ~]$ 

預設情況下,etcdctl 使用 ETCD v2 介面與服務端互動。你可以顯示指定 ETCDCTL_API=3 來使用 etcd v3 版本的功能。
可以通過設定 Linux 系統環境變數來設定使用 etcd v3 版本功能,也可以在每次命令列執行時指定該環境變數。
現在我們往叢集寫入幾個 key-value 鍵值對來驗證一下。

[[email protected] ~]$ ETCDCTL_API=3 etcdctl put name1 batman
OK
[[email protected] ~]$ ETCDCTL_API=3 etcdctl put name2 ironman
OK
[[email protected] ~]$ ETCDCTL_API=3 etcdctl put name3 superman
OK
[[email protected] ~]$ ETCDCTL_API=3 etcdctl put name4 spiderman
OK
[[email protected] ~]$ 

現在可以使用下面的命令讀取剛才寫入的鍵值。

[[email protected] ~]$ ETCDCTL_API=3 etcdctl get name3
name3
superman
[[email protected] ~]$ 

ETCD 還支援指定獲取 key 範圍或字首批量讀取。

[[email protected] ~]$ ETCDCTL_API=3 etcdctl get name1 name4  
# 讀取從name1到name4的所有key-value
name1
batman
name2
ironman
name3
superman
[[email protected] ~]$ ETCDCTL_API=3 etcdctl get --prefix name 
# 列出所有以name為字首的key-value
name1
batman
name2
ironman
name3
superman
name4
spiderman