0 專輯概述
etcd 是雲原生架構中重要的基礎元件,由 CNCF 孵化託管。etcd 在微服務和 Kubernates 叢集中不僅可以作為服務註冊與發現,還可以作為 key-value 儲存的中介軟體。
《徹底搞懂 etcd 系列文章》將會從 etcd 的基本功能實踐、API 介面、實現原理、原始碼分析,以及實現中的踩坑經驗等幾方面具體展開介紹 etcd。預計會有 20 篇左右的文章,筆者將會每週持續更新,歡迎關注。
1 etcd 叢集部署
在生產環境中,為了整個叢集的高可用,etcd 正常都會叢集部署,避免單點故障。本節將會介紹如何進行 etcd 叢集部署。引導 etcd 叢集的啟動有以下三種機制:
- 靜態
- etcd 動態發現
- DNS 發現
靜態啟動 etcd 叢集要求每個成員都知道叢集中的另一個成員。 在許多情況下,群整合員的 IP 可能會提前未知。在這些情況下,可以在發現服務的幫助下引導 etcd 群集。
下面我們將會分別介紹這幾種方式。
2 靜態方式啟動 etcd 叢集
單機安裝
如果想要在一臺機器上實踐 etcd 叢集的搭建,可以通過 goreman 工具。
goreman 是一個 Go 語言編寫的多程式管理工具,是對 Ruby 下廣泛使用的 foreman 的重寫(foreman 原作者也實現了一個 Go 版本:forego,不過沒有 goreman 好用)。
我們需要確認 Go 安裝環境,然後直接執行:
go get github.com/mattn/goreman
編譯後的檔案放在 $GOPATH/bin
中,$GOPATH/bin
目錄已經新增到了系統 $PATH
中,所以我們可以方便執行命令 goreman
命令。下面就是編寫 Procfile 指令碼,我們啟動三個 etcd,具體對應如下:
HostName | ip | 客戶端互動埠 | peer 通訊埠
:-: | :-: | :-: | :-:
infra1 | 127.0.0.1 | 12379 | 12380 |
infra2 | 127.0.0.1| 22379 | 22380 |
infra3 | 127.0.0.1| 32379 | 32380 |
Procfile 指令碼如下:
etcd1: etcd --name infra1 --listen-client-urls http://127.0.0.1:12379 --advertise-client-urls http://127.0.0.1:12379 --listen-peer-urls http://127.0.0.1:12380 --initial-advertise-peer-urls http://127.0.0.1:12380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof --logger=zap --log-outputs=stderr
etcd2: etcd --name infra2 --listen-client-urls http://127.0.0.1:22379 --advertise-client-urls http://127.0.0.1:22379 --listen-peer-urls http://127.0.0.1:22380 --initial-advertise-peer-urls http://127.0.0.1:22380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof --logger=zap --log-outputs=stderr
etcd3: etcd --name infra3 --listen-client-urls http://127.0.0.1:32379 --advertise-client-urls http://127.0.0.1:32379 --listen-peer-urls http://127.0.0.1:32380 --initial-advertise-peer-urls http://127.0.0.1:32380 --initial-cluster-token etcd-cluster-1 --initial-cluster 'infra1=http://127.0.0.1:12380,infra2=http://127.0.0.1:22380,infra3=http://127.0.0.1:32380' --initial-cluster-state new --enable-pprof --logger=zap --log-outputs=stderr
配置項說明:
- --name:etcd叢集中的節點名,這裡可以隨意,可區分且不重複就行
- --listen-peer-urls:監聽的用於節點之間通訊的url,可監聽多個,叢集內部將通過這些url進行資料互動(如選舉,資料同步等)
- --initial-advertise-peer-urls:建議用於節點之間通訊的url,節點間將以該值進行通訊。
- --listen-client-urls:監聽的用於客戶端通訊的url,同樣可以監聽多個。
- --advertise-client-urls:建議使用的客戶端通訊 url,該值用於 etcd 代理或 etcd 成員與 etcd 節點通訊。
- --initial-cluster-token: etcd-cluster-1,節點的 token 值,設定該值後叢集將生成唯一 id,併為每個節點也生成唯一 id,當使用相同配置檔案再啟動一個叢集時,只要該 token 值不一樣,etcd 叢集就不會相互影響。
- --initial-cluster:也就是叢集中所有的 initial-advertise-peer-urls 的合集。
- --initial-cluster-state:new,新建叢集的標誌
注意上面的指令碼,etcd 命令執行時需要根據本地實際的安裝地址進行配置。下面我們啟動 etcd 叢集。
goreman -f /opt/procfile start
使用如上的命令啟動啟動 etcd 叢集,啟動完成之後檢視叢集內的成員。
$ etcdctl --endpoints=http://localhost:22379 member list
8211f1d0f64f3269, started, infra1, http://127.0.0.1:12380, http://127.0.0.1:12379, false
91bc3c398fb3c146, started, infra2, http://127.0.0.1:22380, http://127.0.0.1:22379, false
fd422379fda50e48, started, infra3, http://127.0.0.1:32380, http://127.0.0.1:32379, false
我們在單機搭建的偽叢集成功,需要注意的是在叢集啟動時,我們是通過靜態的方式指定叢集的成員,在實際環境中,叢集成員的 ip 可能不會提前知道。這時候就需要採用動態發現的機制。
docker 啟動叢集
etcd 使用 gcr.io/etcd-development/etcd 作為容器的主要加速器, quay.io/coreos/etcd 作為輔助的加速器。可惜這兩個加速器我們都沒法訪問,如果下載不了,可以使用筆者提供的地址:
docker pull bitnami/etcd:3.4.7
然後將拉取的映象重新 tag:
docker image tag bitnami/etcd:3.4.7 quay.io/coreos/etcd:3.4.7
映象設定好之後,我們啟動 3 個節點的 etcd 叢集,指令碼命令如下:
REGISTRY=quay.io/coreos/etcd
# For each machine
ETCD_VERSION=3.4.7
TOKEN=my-etcd-token
CLUSTER_STATE=new
NAME_1=etcd-node-0
NAME_2=etcd-node-1
NAME_3=etcd-node-2
HOST_1= 192.168.202.128
HOST_2= 192.168.202.129
HOST_3= 192.168.202.130
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
DATA_DIR=/var/lib/etcd
# For node 1
THIS_NAME=${NAME_1}
THIS_IP=${HOST_1}
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd ${REGISTRY}:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://0.0.0.0:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://0.0.0.0:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
# For node 2
THIS_NAME=${NAME_2}
THIS_IP=${HOST_2}
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd ${REGISTRY}:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://0.0.0.0:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://0.0.0.0:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
# For node 3
THIS_NAME=${NAME_3}
THIS_IP=${HOST_3}
docker run \
-p 2379:2379 \
-p 2380:2380 \
--volume=${DATA_DIR}:/etcd-data \
--name etcd ${REGISTRY}:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=/etcd-data --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://0.0.0.0:2380 \
--advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://0.0.0.0:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
注意,上面的指令碼是部署在三臺機器上面,每臺機器執行對應的指令碼即可。在執行時可以指定 API 版本:
docker exec etcd /bin/sh -c "export ETCDCTL_API=3 && /usr/local/bin/etcdctl put foo bar"
docker 的安裝方式比較簡單,讀者根據需要可以定製一些配置。
3 動態發現啟動 etcd 叢集
如前面所述,在實際環境中,叢集成員的 ip 可能不會提前知道。在這種情況下,需要使用自動發現來引導 etcd 叢集,而不是指定靜態配置,這個過程被稱為發現。我們啟動三個 etcd,具體對應如下:
HostName | ip | 客戶端互動埠 | peer 通訊埠
:-: | :-: | :-: | :-:
etcd1 | 192.168.202.128 | 2379 | 2380 |
etcd2 | 192.168.202.129| 2379 | 2380 |
etcd3 | 192.168.202.130| 2379 | 2380 |
協議的原理
Discovery service protocol 幫助新的 etcd 成員使用共享 URL 在叢集引導階段發現所有其他成員。
該協議使用新的發現令牌來引導一個唯一的 etcd 叢集。一個發現令牌只能代表一個 etcd 叢集。只要此令牌上的發現協議啟動,即使它中途失敗,也不能用於引導另一個 etcd 叢集。
提示:Discovery service protocol 僅用於叢集引導階段,不能用於執行時重新配置或叢集監視。
Discovery protocol 使用內部 etcd 叢集來協調新叢集的載入程式。首先,所有新成員都與發現服務互動,並幫助生成預期的成員列表。之後,每個新成員使用此列表引導其伺服器,該列表執行與 --initial-cluster
標誌相同的功能,即設定所有叢集的成員資訊。
獲取 discovery 的 token
生成將標識新叢集的唯一令牌。 在以下步驟中,它將用作發現鍵空間中的唯一字首。 一種簡單的方法是使用uuidgen:
UUID=$(uuidgen)
指定叢集的大小
獲取令牌時,必須指定群集大小。 發現服務使用該大小來了解何時發現了最初將組成叢集的所有成員。
curl -X PUT http://10.0.10.10:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=3
我們需要把該 url 地址 http://10.0.10.10:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83 作為 --discovery
引數來啟動 etcd。
節點會自動使用 http://10.0.10.10:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83 目錄進行 etcd 的註冊和發現服務。
公共發現服務
當我們本地沒有可用的 etcd 叢集,etcd 官網提供了一個可以公網訪問的 etcd 儲存地址。我們可以通過如下命令得到 etcd 服務的目錄,並把它作為 --discovery
引數使用。
公共發現服務 discovery.etcd.io
以相同的方式工作,但是有一層修飾,可以提取醜陋的 URL,自動生成 UUID,並提供針對過多請求的保護。公共發現服務在其上仍然使用 etcd 群集作為資料儲存。
$ curl http://discovery.etcd.io/new?size=3
http://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
以動態發現方式啟動叢集
etcd 發現模式下,啟動 etcd 的命令如下:
# etcd1 啟動
$ /opt/etcd/bin/etcd --name etcd1 --initial-advertise-peer-urls http://192.168.202.128:2380 \
--listen-peer-urls http://192.168.202.128:2380 \
--data-dir /opt/etcd/data \
--listen-client-urls http://192.168.202.128:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.202.128:2379 \
--discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
# etcd2 啟動
/opt/etcd/bin/etcd --name etcd2 --initial-advertise-peer-urls http://192.168.202.129:2380 \
--listen-peer-urls http://192.168.202.129:2380 \
--data-dir /opt/etcd/data \
--listen-client-urls http://192.168.202.129:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.202.129:2379 \
--discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
# etcd3 啟動
/opt/etcd/bin/etcd --name etcd3 --initial-advertise-peer-urls http://192.168.202.130:2380 \
--listen-peer-urls http://192.168.202.130:2380 \
--data-dir /opt/etcd/data \
--listen-client-urls http://192.168.202.130:2379,http://127.0.0.1:2379 \
--advertise-client-urls http://192.168.202.130:2379 \
--discovery https://discovery.etcd.io/3e86b59982e49066c5d813af1c2e2579cbf573de
需要注意的是,在我們完成了叢集的初始化後,這些資訊就失去了作用。當需要增加節點時,需要使用 etcdctl 進行操作。為了安全,每次啟動新 etcd 叢集時,都使用新的 discovery token 進行註冊。另外,如果初始化時啟動的節點超過了指定的數量,多餘的節點會自動轉化為 Proxy 模式的 etcd。
結果驗證
叢集啟動好之後,進行驗證,我們看一下叢集的成員:
$ /opt/etcd/bin/etcdctl member list
# 結果如下
40e2ac06ca1674a7, started, etcd3, http://192.168.202.130:2380, http://192.168.202.130:2379, false
c532c5cedfe84d3c, started, etcd1, http://192.168.202.128:2380, http://192.168.202.128:2379, false
db75d3022049742a, started, etcd2, http://192.168.202.129:2380, http://192.168.202.129:2379, false
結果符合預期,再看下節點的健康狀態:
$ /opt/etcd/bin/etcdctl --endpoints="http://192.168.202.128:2379,http://192.168.202.129:2379,http://192.168.202.130:2379" endpoint health
# 結果如下
http://192.168.202.128:2379 is healthy: successfully committed proposal: took = 3.157068ms
http://192.168.202.130:2379 is healthy: successfully committed proposal: took = 3.300984ms
http://192.168.202.129:2379 is healthy: successfully committed proposal: took = 3.263923ms
可以看到,叢集中的三個節點都是健康的正常狀態。以動態發現方式啟動叢集成功。
4 DNS自發現模式
etcd 還支援使用 DNS SRV 記錄進行啟動。實際上是利用 DNS 的 SRV 記錄不斷輪訓查詢實現。DNS SRV 是 DNS 資料庫中支援的一種資源記錄的型別,它記錄了計算機與所提供服務資訊的對應關係。
Dnsmasq 安裝
這裡使用 Dnsmasq 建立 DNS 服務。Dnsmasq 提供 DNS 快取和 DHCP 服務、Tftp 服務功能。作為域名解析伺服器,Dnsmasq 可以通過快取 DNS 請求來提高對訪問過的網址的連線速度。Dnsmasq 輕量且易配置,適用於個人使用者或少於 50 臺主機的網路。此外它還自帶了一個 PXE 伺服器。
當接受到一個 DNS 請求時,Dnsmasq 首先會查詢 /etc/hosts 這個檔案,然後查詢 /etc/resolv.conf 中定義的外部 DNS。配置 Dnsmasq 為 DNS 快取伺服器,同時在 /etc/hosts 檔案中加入本地內網解析,這樣使得內網機器查詢時就會優先查詢 hosts 檔案,這就等於將 /etc/hosts 共享給全內網機器使用,從而解決內網機器互相識別的問題。相比逐臺機器編輯 hosts 檔案或者新增 Bind DNS 記錄,可以只編輯一個 hosts 檔案。
基於筆者使用的 Centos 7 的主機,首先安裝 Dnsmasq:
yum install dnsmasq
安裝好之後,進行配置,所有的配置都在一個檔案中完成 /etc/dnsmasq.conf。我們也可以在 /etc/dnsmasq.d 中自己寫任意名字的配置檔案。
配置上游伺服器地址
resolv-file 配置 Dnsmasq 額外的上游的 DNS 伺服器,如果不開啟就使用 Linux 主機預設的 /etc/resolv.conf 裡的 nameserver。
$ vim /etc/dnsmasq.conf
# 增加如下的內容:
resolv-file=/etc/resolv.dnsmasq.conf
srv-host=_etcd-server._tcp.blueskykong.com,etcd1.blueskykong.com,2380,0,100
srv-host=_etcd-server._tcp.blueskykong.com,etcd2.blueskykong.com,2380,0,100
srv-host=_etcd-server._tcp.blueskykong.com,etcd3.blueskykong.com,2380,0,100
在 dnsmasq.conf 中相應的域名記錄,配置了我們所涉及的三臺伺服器,分別對應 etcd1,etcd2,etcd3。
在指定檔案中增加轉發 DNS 的地址
$ vim /etc/resolv.dnsmasq.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
這兩個免費的 DNS服務,大家應該不陌生。讀者可以根據本地實際網路進行配置。
本地啟用 Dnsmasq 解析
$ vim /etc/resolv.conf
nameserver 127.0.0.1
將 Dnsmasq 解析配置到本地,這很好理解。
新增解析記錄
分別為各個域名配置相關的 A 記錄指向 etcd 核心節點對應的機器 IP。新增解析記錄有三種方式:使用系統預設 hosts、使用自定義 hosts 檔案、使用自定義 conf。這裡我們使用比較簡單的第一種方式。
$ vim /etc/hosts
# 增加如下的內容解析
192.168.202.128 etcd1.blueskykong.com
192.168.202.129 etcd2.blueskykong.com
192.168.202.130 etcd3.blueskykong.com
啟動服務
service dnsmasq start
啟動好之後,我們進行驗證:
-
DNS 伺服器上 SRV 記錄查詢,查詢到的結果如下:
<span class="katex"><annotation encoding="application x-tex"=""> dig @192.168.202.128 +noall +answer SRV _etcd-server._tcp.blueskykong.com
_etcd-server._tcp.blueskykong.com. 0 IN SRV 0 100 2380 etcd2.blueskykong.com.
_etcd-server._tcp.blueskykong.com. 0 IN SRV 0 100 2380 etcd1.blueskykong.com.
_etcd-server._tcp.blueskykong.com. 0 IN SRV 0 100 2380 etcd3.blueskykong.com.
</code></pre></li>
<li><p>使查詢域名解析結果</p>
<pre><code><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"><span class="mord mathit">d<span class="mord mathit">i<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">@<span class="mord">1<span class="mord">9<span class="mord">2<span class="mord">.<span class="mord">1<span class="mord">6<span class="mord">8<span class="mord">.<span class="mord">2<span class="mord">0<span class="mord">2<span class="mord">.<span class="mord">1<span class="mord">2<span class="mord">8<span class="mspace" style="margin-right:0.2222222222222222em;"><span class="mbin">+<span class="mspace" style="margin-right:0.2222222222222222em;"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"><span class="mord mathit">n<span class="mord mathit">o<span class="mord mathit">a<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mspace" style="margin-right:0.2222222222222222em;"><span class="mbin">+<span class="mspace" style="margin-right:0.2222222222222222em;"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"><span class="mord mathit">a<span class="mord mathit">n<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.02691em;">w<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit" style="margin-right:0.05764em;">S<span class="mord mathit" style="margin-right:0.00773em;">R<span class="mord mathit" style="margin-right:0.22222em;">V<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">4<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">s<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit" style="margin-right:0.03588em;">v<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord">.<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">p<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">4<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">s<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit" style="margin-right:0.03588em;">v<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord">.<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">p<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">.<span class="mord">0<span class="mord mathit" style="margin-right:0.07847em;">I<span class="mord mathit" style="margin-right:0.10903em;">N<span class="mord mathit" style="margin-right:0.05764em;">S<span class="mord mathit" style="margin-right:0.00773em;">R<span class="mord mathit" style="margin-right:0.22222em;">V<span class="mord">0<span class="mord">1<span class="mord">0<span class="mord">0<span class="mord">2<span class="mord">3<span class="mord">8<span class="mord">0<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">2<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">.<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">4<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">s<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit" style="margin-right:0.03588em;">v<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord">.<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">p<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">.<span class="mord">0<span class="mord mathit" style="margin-right:0.07847em;">I<span class="mord mathit" style="margin-right:0.10903em;">N<span class="mord mathit" style="margin-right:0.05764em;">S<span class="mord mathit" style="margin-right:0.00773em;">R<span class="mord mathit" style="margin-right:0.22222em;">V<span class="mord">0<span class="mord">1<span class="mord">0<span class="mord">0<span class="mord">2<span class="mord">3<span class="mord">8<span class="mord">0<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">1<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">.<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">4<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">s<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit" style="margin-right:0.03588em;">v<span class="mord mathit">e<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord">.<span class="mord">¨<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord">9<span class="mord">5<span class="mord mathit" style="margin-right:0.05764em;">E<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">p<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">.<span class="mord">0<span class="mord mathit" style="margin-right:0.07847em;">I<span class="mord mathit" style="margin-right:0.10903em;">N<span class="mord mathit" style="margin-right:0.05764em;">S<span class="mord mathit" style="margin-right:0.00773em;">R<span class="mord mathit" style="margin-right:0.22222em;">V<span class="mord">0<span class="mord">1<span class="mord">0<span class="mord">0<span class="mord">2<span class="mord">3<span class="mord">8<span class="mord">0<span class="mord mathit">e<span class="mord mathit">t<span class="mord mathit">c<span class="mord mathit">d<span class="mord">3<span class="mord">.<span class="mord mathit">b<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">u<span class="mord mathit">e<span class="mord mathit">s<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit" style="margin-right:0.03588em;">y<span class="mord mathit" style="margin-right:0.03148em;">k<span class="mord mathit">o<span class="mord mathit">n<span class="mord mathit" style="margin-right:0.03588em;">g<span class="mord">.<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">m<span class="mord">.<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"><span class="mord">/<span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">d<span class="mord mathit">e<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"><span class="mord">/<span class="mord mathit">p<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit">e<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"><span class="mord">/<span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">i<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:0.73354em;vertical-align:-0.0391em;"><span class="mord mathit" style="margin-right:0.01968em;">l<span class="mord mathit">i<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:0.7335400000000001em;vertical-align:-0.19444em;"><span class="mord mathit">p<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mord cjk_fallback">使<span class="mord cjk_fallback">查<span class="mord cjk_fallback">詢<span class="mord cjk_fallback">域<span class="mord cjk_fallback">名<span class="mord cjk_fallback">解<span class="mord cjk_fallback">析<span class="mord cjk_fallback">結<span class="mord cjk_fallback">果<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"><span class="mord">/<span class="mord mathit">p<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:0.7335400000000001em;vertical-align:-0.19444em;"><span class="mord mathit">p<span class="mord mathit" style="margin-right:0.02778em;">r<span class="mord mathit">e<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"><span class="mrel"><<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="base"><span class="strut" style="height:0.73354em;vertical-align:-0.0391em;"><span class="mord mathit">c<span class="mord mathit">o<span class="mord mathit">d<span class="mord mathit">e<span class="mspace" style="margin-right:0.2777777777777778em;"><span class="mrel">> dig @192.168.202.128 +noall +answer etcd1.blueskykong.com etcd2.blueskykong.com etcd3.blueskykong.com
etcd1.blueskykong.com. 0 IN A 192.168.202.128
etcd2.blueskykong.com. 0 IN A 192.168.202.129
etcd3.blueskykong.com. 0 IN A 192.168.202.130
至此,我們已成功安裝好 Dnsmasq。下面我們基於 DNS 發現啟動 etcd 叢集。
啟動叢集
做好了上述兩步 DNS 的配置,就可以使用 DNS 啟動 etcd 叢集了。需要刪除ETCD_INITIAL_CLUSTER 配置(用於靜態服務發現),並指定 DNS SRV 域名(ETCD_DISCOVERY_SRV)。配置 DNS 解析的 url 引數為 -discovery-srv
,其中 etcd1 節點地啟動命令如下:
$ /opt/etcd/bin/etcd --name etcd1 \
--discovery-srv blueskykong.com \
--initial-advertise-peer-urls http://etcd1.blueskykong.com:2380 \
--initial-cluster-token etcd-cluster-1 \
--data-dir /opt/etcd/data \
--initial-cluster-state new \
--advertise-client-urls http://etcd1.blueskykong.com:2379 \
--listen-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380
etcd 群整合員可以使用域名或 IP 地址進行廣播,啟動的過程將解析 DNS 記錄。--initial-advertise-peer-urls 中的解析地址必須與 SRV 目標中的解析地址匹配。etcd 成員讀取解析的地址,以查詢其是否屬於 SRV 記錄中定義的群集。
我們驗證基於 DNS 發現啟動叢集的正確性,檢視叢集的成員列表:
$ /opt/etcd/bin/etcdctl member list
# 結果如下:
40e2ac06ca1674a7, started, etcd3, http://192.168.202.130:2380, http://etcd3.blueskykong.com:2379, false
c532c5cedfe84d3c, started, etcd1, http://192.168.202.128:2380, http://etcd1.blueskykong.com:2379, false
db75d3022049742a, started, etcd2, http://192.168.202.129:2380, http://etcd2.blueskykong.com:2379, false
可以看到,結果輸出 etcd 叢集有三個成員,符合預期。下面我們使用 IP 地址的方式,繼續驗證叢集節點的狀態。
$ /opt/etcd/bin/etcdctl --endpoints="http://192.168.202.128:2379,http://192.168.202.129:2379,http://192.168.202.130:2379" endpoint health
# 結果如下:
http://192.168.202.129:2379 is healthy: successfully committed proposal: took = 2.933555ms
http://192.168.202.128:2379 is healthy: successfully committed proposal: took = 7.252799ms
http://192.168.202.130:2379 is healthy: successfully committed proposal: took = 7.415843ms
更多的 etcd 叢集操作,讀者可以自行嘗試,筆者不在此一一展開。
5 小結
本文在上一篇文章單機安裝 etcd 的基礎上進行了補充,主要介紹了 etcd 叢集的多種安裝啟動方式:靜態單體,靜態 docker,動態發現以及 DNS 發現的啟動方式。這麼多的安裝姿勢,都是為了我們實際的使用,下一篇我們將具體進入 etcdctl 的使用講解。