前言
Consul采用三Server+3Client的模式部署,在某一些特殊条件下会出现Node无法注册上去的问题。
其主要的表现为Client无法和Server组成集群,但是这不局限于Client,Server也会出现同样的问题。
原始错误如下:
(WARN] agent.fsm: EnsureRegistration failed: error="fail
ed inserting node: Error while renaming Node ID: "5964b14a-b86f-d6b6-5be8-3d8bdf68afdd": Node name consul-lient
2 is reserved by node 5e8058ec-d71b-9f46-86al-cdl4ebc452657 with name consul-client-2 (10.0.88.14)
问题原因
原因是由于Consul中注册的时候是按照NodeId进行唯一区分的,但是NodeId又是根据主机或者容器中的一些环境参数进行生成的,导致如果计算了两个一样的NodeId但是IP和NodeName又不一样,就会出现这个错误。
网上说了很多种解决方案,要么是治标不治本,要么只能临时解决,很不靠谱,考证Github上绝活哥的一些建议,要想根本上解决这个问题,需要将NodeId固定住,或者将调度节点固定住(这个也不是很靠谱,IP变了之后还是可能会出现问题)。
解决方式
第一种(建议):
自己生成NodeId去解决这个问题,其实就是根据一个永远不会变化的值去生成一个NodeId,保证只要我的唯一值不变,NodeId就不会变。考虑到便捷性,我这边是使用的hostname
,这个hostname
不管是在Swarm中还是在K8S中都是可以做到一致的,K8S使用有状态的调度器即可,Swarm直接使用{{.Task.Slot}}
即可。
注意:我这是Swarm的编排,而且我这边是自定义子网 10.0.88.0/24
,需要切换为正确的使用子网。
entrypoint:
- /bin/sh
command:
- -c
- |
node_id=$$(hostname | md5sum | awk '{printf "%s-%s-%s-%s-%s", substr($$1,1,8), substr($$1,9,4), substr($$1,13,4), substr($$1,17,4), substr($$1,21)}')
echo "NodeID->$${node_id}"
/usr/local/bin/docker-entrypoint.sh agent -bind '{{ GetPrivateInterfaces | include "network" "10.0.88.0/24" | attr "address" }}' -node-id "$$node_id"
第二种:
定向调度去解决,就是将节点固定住,不允许K8S/Swarm到处乱调度,这种方式没啥太大问题,就是当IP要变的时候就还是可能会出现问题。而且这种有局限,会丢失一部分的灵活性。