FreeBSD upgrades with bectl

The default FreeBSD upgrade procedure with either distribution sets or package base 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.

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}
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.

package base

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.