FreeBSD failover in the cloud — UCARP to the rescue
I’m a big fan of FreeBSD. However, as painful it is to admit, it isn’t always the best OS to run in the cloud. Compared to Linux, you will get worse network and disk performance even with Virtio installed. There are also other issues. For instance, it is likely that you won’t get CARP to fully work (while this works perfectly fine with OpenBSD’s CARP, and Linux’s VRRP). I have written about workarounds for this issue in the past, but they do not seem to work equally well in FreeBSD 9.0.
Luckily, there is a userland implementation of CARP called UCARP that works better than CARP. It’s also very similar to CARP when it comes to configuration.
Unfortunately UCARP’s website includes more or less zero documentation, so I’ll help you get started. I won’t talk too much about what CARP is, as I assume you already know that if you’re reading this. There is however one major difference between CARP and UCARP — UCARP doesn’t have its own dedicated interface. Instead it relies on IP aliases that are brought up and down with the scripts below.
First of all, you need to install UCARP from ports:
cd /usr/ports/net/ucarp/ && make clean install
We now need to enable UCARP in rc.conf by adding the following:
ucarp_enable="YES" ucarp_if="vtnet1" ucarp_vhid="1" ucarp_pass="carppass" ucarp_preempt="YES" ucarp_facility="daemon" ucarp_src="192.168.10.10" ucarp_addr="192.168.10.1" ucarp_advbase="2" ucarp_advskew="0" ucarp_upscript="/usr/local/bin/ucarp_up.sh" ucarp_downscript="/usr/local/bin/ucarp_down.sh"
I’m not going to go into too much details about the above variables. You can read more about them here. You will however most likely need to change ucarp_if, ucarp_src, ucarp_addr, ucarp_advskew, and ucarp_advbase to match your environment. They’re mostly self-explanatory. The only somewhat confusing ones I guess would be ucarp_src, which is the host’s IP and ucarp_advskew, which determines priority (the lower value will become master).
Next, we need to create two script that will be triggered in the two different states.
#!/bin/sh # Load variables from rc.conf . /etc/rc.subr load_rc_config ucarp /sbin/ifconfig $ucarp_if alias $ucarp_addr/32
#!/bin/sh # Load variables from rc.conf . /etc/rc.subr load_rc_config ucarp /sbin/ifconfig $ucarp_if -alias $ucarp_addr/32
With all of those files in place, you can simply start ucarp with:
Once you’ve gotten the UCARP working, it’s time to tie it into your desired workflow. Contrary to CARP, which relies on dev.d for triggar-actions, you will use ucarp_up.sh and ucarp_down.sh.
The biggest downside perhaps with UCARP is that you can’t bind an application on the failover IP when the node is in backup mode, like you can with CARP. As a result, you will need to work a bit harder when scripting your up/down actions. There is however one benefit with UCARP — you can configure it to run actions prior to bringing up the new interface. That can be handy if you need to do something before the node steps up as mater.