在学习和开发基于 etcd 的服务和性能时,须要本人在本地部署一套 etcd 集群。
原以为这是一个简略的事件,但意外地花了我几个小时才搞定……本文介绍无效的部署办法和踩过的一些坑。
网络筹备
咱们以三个节点为例。首先,默认的 etcd 监听 2370 端口,提供 HTTP API;另外采纳 2380 端口实现节点之间(peer)的通信。
其次,官网文档采纳的是在多个 IP 地址上部署不同的节点。但我只想在手头的一台 MacBook 上部署多个 etcd 容器。
第三,网上的教程应用的都是 docker-compose
来部署多节点,但这也不合乎我的需要,因为我须要动静启动和敞开节点,模仿节点故障,从而察看 etcd 的状态。
综上所述,我须要给这个 etcd 集群调配总共 6 个端口,举例如下:
节点名称 | http | peer |
---|---|---|
etcd-node-1 |
21379 |
21380 |
etcd-node-2 |
22379 |
22380 |
etcd-node-3 |
23379 |
23380 |
启动脚本
我的操作系统是 maxOS v11.2.1,Docker 是 Docker Desktop 3.1.0 版,shell 是 zsh,脚本如下:
# For each machine
# SUDO=sudo
SUDO=
ETCD_VERSION=v3.2.30
TOKEN=amc-etcd-token
CLUSTER_STATE=new
NAMES=(etcd-node-0 etcd-node-1 etcd-node-2)
HOSTS=(host.docker.internal host.docker.internal host.docker.internal)
CLIENT_PORTS=(21379 22379 23379)
PARTNER_PORTS=(21380 22380 23380)
# test array index start
_first=0
if [-z ${NAMES[0]} ]; then
_first=1;
fi
CLUSTER=${NAMES[_first]}=http://${HOSTS[_first]}:${PARTNER_PORTS[_first]}
for ((i=1; i < ${#NAMES[@]}; i++)) do
CLUSTER=${CLUSTER},${NAMES[$i+${_first}]}=http://${HOSTS[$i+${_first}]}:${PARTNER_PORTS[$i+${_first}]};
done;
echo CLUSTER=${CLUSTER}
# For each node 1
for ((i=0; i < ${#NAMES[@]}; i++)) do
THIS_NAME=${NAMES[$i+${_first}]};
THIS_HOST=${HOSTS[$i+${_first}]};
THIS_CLIENT_PORT=${CLIENT_PORTS[$i+${_first}]};
THIS_PARTNER_PORT=${PARTNER_PORTS[$i+${_first}]};
${SUDO} docker run -d --name ${THIS_NAME} \
-p ${THIS_PARTNER_PORT}:2380 -p ${THIS_CLIENT_PORT}:2379 \
quay.io/coreos/etcd:${ETCD_VERSION} \
/usr/local/bin/etcd \
--data-dir=data.etcd --name ${THIS_NAME} \
--initial-advertise-peer-urls http://${THIS_HOST}:${THIS_PARTNER_PORT} --listen-peer-urls http://0.0.0.0:2380 \
--advertise-client-urls http://${THIS_HOST}:${THIS_CLIENT_PORT} --listen-client-urls http://0.0.0.0:2379 \
--initial-cluster ${CLUSTER} \
--initial-cluster-token ${TOKEN} \
--initial-cluster-state ${CLUSTER_STATE};
done;
脚本逻辑阐明
读者只须要批改上文的脚本中前置的几个变量即可,如下:
ETCD_VERSION
: etcd 的版本NAMES
: 这是个数组,示意各个节点的名称。本脚本中也作为容器名HOSTS
: 各个节点对外裸露的主机地址。既然是同一主机,并且我采纳的是 docker 的 bridge 网络,那么就对立采纳host.docker.internal
即可CLIENT_PORTS
: 调配给各个节点的原 2379 端口的映射PARTNER_PORTS
: 调配给各个节点的原 2380 端口的映射
前面的四个数组变量的长度必须相等。
其余注意事项
数组下标问题
首先,该脚本采纳了 macOS 当初的默认 shell /bin/zsh
,但仍然也能够在 sh
和 bash
下执行。然而 zsh
有一个很大的不同:数组下标从 1 而不是 0 开始。
笔者长期在 Linux 下写脚本,差点把这个问题疏忽了。因而,在脚本中通过以下语句做了兼容:
_first=0
if [-z ${NAMES[0]} ]; then
_first=1;
fi
迭代数组成员的时候应用 $i+${_first}
etcd 版本
笔者最开始参照 etcd 的官网文档,采纳了 v3.0.0 版的 etcd,然而节点在启动后会呈现以下谬误:
v3rpc/grpc: grpc: addrConn.resetTransport failed to create client transport: connection error: desc = "transport: dial tcp [::]:2379: connect: cannot assign requested address"; Reconnecting to {"[::]:2379" <nil>}
找了很久没有找到起因和解决方案。起初,我改用 v3.2.20
,问题就迎刃而解了。看来这应该是 etcd 旧版的一个 bug 了。
此外,--listen-peer-urls
和 --listen-client-urls
不能监听在 127.0.0.1
或 localhost
上,因为这就变成了容器外部的环回地址,无奈接管到来自容器外的(包含宿主机和其余容器)的申请。
验证性能
搭建胜利啦,在宿主机上调用 etcd API 即可验证,三个节点都能够验证一遍:
% curl http://127.0.0.1:21379/v2/keys/message -X PUT -d value="Hello world"
{"action":"set","node":{"key":"/message","value":"Hello world","modifiedIndex":8,"createdIndex":8}}
% curl http://127.0.0.1:22379/v2/keys/message -X PUT -d value="Hello etcd"
{"action":"set","node":{"key":"/message","value":"Hello etcd","modifiedIndex":9,"createdIndex":9},"prevNode":{"key":"/message","value":"Hello world","modifiedIndex":8,"createdIndex":8}}
% curl http://127.0.0.1:23379/v2/keys/message -X PUT -d value="Hello ALL"
{"action":"set","node":{"key":"/message","value":"Hello ALL","modifiedIndex":10,"createdIndex":10},"prevNode":{"key":"/message","value":"Hello etcd","modifiedIndex":9,"createdIndex":9}}
理论开发调试中,将这几个节点挂在 nginx 负载平衡前面就能够拜访了。
参考资料
- Running etcd under Docker
- docker 搭建 etcd 集群环境
- 部署 etcd
- 应用 Docker 创立运行 Etcd 集群
- 在容器内运行 etcd 集群
- Docker 之网络配置
- Docker 网络详解之 Host
- MacOS 端口占用状况,其中 netstat 命令与 CentOS 略有出入
本文章采纳 常识共享署名 - 非商业性应用 - 雷同形式共享 4.0 国内许可协定 进行许可。原文公布于 https://cloud.tencent.com/developer/article/1790869,也是自己的博客。
原作者:amc,欢送转载,但请注明出处。
原文题目:《用 Docker 在单台宿主机启动多个 etcd 节点》
公布日期:2021-02-24
原文链接:https://segmentfault.com/a/1190000039266806。