So, I have two compute nodes. I’ll soon have 32GB RAM in each one, currently one has 32GB and the other has its original 8GB… with 5 8GB modules on the way.
I’ve tested these, and they work fine in the nodes I have, they’ll even work along side the Kingston modules I already have, so one storage node will have a mixture. That RAM is expected to arrive on Monday.
Now, it’d be nice to have HA set up so that I can power down the still-to-be-upgraded compute node, and have everything automatically fire up on the other compute node. OpenNebula supports this. BUT I have two instances that are being managed outside of OpenNebula that I need to handle: one being the core router, the other being OpenNebula itself.
My plan was to use corosync. I have an identical libvirt config for both VMs, allowing me to move the VMs manually between the hosts. VM Disk storage is using RBDs on Ceph. Thus, HA by default.
As an experiment, I thought, what would happen if I fired up two instances of the VM that pointed to the same RBD image? I was expecting one of two things to happen:
- The image would be locked by the first started image, locking out the second. One instance would boot, the other would fail to boot.
- Both instances would boot… the split-brain scenario.
So, I created a libvirt domain on one node, slapped Ubuntu on there (I just wanted a basic OS for testing, so command line, nothing fancy). As that was installing, I dumped out the “XML config” and imported that to the second node, but didn’t start it yet.
Once I had the new VM booted on node 1, I booted it on node 2.
To my horror, it started booting, and booted straight to a log-in prompt. Great, I had manually re-created the split-brain scenario I specifically hoped to avoid. Thankfully, it is a throw-away VM specifically for testing this behaviour. To be sure, I logged in on both, then hard-resetted one. It boots to GRUB, then immediately GRUB goes into panic mode. I hard reset the other VM, it boots past GRUB, but then systemd goes into panic mode. This is expected: the two VMs are stomping on each others’ data oblivious to each others’ existence, a recipe for disaster.
So for this to work, I’m going to have to work on my fencing. I need to ensure beyond all possible doubt, that the VM is running in one place and one place ONLY.
libvirt supports VM hooks to do this, and there’s an example here, however this thread seems to suggest this is not a reliable way of doing things. RBD locking is what I hoped libvirt would do implicitly, but it seems not, and it appears that the locks are not removed when a client dies, which could lead to other problems.
A distributed lock manager would handle this, and this is something I need to research. Possibilities include HashiCorp Consul, Apache ZooKeeper, CoreOS etcd and Redis, among others. I can also try to come up with my own, perhaps built on PAXOS or Raft.
The state needs to only be kept in memory, persistence on disk is not required. It’s safe to assume that if the cluster doesn’t know about a VM, it isn’t running anywhere else. Once told of that VMs existence though, it should ensure only one instance runs at a time.
If a node loses contact with the remaining group, it should terminate everything it has, as it’s a fair bet, the others have noticed its absence and have re-started those instances already.
There’s lots to think about here, so I’ll leave this post at this point and ponder this some more.