FreeBSD upgrades with bectl

The default FreeBSD upgrade procedure with either freebsd-update or distribution sets both operate in the same way - a boot-environment is created of the current system state, and then the running system is manipulated inplace to perform the upgrade. The created boot-environment is there in case of a failure.

However, I have grown accustomed to transactional updates be that from Fedora Atomic (yes I'm old) or OpenSUSE. I would like to recreate the same experience with FreeBSD. I hope in the future that this process becomes official or has some nicer tooling wrapped around it in the future to make it more accessible to people.

freebsd-update

Update the current system, and then reboot into it.

export BECTL_NAME="$(uname -r)_$(date '+%Y-%m-%d')"
bectl create -r ${BECTL_NAME}
bectl mount ${BECTL_NAME} /tmp/${BECTL_NAME}
freebsd-update -b /tmp/${BECTL_NAME} fetch install
bectl unmount ${BECTL_NAME}
bectl activate ${BECTL_NAME}
# reboot

OPTIONAL: You can use bectl activate -t ${BECTL_NAME} here instead for a one-time reboot, which allows a slightly easier rollback path. You just need to remember to run activate again without -t once the reboot completes and you are happy.

Begin the 15.1 upgrade process. Normally you need to reboot in the middle, but since we are doing this into a boot environment we can avoid this.

export BECTL_NAME="15.1-RELEASE"
bectl create -r ${BECTL_NAME}
bectl mount ${BECTL_NAME} /tmp/${BECTL_NAME}

freebsd-update -b /tmp/${BECTL_NAME} upgrade -r 15.1-RELEASE
freebsd-update -b /tmp/${BECTL_NAME} install

# Needs to be run a second time now for the userland to be updated. Normally this
# is where the reboot would be.

freebsd-update -b /tmp/${BECTL_NAME} install
pkg -c /tmp/${BECTL_NAME} upgrade
freebsd-update -b /tmp/${BECTL_NAME} install

bectl unmount ${BECTL_NAME}
bectl activate -t ${BECTL_NAME}
# reboot

This now reboots into the new version. NOTE the -t here for single time reboot.

Finally if you are happy with the state of the system:

export BECTL_NAME="15.1-RELEASE"
bectl activate ${BECTL_NAME}

Then proceed to follow the bootloader update section from the official documentation.

distribution sets

Update the current system, and then reboot into it.

export BECTL_NAME="$(uname -r)_$(date '+%Y-%m-%d')"
bectl create -r ${BECTL_NAME}
bectl mount ${BECTL_NAME} /tmp/${BECTL_NAME}

pkg -c /tmp/${BECTL_NAME} upgrade

bectl unmount ${BECTL_NAME}
bectl activate ${BECTL_NAME}
# reboot

Upgrade to 15.1

export BECTL_NAME="15.1-RELEASE"
bectl create -r ${BECTL_NAME}
bectl mount ${BECTL_NAME} /tmp/${BECTL_NAME}

pkg -c /tmp/${BECTL_NAME} -oABI=FreeBSD:15:$(uname -p) -oOSVERSION=1501000 upgrade

# Resolve any failed config file merges
find /tmp/${BECTL_NAME}/etc /tmp/${BECTL_NAME}/usr/local/etc -name '*.pkgnew' -ls

bectl unmount ${BECTL_NAME}
bectl activate -t ${BECTL_NAME}
# reboot

Finally if you are happy with the state of the system:

export BECTL_NAME="15.1-RELEASE"
bectl activate ${BECTL_NAME}

Then proceed to follow the bootloader update section from the official documentation.