If a node is promoted right after another node is demoted, there exists
the possibility of a race, by which the newly promoted manager attempts
to connect to the newly demoted manager for its initial Raft membership.
This connection fails, and the whole swarm Node object exits.
At this point, the daemon nodeRunner sees the exit and restarts the
Node.
However, if the address of the no-longer-manager is recorded in the
nodeRunner's config.joinAddr, the Node again attempts to connect to the
no-longer-manager, and crashes again. This repeats. The solution is to
remove the node entirely and rejoin the Swarm as a new node.
This change erases config.joinAddr from the restart of the nodeRunner,
if the node has previously become Ready. The node becoming Ready
indicates that at some point, it did successfully join the cluster, in
some fashion. If it has successfully joined the cluster, then Swarm has
its own persistent record of known manager addresses. If no joinAddr is
provided, then Swarm will choose from its persisted list of managers to
join, and will join a functioning manager.
Signed-off-by: Drew Erny <derny@mirantis.com>
| ... | ... |
@@ -282,6 +282,19 @@ func (n *nodeRunner) handleNodeExit(node *swarmnode.Node) {
|
| 282 | 282 |
close(n.done) |
| 283 | 283 |
select {
|
| 284 | 284 |
case <-n.ready: |
| 285 |
+ // there is a case where a node can be promoted to manager while |
|
| 286 |
+ // another node is leaving the cluster. the node being promoted, by |
|
| 287 |
+ // random chance, picks the IP of the node being demoted as the one it |
|
| 288 |
+ // tries to connect to. in this case, the promotion will fail, and the |
|
| 289 |
+ // whole swarm Node object packs it in. |
|
| 290 |
+ // |
|
| 291 |
+ // when the Node object is relaunched by this code, because it has |
|
| 292 |
+ // joinAddr in the config, it attempts again to connect to the same |
|
| 293 |
+ // no-longer-manager node, and crashes again. this continues forever. |
|
| 294 |
+ // |
|
| 295 |
+ // to avoid this case, in this block, we remove JoinAddr from the |
|
| 296 |
+ // config. |
|
| 297 |
+ n.config.joinAddr = "" |
|
| 285 | 298 |
n.enableReconnectWatcher() |
| 286 | 299 |
default: |
| 287 | 300 |
if n.repeatedRun {
|