To start, read the official release notes.
If your install fits into "vanilla Debian plus maybe a handful of 3rd-party repos", then this guide for a simple upgrade to Debian 12 "bookworm" from Debian 11 "bullseye" can be helpful. 3rd-party repos are handled with a find command.
Note upgrade is only supported from Debian 11 to Debian 12. If you are on Debian 10, upgrade to Debian 11 first and make sure to change the security repo as per the release notes. Then once on Debian 11, you can upgrade to Debian 12.
- Check free disk space
df -h
5 GiB free is a conservative amount. sudo apt clean
and sudo apt autoremove
can be used to free some disk space.
On a server with only docker installed, even 1 GiB free was sufficient. Do err on the side of caution here, however.
- Identify any 3rd-party repos that may need to be updated. They'll be changed with a
find
command, below.
ls /etc/apt/sources.list.d
- Update current distribution
sudo apt-get update && sudo apt-get dist-upgrade --autoremove -y
If this brought in a new kernel, sudo reboot
- otherwise continue
- Change repo to bookworm, from bullseye.
sudo sed -i 's/bullseye/bookworm/g' /etc/apt/sources.list
- Add
non-free-firmware
ifnon-free
is currently in use
sudo sed -i '/non-free/ s/$/ non-free-firmware/' /etc/apt/sources.list
- Change all 3rd-party repos
sudo find /etc/apt/sources.list.d -type f -exec sed -i 's/bullseye/bookworm/g' {} \;
- Update Debian
For the following, say Yes to restarting services, and keep existing config files when prompted. If using msmtp, acknowledge warnings. AppArmor for msmtp worked for me.
sudo apt-get update && sudo apt-get dist-upgrade --autoremove -y
And finally, reboot
sudo reboot
Config ansible.cfg
:
[defaults]
interpreter_python = /usr/bin/python3
Playbook bookworm.yml
:
---
- name: Upgrade to Debian bookworm
hosts: all
serial: 1
gather_facts: false
roles:
- base/upgrade_bookworm
Role base/upgrade_bookworm/tasks/main.yml
:
---
- name: Get distribution version
setup:
filter: ansible_distribution*
- name: Skip if not Debian 11
meta: end_host
when: ansible_distribution != 'Debian' or ansible_distribution_major_version != '11'
- name: apt clean
apt:
clean: yes
become: yes
- name: Get filesystem facts
setup:
filter: ansible_mounts
- name: Fail if free space on / is below 5 GiB
ansible.builtin.assert:
that:
- item.size_available > (5 * 1024 * 1024 * 1024)
fail_msg: "Free disk space on {{ item.mount }} is below 5 GiB"
loop: "{{ ansible_mounts }}"
when: item.mount == "/"
- name: All apt packages up to date
apt:
upgrade: dist
update_cache: yes
become: yes
- name: apt autoremove
apt:
autoremove: yes
become: yes
- name: apt clean
apt:
clean: yes
become: yes
- name: Check if reboot required
ansible.builtin.stat:
path: /run/reboot-required
get_checksum: no
register: reboot_required_file
- name: Reboot if required
ansible.builtin.reboot:
msg: "Reboot initiated by Ansible"
connect_timeout: 5
reboot_timeout: 600
pre_reboot_delay: 0
post_reboot_delay: 60
test_command: whoami
when: reboot_required_file.stat.exists
become: true
- name: Switch OS from bullseye to bookworm
ansible.builtin.replace:
path: /etc/apt/sources.list
regexp: 'bullseye'
replace: 'bookworm'
become: yes
- name: Add non-free-firmware if non-free is in use
ansible.builtin.replace:
path: /etc/apt/sources.list
regexp: '(.*non-free.*)'
replace: '\1 non-free-firmware'
become: yes
- name: Find all 3rd-party repos
ansible.builtin.find:
paths: /etc/apt/sources.list.d
patterns: '*'
recurse: no
register: third_party_repos
- name: Switch 3rd-party repos from bullseye to bookworm
ansible.builtin.replace:
path: "{{ item.path }}"
regexp: 'bullseye'
replace: 'bookworm'
loop: "{{ third_party_repos.files }}"
loop_control:
label: "{{ item.path }}"
become: yes
- name: Use apt to move to bookworm
apt:
upgrade: dist
update_cache: yes
become: yes
- name: Get distribution version
setup:
filter: ansible_distribution*
- name: Fail if not Debian 12
assert:
that:
- ansible_distribution_major_version == '12'
fail_msg: "Upgrade to Debian 12 failed"
- name: apt autoremove
apt:
autoremove: yes
become: yes
- name: apt clean
apt:
clean: yes
become: yes
- name: Re-enable msmtp apparmor profile
ansible.builtin.file:
path: /etc/apparmor.d/disable/usr.bin.msmtp
state: absent
become: yes
- name: Restart apparmor service
ansible.builtin.systemd:
name: apparmor
state: restarted
become: yes
- name: Reboot on bookworm
ansible.builtin.reboot:
msg: "Reboot initiated by Ansible"
connect_timeout: 5
reboot_timeout: 600
pre_reboot_delay: 0
post_reboot_delay: 60
test_command: whoami
become: yes
- name: Pause for 5 minutes for staggered upgrades
pause:
minutes: 5
Thanks for this. A couple of issues I encountered:
stat
of reboot-required,get_md5
should beget_checksum
, I don't see the former in the documentation.