Bullseye upgrade
It's Debian major upgrade time again! My personal policy is generally to upgrade slightly before or during the freeze. This time I feel almost late because it seems we'll be releasing in almost a month now (May 2021, it's April 2021 now).
Update: this procedure was tested first on my workstation (curie). I have done another (the laptop, angela) in July 2021, and the server (marcos) in October 2021.
This document contains my upgrade procedure, notable changes in the new version, issues I have stumbled upon (and possibly fixed), and troubleshooting instructions.
It does not hope to replace the official documentation: it is a personal, living document that I have started keeping back when I upgraded to jessie. The other documents can be found in the parent upgrades page.
Procedure
This procedure is designed to be applied, in batch, on multiple servers. Do NOT follow this procedure unless you are familiar with the command line and the Debian upgrade process. It has been crafted by and for experienced system administrators that have dozens if not hundreds of servers to upgrade.
In particular, it runs almost completely unattended: configuration changes are not prompted during the upgrade, and just not applied at all, which will break services in many cases. I use a clean-conflicts script to do this all in one shot to shorten the upgrade process (without it, configuration file changes stop the upgrade at more or less random times). Then those changes get applied after a reboot. And yes, that's even more dangerous.
IMPORTANT: if you are doing this procedure over SSH (I had the privilege of having a console), you may want to upgrade SSH first as it has a longer downtime period, especially if you are on a flaky connection.
Preparation:
: reset to the default locale export LC_ALL=C.UTF-8 && : put server in maintenance && sudo touch /etc/nologin && : install some dependencies sudo apt install ttyrec screen debconf-utils deborphan apt-forktracer && : create ttyrec file with adequate permissions && sudo touch /var/log/upgrade-bullseye.ttyrec && sudo chmod 600 /var/log/upgrade-bullseye.ttyrec && sudo ttyrec -e screen /var/log/upgrade-bullseye.ttyrec
Backups and checks:
( umask 0077 && tar cfz /var/backups/pre-bullseye-backup.tgz /etc /var/lib/dpkg /var/lib/apt/extended_states /var/cache/debconf $( [ -e /var/lib/aptitude/pkgstates ] && echo /var/lib/aptitude/pkgstates ) && dpkg --get-selections "*" > /var/backups/dpkg-selections-pre-bullseye.txt && debconf-get-selections > /var/backups/debconf-selections-pre-bullseye.txt ) && ( puppet agent --test || true )&& apt-mark showhold && dpkg --audit && : look for dkms packages and make sure they are relevant, if not, purge. && ( dpkg -l '*dkms' || true ) && : look for leftover config files && /home/anarcat/src/koumbit-scripts/vps/clean_conflicts && : run backups && /home/anarcat/bin/backup-$(hostname) && printf "End of Step 2\a\n"
Perform any pending upgrade and clear out old pins:
puppet agent --disable "running major upgrade" && apt update && apt -y upgrade && : Check for pinned, on hold, packages, and possibly disable && rm -f /etc/apt/preferences /etc/apt/preferences.d/* && rm -f /etc/apt/sources.list.d/backports.debian.org.list && rm -f /etc/apt/sources.list.d/backports.list && rm -f /etc/apt/sources.list.d/bookworm.list && rm -f /etc/apt/sources.list.d/bullseye.list && rm -f /etc/apt/sources.list.d/buster-backports.list && rm -f /etc/apt/sources.list.d/experimental.list && rm -f /etc/apt/sources.list.d/incoming.list && rm -f /etc/apt/sources.list.d/proposed-updates.list && rm -f /etc/apt/sources.list.d/sid.list && rm -f /etc/apt/sources.list.d/testing.list && : purge removed packages && apt purge $(dpkg -l | awk '/^rc/ { print $2 }') && apt autoremove -y --purge && : possibly clean up old kernels && dpkg -l 'linux-image-*' && : look for packages from backports, other suites or archives && : if possible, switch to official packages by disabling third-party repositories && apt-forktracer | sort && printf "End of Step 3\a\n"
Check free space, see this guide to free up space and download packages:
systemctl stop apt-daily.timer && sed -i 's#buster/updates#bullseye-security#' $(ls /etc/apt/sources.list /etc/apt/sources.list.d/*) && sed -i 's/buster/bullseye/g' $(ls /etc/apt/sources.list /etc/apt/sources.list.d/*) && apt update && apt -y -d full-upgrade && apt -y -d upgrade && apt -y -d dist-upgrade && df -h && printf "End of Step 4\a\n"
Actual upgrade run:
env DEBIAN_FRONTEND=noninteractive APT_LISTCHANGES_FRONTEND=none APT_LISTBUGS_FRONTEND=none UCF_FORCE_CONFFOLD=y \ apt full-upgrade -y -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' && printf "End of Step 5\a\n"
Post-upgrade procedures:
apt-get update --allow-releaseinfo-change && puppet agent --enable && puppet agent -t --noop && printf "Press enter to continue, Ctrl-C to abort." && read -r _ && (puppet agent -t || true) && : reinstall Python packages to follow Python upgrade && for package in rsendmail pubpaste ; do cd ~/src/$package && pip3 install . done && : rm -f /etc/apt/apt.conf.d/50unattended-upgrades.dpkg-dist /etc/ca-certificates.conf.dpkg-old /etc/cron.daily/bsdmainutils.dpkg-remove /etc/default/prometheus-apache-exporter.dpkg-dist /etc/default/prometheus-node-exporter.dpkg-dist /etc/logrotate.d/apache2.dpkg-dist /etc/nagios/nrpe.cfg.dpkg-dist /etc/ssh/ssh_config.dpkg-dist /etc/ssh/sshd_config.ucf-dist /etc/unbound/unbound.conf.dpkg-dist && printf "\a" && /home/anarcat/src/koumbit-scripts/vps/clean_conflicts && systemctl start apt-daily.timer && printf "End of Step 6\a\n" && shutdown -r +1 "rebooting to get rid of old kernel image..."
Post-upgrade checks:
export LC_ALL=C.UTF-8 && sudo ttyrec -a -e screen /var/log/upgrade-bullseye.ttyrec apt-mark manual bind9-dnsutils apt purge libgcc1:amd64 gcc-8-base:amd64 apt purge $(dpkg -l | awk '/^rc/ { print $2 }') # purge removed packages apt autoremove -y --purge apt purge $(deborphan --guess-dummy | grep -v python-is-python2) while deborphan -n | grep -v python-is-python2 | grep -q . ; do apt purge $(deborphan -n | grep -v python-is-python2); done apt autoremove -y --purge apt clean # review and purge older kernel if the new one boots properly dpkg -l 'linux-image*' # review packages that are not in the new distribution apt-forktracer | sort printf "All procedures completed\a\n" &&
Notable changes
Here are some packages with notable version changes that I noticed.
- driverless scanning and printing
- persistent systemd journal, which might have some privacy issues
(
rm -rf /var/log/journal
to disable, see journald.conf(5)) - last release to support non-merged /usr
- security archive changed to
deb https://deb.debian.org/debian-security bullseye-security main contrib
(covered by script above) - the Intel VA-API driver might give performance boosts and battery savings when playing video, see this note
- password hashes have changed to yescrypt (recognizable
from its
$y$
prefix), a major change from the previous default, SHA-512 (recognizable from its$6$
prefix), see also crypt(5) (in bullseye), crypt(3) (in buster), andmkpasswd -m help
for a list of supported hashes on whatever
There is a more exhaustive review of server-level changes from mikas as well. Notable:
kernel.unprivileged_userns_clone
enabled by default (bug 898446)- Prometheus hardering, initiated by yours truly
- Ganeti has a major upgrade! there were concerns about the upgrade path, not sure how that turned out
See also the wiki page about bullseye for another list.
New packages
This is a curated list of packages that were introduced in bullseye. There are actually thousands of new packages in the new Debian release, but this is a small selection of projects I found particularly interesting:
- age, alternative encryption tool
- bpfmon, BPF-based packet visualizer
- bpytop, awesome looking system monitor, python rewrite of bashtop
- crowdsec, "lightweight and collaborative security engine", think of a collaborative fail2ban
- dnf, the RedHat package manager
- doas, OpenBSD's sudo replacement
- foot, fast, lightweight and minimalistic Wayland terminal emulator
- gammastep, redshift replacement for Wayland
- gdu, disk usage analyzer, golang rewrite of ncdu, presumably faster
- guix, declarative package manager
- jamulus, "real-time collaborative music session client and server"
- laminar, simple CI
- lowdown, Markdown translator (to HTML, man, LaTeX, etc)
- pipewire, Pulseaudio and Jack replacement, video multiplexer, already in buster, but actually usable now
- plocate, mlocate rewrite, much faster, will be default in bookworm
- podman, a Docker replacement
- rssguard, nice looking feed reader
- sayonara, nice looking music player
- sbuild-qemu, a qemu-backed sbuild Debian package builder
- sequoia, Rust OpenPGP implementation, ships with
sq
andsq-keyring-linter
in bullseye! - sway, Wayland rewrite of the i3 window manager
- vorta, GUI frontend to the Borg backup tool
My packages
In packages I maintain, those are the important changes:
- charybdis is not going to ship with bullseye at all, it has been abandoned upstream and forked by OFTC and Freenode into solanum, which should hopefully make it to bullseye-backports eventually
- gameclock was removed from Debian: it's an old program which I would need to rewrite to port both to Python 3 and GTK 3, and I just can't find the time. quite sad.
- monkeysign is also going away, but thankfully there are alternatives: caff still exists (in signing-party), as do pius and GNOME Keysign
- feed2exec, undertime, linkchecker, and stressant are still alive and most are seeing modest upgrades
Updated packages
This table summarizes package version changes I find interesting.
Package | Buster | Bullseye | Notes |
---|---|---|---|
APT | 1.8 | 2.2 | 2.0, 2.2 |
Browserpass | 2.0 | 3.7 | Major usability improvements |
Docker | 18 | 20 | Docker made it for a second release |
Emacs | 26 | 27 | JSON parsing for LSP? ~/.config/emacs/? harfbuzz?? oh my! details |
Firefox | 68 | 78 | 78 was already in buster-updates |
Ganeti | 2.16.0 | 3.0.1 | breaking upgrade? |
GNOME | 3.30 | 3.38 | Missed the "GNOME 40" release |
Inkscape | 0.92 | 1.0 | Finally, 1.0! |
Libreoffice | 6.2 | 7.0 | |
OpenSSH | 7.9 | 8.4 | FIDO/U2F, Include, signatures, quantum-resistant key exchange, key fingerprint as confirmation |
Postgresql | 11 | 13 | |
Python | 3.7 | 3.9 | walrus operator, importlib.metadata, dict unions, zoneinfo |
Puppet | 5.5 | 5.5 | Missed the Puppet 6 (and 7!) releases |
Note that this table may not be up to date with the current bullseye release. See the official release notes for a more up to date list.
Removed packages
- apt-venv was removed because of an invalid email address, seems silly but I guess it makes sense
- debirf also had critical bugs, although there's still hope for that guy
- elpy is also failing its test suite but hopefully should make it back when that's fixed (although switching to LSP is also an option here)
- gocode was removed along with elpa-company-go, need to switch to gopls
- gtk-recordmydesktop - Python 2, dead upstream, see bug 943983, peek (in Debian) is a great, no-frills replacement
- Python 2 support is removed! hopefully most of my stuff is already Python 3, but I did lose monkeysign and gameclock, as mentioned above
- Mailman 2 is consequently removed
- syncmaildir has a FTBFS and has been removed from testing, seems like it is in bad shape
- qalculate-gtk, my dearest calculator, was dropped from testing too! a team picked up the package, but too late it seems
- rainloop, my webmail, was removed because of a dependency problem, likely to get fixed in backports
- usbguard-applet-qt - removed 0.7.5 from usbguard,
workaround: find the device ID in
lsbusb
and runusbguard allow-device id $ID
upstream, with the idea that it was a proof of concept and would be maintained outside of the main tree, but no clear candidate has emerged just yet, see this upstream issue, this fork, usbguard-gnome, usbguard-notifier and also usbauth-all, none packaged in Debian
See also the noteworthy obsolete packages list.
Security updates URL changes
So you might have noticed this little line in the upgrade procedure:
sed -i 's#buster/updates#bullseye-security#' /etc/apt/sources.list $(ls /etc/apt/sources.list.d/*) &&
This is a known issue in this release, it's because the security
sources.list
is now:
deb https://deb.debian.org/debian-security bullseye-security main contrib
In buster
, it was:
deb http://security.debian.org/ buster/updates main contrib non-free
... although this presumably worked already as well:
deb https://deb.debian.org/debian-security buster/updates main contrib
Also note that the codename of the security changed, this time, from
buster
to bullseye-security
. This affects you only if you have an
APT configuration which involves pinning the APT::Default-Release
manually.
At least that's what the release notes say. In reality, in my case, I had the codename set in the unattended-upgrades configuration file, which required a change (in Puppet).
I can't find any other recent changes in my notes, but I could have sworn it's not the first time a change like this happens. If someone remember what it was before that, I would be grateful if I could update that list!
Issues
See also the official list of known issues.
Pending
Critical packages missing
In the "removed packages" list above, i have decided to keep the following, even if they don't make it to bullseye:
- elpy - keeping until i switch to LSP? hopefully it will make it too
- syncmaildir - my email sync! maybe i can try another
- qalculate-gtk - it will get back on its feet, i'm sure
- nomacs - a great image viewer, has some packaging issues, most notably it's out of date with upstream and vendors libexiv2
I also particularly need to pay attention to usbguard, as it's quite possible I won't be able to do anything after reboot. :p
Some other removed packages I have just accepted the removal, with the following alternatives:
Package | Alternative | Rationale |
---|---|---|
gocode |
gopls |
LSP is the (ad-hoc) standard |
gtk-recordmydesktop |
obs , peek |
peek is a nice, simple alternative, OBS Studio can also be used for live streaming |
nomacs |
geeqie , many others |
i mostly use geeqie all the time, and only recently found nomacs, might be interesting if it gets packaged properly |
usbguard-applet-qt |
usbguard allow-device |
GUI just gone, but commandline might work |
For syncmaildir, the plan is to drop it. See this blog post. For elpy, I'm likely to use LSP as well, since it seems it won't make it after all. For qalculate, I'm betting on backports.
Puppet breaks in bullseye/sid
testing has this ... peculiar notion of itself. instead of announcing itself like a normal Debian stable release, for example:
anarcat@angela:~(main)$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 10 (buster)
Release: 10
Codename: buster
It is kind of unsure about its identity:
vagrant@testing:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux bullseye/sid
Release: testing/unstable
Codename: n/a
When you know how Debian works (that testing
is really just an old,
partial copy of unstable
), that makes sense. But when you create
Puppet manifests, you expect stuff like:
if $facts['os']['release']['major'] < 11 {
# stuff before bullseye
} else {
# stuff after bullseye
}
To just work. But they don't. In bullseye/sid/testing/unstable,
however you want to call it, os.release.major
is actually
"bullseye/sid". Not "bullseye", not "sid", and, of course, not
"11". "bullseye/sid". So obviously that just totally breaks when
comparing to "11".
I tried patching /etc/os-release
:
cat >> /etc/os-release <<EOF
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
EOF
But that doesn't seem to work: it looks like facter -p
, at least,
takes the major/minor information from... /etc/debian_version
! So
you actually need to do this to fix your manifests:
echo 11.0 > /etc/debian_version
But that's really... quite a hack. To workaround this from the Puppet side, I ended up doing this ugly kludge:
# remove packages gone from bullseye
#
# we should really use < 11 here, but os.release.major is
# actually "bullseye/sid" now? ouch?
#
# remove this when we stop supporting buster
$bullseye_removed = $facts['os']['distro']['codename'] ? {
'bullseye/sid' => absent,
'bullseye' => absent,
default => present,
}
package { 'gtk-recordmydesktop':
ensure => $bullseye_removed,
}
It's unclear to me here where the fault lies. On the one hand, it
seems that Puppet shouldn't change the type of one of its core facts,
but on the other, /etc/debian_version
is bullseye/sid
, a string
and not a version, in testing/unstable in Debian... Garbage-in,
garbage-out? Why don't we set a real version number there in Debian in
the first place?
Resolved
Cool things I want to try
- sway
- figure out what else is new in bullseye?
Update: I postponed those. I feel sway (and Wayland in general) is not ready for prime time just yet. For example it requires pipewire for screensharing, Emacs is not yet ported yet, etc. Kind of a mess.
Debian Planet has the #newinbullseye
stuff (mikas blog
mostly), I added what I found here already. There's also this wiki
page and, of course, the release notes.
Browserpass fails to upgrade
Upgrade crashed on this:
dpkg: error processing archive /var/cache/apt/archives/webext-browserpass_3.7.2-1+b1_amd64.deb (--unpack):
unable to open '/usr/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}/browserpass@maximbaz.com/icon.png.dpkg-new': No such file or directory
Reinstalling /etc/chromium/native-messaging-hosts/com.dannyvankooten.browserpass.json that was moved away
Errors were encountered while processing:
/var/cache/apt/archives/webext-browserpass_3.7.2-1+b1_amd64.deb
This is bug #982758. Workaround:
apt purge webext-browserpass
If the upgrade crashed, purge the package with the same Dpkg options:
apt -o Dpkg::Options::='--force-confdef' -o Dpkg::Options::='--force-confold' purge webext-browserpass
Once the upgrade is completed, just reinstall:
apt install webext-browserpass
The extension is quite finicky: i had to disable and re-enable it to get the button to show up on the browser interface.
Double redshift
I had two Redshift items in the notification area (and presumably processes too) running after a reboot and re-login. Not sure what's going on, it made the monitor "flicker slowly" as it flipped between the two configurations somehow.
It seems like the Debian package now ships a systemd unit file in
/usr/lib/systemd/user/redshift-gtk.service
, which takes care of the
startup, so I disabled the hack in my .xsession
file, nice.
Emacs took 2 minutes to start
That was because I still had company-go
in my .emacs
configuration, which meant it was trying to fetch it from MELPA, which
took forever. I removed it and, anyways, it wouldn't have done it a
second time so that's fixed.
i3-focus and rsendmail delivery failed
I have this custom i3-focus script to improve on the "alt-tab" behavior, which depends on a python library not in Debian. I have this virtualenv to deploy it, but somehow it failed after the upgrade. Doing this fixed it:
mv .virtualenvs/i3_py .virtualenvs/i3_py.bak &&
python3 -m venv --system-site-packages ~/.virtualenvs/i3_py &&
.virtualenvs/i3_py/bin/pip3 install i3_py &&
rm -rf .virtualenvs/i3_py.bak
This is presumably because Python libraries get installed in a version-specific directory...
Note that this also crashed rsendmail which I really need to get around packaging (which would fix this issue). It also meant it totally lost the mails, because postfix panicked and drop the mails when it couldn't generate a bounce either.
Not enough disk space
I have too much stuff on my computers. I was already a bit short on my
/
partition before the upgrade:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/curie--vg-root 28G 25G 2.8G 90% /
The upgrade downloaded ~7GB of Debian packages, and required an extra 4.5GB of disk space! Clearly that wouldn't do here, so I had to expand the root partition, which ended up like this after the upgrade:
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/curie--vg-root 38G 25G 13G 67% /
I'm surprised that Debian bullseye now would use an extra 4GB of disk space! The disk requirements don't seem to have changed in decades, yet I keep having to pile up more disk space only to store software... We'll see what the end result will be.
Packages I have removed:
php*
- maybe some leftover of a dev environment?
After the complete upgrade procedure (but before removing the extra kernel):
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/curie--vg-root 38G 28G 9.1G 76% /
So the upgrade did use about 3-4GB of disk space, which is quite significant!
Maybe there's a way to figure out which package ate all that much?
Packages mistakenly removed
Those packages were removed during the upgrade, yet I still want to use them:
- inkscape
- gnuradio
Workaround: apt install $PACKAGE
The package libu2f-host0
was also removed and, typically, I needed it
to make U2F authentication work (2FA) in Firefox and Chrome, but it
seems it's not necessary in bullseye anymore at least, so I've just
removed it altogether.
LUKS password prompt in plain text instead of GUI
It seems like Plymouth just disappeared? At least on curie. Could not reproduce on angela, suspecting this was never correctly setup on curie.
Troubleshooting
Upgrade failures
Instructions on errors during upgrades can be found in the release notes troubleshooting section.
Reboot failures
If there's any trouble during reboots, you should use some recovery system. The release notes actually have good documentation on that, on top of "use a live filesystem".
Finding orphaned and weird packages
The apt-forktracer call above used to have many other different incantations, and it's not yet clear that it does everything we need. What we want to find are basically packages that are not "canonical Debian packages", which are shipped by the stable Debian distribution. Those are typically called "obsolete" packages in Debian, but that term is somewhat to narrow, as I also want to consider packages that were never part of Debian at all.
Weirdly, the release notes suggest three different methods to do this, in different part of the documentation. (Filed this as a bug in 987017.)
This section tries to figure out the right way forward. See also step 4.2.2, 4.8 and this forum.
aptitude search 1
This is the first way I found:
aptitude search '?narrow(?not(?archive("^[^n][^o][^w].*$")),?version(CURRENT))'
This incantation comes from the
cross-upgrade
documentation. It selects packages that are currently installed
(?narrow(...,?version(CURRENT))
) from an archive other than "now"
(?not(?archive("^[^n][^o][^w].*$")
). This was cargo-culted from
Ewan's cross-upgrading documentation.
Nowadays, the release notes actually suggest a similar pattern:
aptitude search '?narrow(?installed, ?not(?origin(Debian)))'
apt-show-versions
I also found this somewhat works to find weird packages:
apt-show-versions | grep -v /bullseye
This uses the more flexible apt-show-version to list
everything that is not in the bullseye
repository. But the regex
could hide third-party repositories that happen to reuse that
codename. It can also yield strange results like:
linux-libc-dev:i386 not installed
Those are presumably harmless, so this might be a better call:
apt-show-versions | grep -v /bullseye | grep -v 'not installed$'
... to filter out those packages.
aptitude 2: ~obsolete
Then the release notes also suggest this:
aptitude search '?obsolete'
This command has been recommended to find obsolete packages since buster.
apt-forktracer
This one is fairly new to the game, at least as far as I am concerned:
apt-forktracer | sort
This will not find packages that are from a newer version (for example from "testing" in "stable").
It's also recommended by the release notes. I've settled on it because its output is so much simpler, but I still need to compare the various results.
apt list
Starting from bullseye, ironically, we have another way of doing this, since APT adopted the aptitude patterns:
apt list '?obsolete'
It works well, and the output is digestible, but it will not catch versions on the local machine newer than in the archive, which might be a problem in some cases.
References
- Official guide
- Release notes
- Koumbit guide (WIP, reviewed 2021-08-26)
- DSA guide (WIP, reviewed 2021-08-26)
- TPA guide (WIP, last sync 2021-08-26)
- Solution proposal to automate this