Introduction
The (original) Linux i386 architecture is pretty close to being removed, especially from Debian Linux (but also from the Linux kernel). The last few years have brought several announcements of "this is the last release with i386", only for there to be one more "last release" with i386 as a supported architecture. And various third party software has dropped support for i386, or is in the process of doing so.
Most relevant to me, SaltStack announced a switch to "onedir" packaging about a year ago, from Salt 3005 and especially Salt 3006. The "onedir" packaging means that Salt becomes a binary distribution, bundling its own Python interpreter -- which is obviously architecture specific. This means that my work around of using the "amd64" Salt packages (for older Salt releases) with an i386 Python (and some helper back ported Python modules) will no longer work. So that prompted me to finally convert the last few i386 VMs that were managed by Salt across to amd64 VMs.
The i386 cross grade approach I followed was fairly similar to my
earlier test Debian i386 to amd64
crossgrade, but
required some tweaks to get it working for Debian Bullseye. Especially,
as the Debian CrossGrading
Wiki page points out, Debian Bullseye requires perl-base
cross
graded even earlier in the process, before the rest of the perl
packages. And there are some twisty perl / Debian packaging tool
dependencies to resolve early on.
This post documents the approach I used on three Debian Bullseye i386 systems to cross grade them to Debian Bullseye amd64. (At the time of this writing Debian Bookworm is the stable Debian Linux; but I decided to do the cross grade on these system before upgrading them to Debian Bookworm, as the Debian Bullseye cross grade challenges were better documented.)
If you are considering attempting this cross grade approach yourself:
know that you will end up with a broken system in the middle of the cross grade, and it will take care and experience to move forward into a working system again. Key packages you rely on might be auto-removed, or require data or configuration to be recreated to continue working.
make backups before you start. More than one. Be very sure you can restore from backups. If you are cross grading a VM, consider if you can minimise other writes to disk during the cross grade (eg, firewall the VM off from incoming network connections) and snapshot the VM disk image before you start, so you have an undo option of rolling back to the snapshot and pretending you did not try the risky crossgrade. But either way make sure you have a backup handy you can look at to see "how it was before" to guide you in putting the system back together.
especially if it is a VM, consider making a clone of the system in a virtual machine, and doing a few dry runs of the upgrade process in a VM you are happy to throw away. That should let you encounter most (but maybe not all) of the problems in a safer environment where you can roll back and try again.
at least twice during the cross grade you will have to tell the Debian packaging tools that you know what you are asking is a terrible idea, but you want to do it anyway (
Yes, do as I say!
literally entered). Neither Debian nor I take any responsibility for your broken system as a result of attempting to cross grade it from i386 to amd64 following this or any other guide. You need to assure yourself that you have the experience to carry out this complicated risky procedure through to a safe conclusion.be aware that some packages (especially databases) have architecture dependent file formats on disk, which will break horribly if you change architecture. Make sure you have a plan to recover a working system from that cross grade (eg, in the case of databases make sure you know how to dump and reload the database before/after the crossgrade).
My first few trial attempts (in a VM clone) of the cross grade with Debian Bullseye took 1-2 hours to figure out all the required steps. By the time I had reduced each VM clone upgrade to a runsheet of steps specific to that VM install, the production crossgrade took about 30 minutes. But it took at least half a dozen attempts to get a "do these things, in this order" run sheet, that I was happy to attempt in production. Per VM.
If you have some other way to reinstall the system (especially automatically) on a new VM that is 64-bit from the start, that would be a safer option. This risky crossgrade procedure is probably only relevant to long standing pets which are difficult to replace. (All of mine were originally installed 15+ years ago, and have been through many Debian hand upgrades of Debian Linux releases since the install; two of them had been through a physical to virtual conversion too.)
Crossgrade preparation
Make sure your system is capable of running 64-bit code (especially if
it is a VM, make sure the VM "hardware" is ready for 64-bit code). The
lm
flag ("Long Mode") needs to be visible in the CPU flags, eg:
ewen@debian:~$ grep ' lm ' /proc/cpuinfo
flags : fpu de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pse36 clflush mmx fxsr sse sse2 syscall nx lm rep_good nopl xtopology cpuid tsc_known_freq pni cx16 x2apic hypervisor lahf_lm cpuid_fault pti
ewen@debian:~$
Or check with:
lscpu | grep 64-bit
if you have lscpu
installed.
Make sure you have access to the system console (eg, via a serial console
or a virtual machine console, or a remote KVM switch -- or maybe by
being local to the system). At one point in the upgrade you need to
select a specific kernel version, from the grub
boot menu, which requires
console access.
Finish any package installs, and upgrades on the Debian Linux i386 system,
and make sure any earlier upgrades have been tidied up. Eg, dpkg --audit
should be clean and dpkg -l | grep -v 'ii'
shouldn't show anything left.
Any obsolete packages that you cannot reinstall again should be removed.
Make sure the system boots cleanly on the Debian Linux i386 install.
Make a backup. That you are confident you can restore from and get a working system again.
Record the package status of the i386 system, for cross reference later on (eg, confirming the same packages got reinstalled, and the same package are marked as "automatic dependencies"):
apt-mark showauto >i386-auto-packages
dpkg --get-selections >i386-package-selections
Switch to dual architectures, and switch to a 64-bit Linux Kernel
Enable the amd64
architecture as a foreign architecture:
dpkg --print-architecture
sudo dpkg --add-architecture amd64
dpkg --print-foreign-architectures
sudo apt-get update
The base architecture at this point should be i386
, but you should
be able to install amd64
architecture packages by explicitly specifying
them at this point.
Then install the 64-bit amd64 kernel, and boot into that:
sudo apt-get install linux-image-amd64:amd64
sudo update-grub
sudo shutdown -r now
For this reboot (and only this reboot) you will have to interrupt the
grub
automatic boot, and pick a different kernel from the menu.
Specifically you need to go into the Advanced options for Debian GNU/Linux
menu option (second menu) and pick the amd64
kernel entry which
is named something like Debian GNU/Linux, with Linux 5.10.0-26-amd64
and will be the third entry in that submenu (because the existing i386
kernel sorts before the amd64 kernel in the generated list).
Make sure the system booted into a 64-bit kernel:
uname -m
should return x86_64
if you are running a 64-bit kernel. If not,
try rebooting again and choosing the correct kernel in the grub
boot menu.
Once you have the 64-bit kernel booting, remove the equivalent i386 (32-bit) kernel, and reboot again to make sure the 64-bit kernel is booted automatically from now on:
sudo apt-get purge linux-image-686-pae linux-image-5.10.0-26-686-pae
sudo update-grub
sudo shutdown -r now
If you wish you can pause at this point indefinitely -- the Linux i386
user land should run on the Linux amd64 kernel without any substantial
problems, as this was used for a long period in the early x86_64
kernel development.
Change the primary architecture to amd64
This is one of the more complicated steps. At this point we are changing
dpkg
/ apt
to the amd64
, which changes the primary architecture from
i386
to amd64
.
On Debian Bullseye, perl-base:i386
conflicts (indirectly, I think)
with perl-base:amd64
. So we have to force installing perl-base:amd64
at this point. The conflict is sufficiently bad that we cannot
even use apt
to download packages once dpkg
/ apt
have been
changed to amd64
. So we need to pre-download several amd64
packages first, then install them "all at once". And then let apt
fix up the conflicts any way it can, after we have installed a few
more perl
packages. (We cannot install those additional packages
at the same time as perl-base:amd64
as the conflicts are too complicated
to resolve, so apt
gives up.)
This combination of steps worked for me on my Debian Bullseye systems
(although apt-get -f install
removed some packages important to me
on each system, which had to be put back later on):
sudo -s
apt-get clean
apt-get --download-only install dpkg:amd64 tar:amd64 apt:amd64 apt-utils:amd64
(cd /var/cache/apt/archives/ && apt download perl-base:amd64)
dpkg --install /var/cache/apt/archives/*_amd64.deb
dpkg --install /var/cache/apt/archives/*_amd64.deb
dpkg --print-architecture # Should show: amd64
dpkg --print-foreign-architectures # Should show: i386
Note the two runs of dpkg --install ...
for the same packages; this
is required because some packages will not install on the first run
due to missing amd64
dependencies; but they can install the second
time around. (There might be a topological sort of those dependencies
to install them in "the right order". But for these critical packages,
there are lots of circular dependencies, so simply running the install
of these key packages twice is the most pragmatic approach.)
Once perl-base:amd64
is installed, a bunch of other Perl dependencies
used for Debian package management will be broken, so some additional
perl packages need to be upgraded at this step, including
libtext-csv-xs-perl
and libencode-perl
:
(cd /var/cache/apt/archives/ && apt download libperl5.32:amd64 libgdbm-compat4:amd64 libgdbm6:amd64)
(cd /var/cache/apt/archives/ && apt download perl:amd64)
(cd /var/cache/apt/archives/ && apt download libencode-perl:amd64)
(cd /var/cache/apt/archives/ && apt download libtext-csv-xs-perl:amd64)
(cd /var/cache/apt/archives/ && apt download libdebconfclient0:amd64)
dpkg --install /var/cache/apt/archives/*_amd64.deb
At this point it should be possible to get apt
back to a point where
it is "happy" automatically, but do keep track of which packages it is
removing as some of them will be important to you and need to be
reinstalled later on. Those packages need to be removed at this point
to break dependency loops:
apt-get -f install
dpkg --configure -a
Switch the shell to amd64
Install the amd64
bash and dash, and run them instead of the
32-bit versions. This will pull in several other key dependencies,
and also force-remove the i386
versions, so you will have to agree
that you know this can break your system and you want to do it
anyway (Yes, do as I say!
):
apt-get install dash bash
exec /bin/bash
Install the remaining amd64
replacements for installed i386
packages
Download the packages which are needed to install amd64
replacements:
apt-get --download-only -y --no-install-recommends install \
`dpkg -l | grep '^.i' | awk '{print $2}' | grep :i386 | uniq |
grep -v 'linux-image.*686-pae' |
sed -e 's/\(.*\):i386/\1:i386- \1:amd64/'`
Then install as many of the amd64
libraries as possible (since these
can mostly be installed in parallel with the i386
packages, and fix
dependency issues):
dpkg --install /var/cache/apt/archives/lib*.deb /var/cache/apt/archives/perl*.deb
apt-get -f install
dpkg --configure -a
(we also install the outstanding perl packages at this point for certainty).
Then we can install the majority of the remaining amd64
packages:
dpkg --get-selections | grep :amd64 | cut -f 1 -d : | tee /tmp/64-bit
dpkg --get-selections | grep :i386 | grep -vf /tmp/64-bit | cut -f 1 -d : |
xargs -I {} sh -c 'ls /var/cache/apt/archives/{}*_amd64.deb' | uniq |
tee /tmp/packages-to-install
dpkg --install `cat /tmp/packages-to-install`
which might take a second pass to be able to install all the packages due to dependency issues:
dpkg --get-selections | grep :amd64 | cut -f 1 -d : | tee /tmp/64-bit
dpkg --get-selections | grep :i386 | grep -vf /tmp/64-bit | cut -f 1 -d : |
grep -v 'linux-image.*686-pae' |
xargs -I {} sh -c 'ls /var/cache/apt/archives/{}*_amd64.deb' | uniq |
tee /tmp/packages-to-install
test -s /tmp/packages-to-install && dpkg --install `cat /tmp/packages-to-install`
Tidy up the amd64
system
Check what else is left to be converted from i386
to amd64
. Some
packages will still have i386
versions installed, but will also have
an amd64
version -- packages like gcc-9-base
and gcc-10-base
are
effectively library packages and permit parallel installs of both i386
and amd64
versions.
dpkg --get-selections | grep :i386 | grep -v lib | grep -v deinstall | wc -l
dpkg --get-selections | grep :i386 | grep -v lib | grep -v deinstall
dpkg --get-selections | grep :i386 | grep -v lib | awk '$2 ~ /^install$/ { print $1; }' | grep -v 'linux-image.*686-pae' | sed 's/:i386/:amd64/;' | grep -vf /tmp/64-bit
There may still be conflicts at this point, in which case you will need
to figure out some way to resolve them for your combination of packages;
it might involve removing a package important to you, cross grading
other packages, and then reinstalling the packages you wanted on the system
once the dependencies have been resolved properly. Inevitably if apt
cannot figure out a solution, it will be a complicated problem, so assess
carefully what you can live without temporarily to be able to make forward
progress.
Once that is done, run a normal upgrade of the amd64
system to make
sure apt
is happy, and reboot the system to make sure all the running
programs are the amd64
versions:
apt-get update
apt-get upgrade
apt-get dist-upgrade
sudo update-grub
sudo shutdown -r now
Assuming the system came back up as a 64-bit system:
uname -m # Should show: x86_64
getconf LONG_BIT # Should show: 64
then clean up most of the i386
libraries next:
sudo apt-get update
sudo apt-get dist-upgrade
sudo apt-get --purge autoremove
Then I found if gnuplot
was installed, I had to temporarily remove it
to make progress on the remaining cleanup (and install it again later):
HAVE_GNUPLOT=$(dpkg -l gnuplot >/dev/null 2>&1 && echo "true")
if [ -n "${HAVE_GNUPLOT}" ]; then sudo apt-get remove gnuplot; fi
before I could remove the essential i386
libraries, which hopefully
by this point your system does not need (just the amd64
versions of
those libraries). But apt
/ dpkg
does not know this so you will
have to confirm you really want to remove these essential libraries
(Yes, do as I say!
):
dpkg --get-selections | grep :i386 | grep -v deinstall | wc -l
sudo apt-get purge $(dpkg --get-selections | grep :i386 | grep -v deinstall | awk '{print $1;}')
Then you should be able to reinstall any packages that were removed to break dependency loops:
dpkg --get-selections | awk '/:i386.*deinstall/ { print $1; }' | sed 's/:i386/:amd64/'
sudo apt-get install --no-install-recommends $(dpkg --get-selections | awk '/:i386.*deinstall/ { print $1; }' | sed 's/:i386/:amd64/')
sudo apt-get -f install
sudo dpkg --configure -a
dpkg --get-selections | grep deinstall
sudo apt-get install $(dpkg --get-selections | awk '/deinstall/ { print $1; }')
Including reinstalling gnuplot
again if you had to remove it above:
if [ -n "${HAVE_GNUPLOT}" ]; then sudo apt-get install gnuplot; fi
Then confirm there is nothing else that needs to be reinstalled:
dpkg --get-selections | grep deinstall
dpkg --get-selections | awk '/:i386.*deinstall/ { print $1; }' | sed 's/:i386/:amd64/'
and no i386
packages still installed:
dpkg --get-selections | grep i386
dpkg -l | grep "^i.*:386"
Cleaning up from the crossgrade
Do a regular package update to make sure there are no complaints, and then reboot to make sure you have a working system:
sudo apt-get update
sudo apt-get dist-upgrade
sudo dpkg --configure -a
sudo update-grub
sudo shutdown -r now
Assuming the system booted okay, purge the i386
packages that were
removed, and remove the i386
architecture:
sudo apt-get --purge autoremove
sudo dpkg --remove-architecture i386
dpkg --print-architecture # Should show: amd64
dpkg --print-foreign-architectures # Should return nothing
Then make sure that dpkg
/ apt
are happy:
dpkg --audit
dpkg -l | grep -v "^ii"
and if the package state is tidy reboot again as a plain amd64
system:
sudo update-grub
sudo shutdown -r now
Ensure your production system is production ready again
Check for any other packages that might have been removed as dependencies
and need to be installed, by comparing the i386
package list to the
amd64
package list:
dpkg --get-selections >/tmp/amd64-package-selections
diff -bw <(sed 's/:i386/:amd64/;' i386-package-selections | sort) <(sort </tmp/amd64-package-selections) | grep "<" | grep -v "686-pae" | awk '{print $2;}' | grep -v "^lib" | grep -v pkgmonkey-client | tee /tmp/missing-packages
sudo apt-get install $(cat /tmp/missing-packages)
dpkg --get-selections >/tmp/amd64-package-selections
diff -wb /tmp/amd64-package-selections <(sed 's/:i386/:amd64/;' i386-package-selections) | grep -v "linux-image" | grep "^>"
sudo apt-get install $(diff -wb /tmp/amd64-package-selections <(sed 's/:i386/:amd64/;' i386-package-selections) | grep -v "linux-image" | grep -v "pkgmonkey-client" | awk '/^>/ {print $2;}')
dpkg --get-selections >/tmp/amd64-package-selections
diff -wb /tmp/amd64-package-selections <(sed 's/:i386/:amd64/;' i386-package-selections) | grep -v "linux-image" | grep -v "pkgmonkey-client" | grep "^>"
Then check for any extra packages that got dragged in as dependencies during the upgrade which you did not have installed before and do not want, and consider if you want to remove them:
dpkg --get-selections >/tmp/amd64-package-selections
diff -wb /tmp/amd64-package-selections <(sed 's/:i386/:amd64/;' i386-package-selections) | grep -v "linux-image" | grep "^<" | grep -v binutils | grep -v 'lib.san' | grep -v 'libunwind8'
Beware that some of these additional packages will be new amd64
dependencies. Eg, strace
on amd64
requires libunwind8
, and
gcc
on amd64
indirectly requires liblsan0
and libtsan0
. It
will take some systems administration experience, and some investigation,
to determine what is still needed for production and what was temporarily
installed to meet dependencies during the cross grade.
Once you are happy that the production packages are installed, and no unnecessary packages are installed, restore the "automatically installed" marks so that future upgrades will work better:
sed 's/:i386/:amd64/' i386-auto-packages | grep -v 686-pae | xargs sudo apt-mark auto
(which uses the list of i386
automatically installed packages, created at the beginning).
Then remove any packages which are now no longer required:
sudo apt-get -f install
sudo apt-get --purge autoremove
and confirm you do not have any 386
or 686
packages left:
dpkg -l | grep '[36]86'
Architecture upgrades for specific tools
Some packages have their own architecture dependent files on disk. Particularly databases, but also other programs. You will need to figure out, before committing to the production upgrade, how to handle these situations.
On my mail servers, I found that (a) postfix
got removed during the
crossgrade (replaced by exim
) and had to be reinstalled, and (b) the
spamassassin
tool had some C libraries that it compiles to do regular
expressions faster than in perl
, which have to to be rebuilt, with
sa-compile
.
In the case of spamassassin
I did this with:
test -x /usr/bin/sa-compile && (
sudo sa-compile --list >/tmp/before
sudo sa-compile
sudo sa-compile --list >/tmp/after
diff /tmp/before /tmp/after
sudo service spamassassin restart
sudo service spamass-milter restart
sudo service postfix restart
)
Then once you have a final configuration, reboot the system one more time to make sure you are running your final package configuration:
sudo update-grub
sudo shutdown -r now
And watch your logs and monitoring very carefully for the next few hours to keep an eye out for other problems that need manual fixes.
From this point on, if you successfully got to a working system and
fixed any data architecture dependencies, then it should act like
any other Debian Linux amd64
install, including for any future
upgrades.