一、etcd簡介與應用場景
etcd 是一個分布式一致性k-v存儲系統,可用於服務注冊發現與共享配置,具有以下優點:1、簡單 : 相比於晦澀難懂的paxos算法,etcd基於相對簡單且易實現的raft算法實現一致性,並通過gRPC提供接口調用;2、安全:支持TLS通信,並可以針對不同的用戶進行對key的讀寫控制;3、高性能:10,000 /秒的寫性能。其主要應用於服務注冊發現以及共享配置。
1、 服務注冊與發現
- 服務啟動后向etcd注冊,並上報自己的監聽的端口以及當前的權重因子等信息,且對該信息設置ttl值。
- 服務在ttl的時間內周期性上報權重因子等信息。
- client端調用服務時向etcd獲取信息,進行調用,同時監聽該服務是否變化(通過watch方法實現)。
- 當新增服務時watch方法監聽到變化,將服務加入代用列表,當服務掛掉時ttl失效,client端檢測到變化,將服務踢出調用列表,從而實現服務的動態擴展。
- 另一方面,client端通過每次變化獲取到的權重因子來進行client端的加權調用策略,從而保證后端服務的負載均衡。
2、共享配置
一般服務啟動時需要加載一些配置信息,如數據庫訪問地址,連接配置,這些配置信息每個服務都差不多,如果通過讀取配置文件進行配置會存在要寫多份配置文件,且每次更改時這些配置文件都要更改,且更改配置后,需要重啟服務后才能生效,這些無疑讓配置極不靈活,如果將配置信息放入到etcd中,程序啟動時進行加載並運行,同時監聽配置文件的更改,當配置文件發生更改時,自動將舊值替換新值,這樣無疑簡化程序配置,更方便於服務部署。
二、單機模式運行
默認在centos7的yum源里已集成了etcd包,可以通過yum進行安裝。也可以去github上下載二進制包:https://github.com/coreos/etcd/tags,這里我選擇的yum直接安裝的。啟用etcd服務命令如下:
- # systemctl start etcd
進行如下測試etcd的可用性:
- [root@etcd1 ~]# etcdctl set site www.361way.com
- www.361way.com
- [root@etcd1 ~]# etcdctl get site
- www.361way.com
從上面可以看到可以進行k/v值的設置和獲取。不過單機模式一般很少使用。
三、集群模式說明
這里的集群模式是指完全集群模式,當然也可以在單機上通過不同的端口,部署偽集群模式,只是那樣做只適合測試環境,生產環境考慮到可用性的話需要將etcd實例分布到不同的主機上,這里集群搭建有三種方式,分布是靜態配置,etcd發現,dns發現。默認配置運行etcd,監聽本地的2379端口,用於與client端交互,監聽2380用於etcd內部交互。etcd啟動時,集群模式下會用到的參數如下:
- --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
- 新建集群的標志,初始化狀態使用 new,建立之后改此值為 existing
主機規划如下:
name | IP |
etcd01 | 192.168.122.51 |
etcd02 | 192.168.122.52 |
etcd03 | 192.168.122.53 |
注意,這里的name是etcd集群里使用的名字,不是主機名,當然和主機名一致也是沒關系的。
四、靜態模式
如果只是測試,這里建議使用二進制包進行測試。因為源碼包編譯的,使用etcd命令執行時加上的參數會被配置文件/etc/etcd/etcd.conf覆蓋。直接二進制包的不會,如果是現網使用yum包就比較推薦了。分別在三個節點上使用如下命令啟動:
- #節點1:
- ./etcd --name etcd01 --initial-advertise-peer-urls http://192.168.122.51:2380 \
- --listen-peer-urls http://0.0.0.0:2380 \
- --listen-client-urls http://0.0.0.0:2379 \
- --advertise-client-urls http://192.168.122.51:2379 \
- --initial-cluster-token etcd-cluster-1 \
- --initial-cluster etcd01=http://192.168.122.51:2380,etcd02=http://192.168.122.52:2380,etcd03=http://192.168.122.53:2380 \
- --initial-cluster-state new
- #節點2
- ./etcd --name etcd02 --initial-advertise-peer-urls http://192.168.122.52:2380 \
- --listen-peer-urls http://0.0.0.0:2380 \
- --listen-client-urls http://0.0.0.0:2379 \
- --advertise-client-urls http://192.168.122.52:2379 \
- --initial-cluster-token etcd-cluster-1 \
- --initial-cluster etcd01=http://192.168.122.51:2380,etcd02=http://192.168.122.52:2380,etcd03=http://192.168.122.53:2380 \
- --initial-cluster-state new
- #節點3
- ./etcd --name etcd03 --initial-advertise-peer-urls http://192.168.122.53:2380 \
- --listen-peer-urls http://0.0.0.0:2380 \
- --listen-client-urls http://0.0.0.0:2379 \
- --advertise-client-urls http://192.168.122.53:2379 \
- --initial-cluster-token etcd-cluster-1 \
- --initial-cluster etcd01=http://192.168.122.51:2380,etcd02=http://192.168.122.52:2380,etcd03=http://192.168.122.53:2380 \
- --initial-cluster-state new
啟動成功后,可以使用如下命令查看(啟動集群后,將會進入集群選舉狀態。看到isLeader為true為就是選舉出的leader節點):
- [root@etcd1 ~]# etcdctl member list
- 692a38059558446: name=etcd03 peerURLs=http://192.168.122.53:2380 clientURLs=http://192.168.122.53:2379 isLeader=true
- 1b1ca7d3774cbbb9: name=etcd02 peerURLs=http://192.168.122.52:2380 clientURLs=http://192.168.122.52:2379 isLeader=false
- cb75efb850ec8c2a: name=etcd01 peerURLs=http://192.168.122.51:2380 clientURLs=http://192.168.122.51:2379 isLeader=false
- [root@etcd1 ~]# etcdctl cluster-health
- member 692a38059558446 is healthy: got healthy result from http://192.168.122.53:2379
- member 1b1ca7d3774cbbb9 is healthy: got healthy result from http://192.168.122.52:2379
- member cb75efb850ec8c2a is healthy: got healthy result from http://192.168.122.51:2379
如果使用yum包安裝的,需要修改etcd.conf配置文件如下:
- [root@etcd1 ~]# grep -v ^# /etc/etcd/etcd.conf
- ETCD_NAME=etcd01
- ETCD_DATA_DIR="/var/lib/etcd/default.etcd"
- ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
- ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
- ETCD_INITIAL_ADVERTISE_PEER_URLS="http://192.168.122.51:2380"
- ETCD_INITIAL_CLUSTER="etcd01=http://192.168.122.51:2380,etcd02=http://192.168.122.52:2380,etcd03=http://192.168.122.53:2380"
- ETCD_INITIAL_CLUSTER_STATE="existing"
- ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster2"
- ETCD_ADVERTISE_CLIENT_URLS="http://192.168.122.51:2379"
修改完成后,還需要修改/usr/lib/systemd/system/etcd.service文件內容如下:
- [Unit]
- Description=Etcd Server
- After=network.target
- After=network-online.target
- Wants=network-online.target
- [Service]
- Type=notify
- WorkingDirectory=/var/lib/etcd/
- EnvironmentFile=-/etc/etcd/etcd.conf
- User=etcd
- # set GOMAXPROCS to number of processors
- ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/bin/etcd \
- --name=\"${ETCD_NAME}\" \
- --data-dir=\"${ETCD_DATA_DIR}\" \
- --listen-peer-urls=\"${ETCD_LISTEN_PEER_URLS}\" \
- --advertise-client-urls=\"${ETCD_ADVERTISE_CLIENT_URLS}\" \
- --initial-cluster-token=\"${ETCD_INITIAL_CLUSTER_TOKEN}\" \
- --initial-cluster=\"${ETCD_INITIAL_CLUSTER}\" \
- --initial-cluster-state=\"${ETCD_INITIAL_CLUSTER_STATE}\" \
- --listen-client-urls=\"${ETCD_LISTEN_CLIENT_URLS}\""
- Restart=on-failure
- LimitNOFILE=65536
- [Install]
- WantedBy=multi-user.target
配置過程中可能遇到的問題有兩個。
1、本地連接報錯
內容如下:
- Error: client: etcd cluster is unavailable or misconfigured
- error #0: dial tcp 127.0.0.1:2379: getsockopt: connection refused
- error #1: dial tcp 127.0.0.1:4001: getsockopt: connection refused
如果出現如上的錯誤,是因為ETCD_LISTEN_CLIENT_URLS參數沒有配置http://127.0.0.1:2379而導致的,所以這里我使用了0.0.0.0代表了監控所有地址。
2、context deadline exceeded
集群啟動后,在通過etcdctl member list查看結果時,一直返回這個。后來發現和我使用的環境有關,因為測試不能上外網,這里配置了一個squid代理,在環境變量里有如下配置:
- http_proxy=10.212.52.25:3128
- https_proxy=10.212.52.25:3128
- ftp_proxy=10.212.52.25:3128
- export http_proxy https_proxy ftp_proxy
發現將這部分結果注釋,重新啟動etcd服務就好了。
五、動態配置
靜態配置前提是在搭建集群之前已經提前知道各節點的信息,而實際應用中可能存在預先並不知道各節點ip的情況,這時可通過已經搭建的etcd來輔助搭建新的etcd集群。首先需要在已經搭建的etcd中創建用於發現的url,命令如下:
- [root@etcd1 ~]# curl -X PUT http://192.168.122.51:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size -d value=3
- {"action":"set","node":{"key":"/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83/_config/size","value":"3","modifiedIndex":19,"createdIndex":19}}
如果沒有搭建好的etcd集群用於注冊和發現,可使用etcd公有服務來進行服務注冊發現。公有etcd服務上創建用於發現的url為:
- [root@etcd1 ~]# curl https://discovery.etcd.io/new?size=3
- https://discovery.etcd.io/a6a292c79fff6d25ef09243e3dfd2043
在三個節點上啟動的命令分別如下:
- #節點1
- ./etcd --name infra0 --initial-advertise-peer-urls http://192.168.122.51:2380 \
- --listen-peer-urls http://0.0.0.0:2380 \
- --listen-client-urls http://0.0.0.0:2379 \
- --advertise-client-urls http://192.168.122.51:2379 \
- --discovery http://192.168.122.51:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
- #節點2
- ./etcd --name infra1 --initial-advertise-peer-urls http://10.0.1.109:2380 \
- --listen-peer-urls http://0.0.0.0:2380 \
- --listen-client-urls http://0.0.0.0:2379 \
- --advertise-client-urls http://10.0.1.109:2379 \
- --discovery http://192.168.122.51:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
- #節點3
- ./etcd --name infra2 --initial-advertise-peer-urls http://10.0.1.110:2380 \
- --listen-peer-urls http://0.0.0.0:2380 \
- --listen-client-urls http://0.0.0.0:2379 \
- --advertise-client-urls http://10.0.1.110:2379 \
- --discovery http://192.168.122.51:2379/v2/keys/discovery/6c007a14875d53d9bf0ef5a6fc0257c817f0fb83
同樣,如果使用yum 包安裝的,需要修改etcd.conf文件和etcd.service文件。
六、DNS發現
這個配置方法我沒測試過,這里直接拿官方給的樣例列出下。
- _etcd-server-ssl._tcp.example.com
- _etcd-server._tcp.example.com
- _etcd-client._tcp.example.com
- _etcd-client-ssl._tcp.example.com
另一方面,client端將獲取以上域名下的節點域名,用於client端與etcd通信,ssl與非ssl的使用取決於以上那個域名下有值。
創建dns記錄
- $ dig +noall +answer SRV _etcd-server._tcp.example.com
- _etcd-server._tcp.example.com. 300 IN SRV 0 0 2380 infra0.example.com.
- _etcd-server._tcp.example.com. 300 IN SRV 0 0 2380 infra1.example.com.
- _etcd-server._tcp.example.com. 300 IN SRV 0 0 2380 infra2.example.com.
- $ dig +noall +answer SRV _etcd-client._tcp.example.com
- _etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra0.example.com.
- _etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra1.example.com.
- _etcd-client._tcp.example.com. 300 IN SRV 0 0 2379 infra2.example.com.
- $ dig +noall +answer infra0.example.com infra1.example.com infra2.example.com
- infra0.example.com. 300 IN A 10.0.1.111
- infra1.example.com. 300 IN A 10.0.1.109
- infra2.example.com. 300 IN A 10.0.1.110
然后啟動各個節點
- $ etcd --name infra0 \
- --discovery-srv example.com \
- --initial-advertise-peer-urls http://infra0.example.com:2380 \
- --initial-cluster-token etcd-cluster-1 \
- --initial-cluster-state new \
- --advertise-client-urls http://infra0.example.com:2379 \
- --listen-client-urls http://infra0.example.com:2379 \
- --listen-peer-urls http://infra0.example.com:2380
- $ etcd --name infra1 \
- --discovery-srv example.com \
- --initial-advertise-peer-urls http://infra1.example.com:2380 \
- --initial-cluster-token etcd-cluster-1 \
- --initial-cluster-state new \
- --advertise-client-urls http://infra1.example.com:2379 \
- --listen-client-urls http://infra1.example.com:2379 \
- --listen-peer-urls http://infra1.example.com:2380
- $ etcd --name infra2 \
- --discovery-srv example.com \
- --initial-advertise-peer-urls http://infra2.example.com:2380 \
- --initial-cluster-token etcd-cluster-1 \
- --initial-cluster-state new \
- --advertise-client-urls http://infra2.example.com:2379 \
- --listen-client-urls http://infra2.example.com:2379 \
- --listen-peer-urls http://infra2.example.com:2380
參考頁面: